From 9fa8eabe930bddba504086ee2eb039c9816e3ba1 Mon Sep 17 00:00:00 2001 From: Chen Peng Date: Sat, 20 Apr 2024 18:16:38 +0800 Subject: [PATCH] SourceCode: 1. line location base api --- bake | 2 +- .../lib/src/content/source_code.dart | 105 ++++++++++++++++++ packages/you_note_dart/lib/src/note_core.dart | 2 +- .../test/code_analyzer/code_block_test.dart | 28 ++--- .../test/code_analyzer/use_case_basic.dart | 7 +- 5 files changed, 123 insertions(+), 21 deletions(-) create mode 100644 packages/you_note_dart/lib/src/content/source_code.dart diff --git a/bake b/bake index 73bd2879..a3b7c02c 100755 --- a/bake +++ b/bake @@ -140,7 +140,7 @@ get() { _run_all_package install; } build() { _run_all_package build; } upgrade() { _run_all_package upgrade;} clean() { _run_all_package clean; } -tests() { _run_all_package test; } +test() { _run_all_package test; } gen() { _run_all_package gen; } ls(){ for pkg in ${!_pkgs[*]} ; do diff --git a/packages/you_note_dart/lib/src/content/source_code.dart b/packages/you_note_dart/lib/src/content/source_code.dart new file mode 100644 index 00000000..78396789 --- /dev/null +++ b/packages/you_note_dart/lib/src/content/source_code.dart @@ -0,0 +1,105 @@ + +import 'dart:io'; + +import 'package:analyzer/dart/analysis/features.dart'; +import 'package:analyzer/dart/analysis/utilities.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; + +class SourceCode { + final String content; + final CodeBlock? _build; + + SourceCode._(this._build, this.content); + + static SourceCode parseFile(String path) { + return SourceCode.parse(File(path).readAsStringSync()); + } + + static SourceCode parse(String content) { + var parseResult = parseString(content: content, featureSet: FeatureSet.latestLanguageVersion()); + var unit = parseResult.unit; + _CodeVisitor visitor = _CodeVisitor(content); + unit.visitChildren(visitor); + return SourceCode._(visitor.build, content); + } + + List get codesInBuild => _build == null + ? [] + : _build._children.isEmpty + ? [_build] + : _build.children; + + CodeBlock? findCellCode({required int line}) { + int offset = 0; + for (var MapEntry(key: i, value: lineContent) in content.split("\n").asMap().entries) { + if (i + 1 == line) { + break; + } + // '+1' : '\n' + offset += 1 + lineContent.length; + } + + for (var code in codesInBuild) { + if (code.contains(offset)) { + return code; + } + } + return null; + } + + line(int line) { + var lines = content.split("\n"); + return lines[line - 1]; + } +} + +class CodeBlock { + final String content; + final int offset; + final int end; + final List _children = []; + + CodeBlock({required this.offset, required this.end, required this.content}); + + int get length => end - offset; + + List get children => List.unmodifiable(_children); + + String get blockContent { + return content.substring(offset, end); + } + + bool contains(int anOffset) { + return offset <= anOffset && anOffset <= end; + } + + @override + String toString() { + return "$offset:$end"; + } +} + +class _CodeVisitor extends GeneralizingAstVisitor { + CodeBlock? build; + final String source; + + _CodeVisitor(this.source); + + @override + visitFunctionDeclaration(FunctionDeclaration node) { + if (node.name.lexeme == "build") { + var body = node.functionExpression.body as BlockFunctionBody; + var block = body.block; + build = CodeBlock(content: source, offset: block.leftBracket.end, end: block.rightBracket.offset); + } + return super.visitFunctionDeclaration(node); + } + + @override + visitExpressionStatement(ExpressionStatement node) { + // FIXME go back + var expr = node.expression; + return super.visitExpressionStatement(node); + } +} diff --git a/packages/you_note_dart/lib/src/note_core.dart b/packages/you_note_dart/lib/src/note_core.dart index 21c83993..4d2a26a8 100644 --- a/packages/you_note_dart/lib/src/note_core.dart +++ b/packages/you_note_dart/lib/src/note_core.dart @@ -366,7 +366,7 @@ class Pen { currentCell.print(object); } - /// 注意:只能在NotePage的[build]函数的最外层调用,不能放在button回调或Timer回调中 + /// 注意:只能在NotePage的[_build]函数的最外层调用,不能放在button回调或Timer回调中 /// 通过闭包记住currentCell的引用,以便可以在之后的回调中也可以print内容到currentCell @experimental @Deprecated("已经有更好的方案,这个废弃") diff --git a/packages/you_note_dart/test/code_analyzer/code_block_test.dart b/packages/you_note_dart/test/code_analyzer/code_block_test.dart index 845e6e12..8db4af26 100644 --- a/packages/you_note_dart/test/code_analyzer/code_block_test.dart +++ b/packages/you_note_dart/test/code_analyzer/code_block_test.dart @@ -1,25 +1,19 @@ -import 'dart:io'; -import 'package:analyzer/dart/analysis/features.dart'; -import 'package:analyzer/dart/analysis/utilities.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:checks/checks.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:you_note_dart/src/content/source_code.dart'; void main() { group("code analyzer", () { - test("block", () async {//packages/you_note_dart/lib/src/note_core.dart - File file=File.fromUri(Uri.file("test/code_analyzer/use_case_basic.dart")); - var parseResult = parseString(content: file.readAsStringSync(), featureSet: FeatureSet.latestLanguageVersion()); - var unit = parseResult.unit; - unit.visitChildren(CodeVisitor()); + test("block", () async { + SourceCode code = SourceCode.parseFile("test/code_analyzer/use_case_basic.dart"); + check(code.line(8)).equals(r' print("x:$x");'); + check(code.findCellCode(line: 8)!.blockContent).equals(r""" + + // begin comment 中文字符 + print("x:$x"); + // end comment 中文字符 +"""); }); }); } - -class CodeVisitor extends GeneralizingAstVisitor{ - @override - visitFunctionDeclaration(FunctionDeclaration node) { - return super.visitFunctionDeclaration(node); - } - } diff --git a/packages/you_note_dart/test/code_analyzer/use_case_basic.dart b/packages/you_note_dart/test/code_analyzer/use_case_basic.dart index be9bf91f..6d62c6e0 100644 --- a/packages/you_note_dart/test/code_analyzer/use_case_basic.dart +++ b/packages/you_note_dart/test/code_analyzer/use_case_basic.dart @@ -1,9 +1,12 @@ import 'package:flutter/widgets.dart'; +import 'package:you_note_dart/src/note_core.dart'; var x = "x"; -void build(BuildContext context) { - debugPrint("x:$x"); +void build(BuildContext context, Pen print) { + // begin comment 中文字符 + print("x:$x"); + // end comment 中文字符 } class A {}