Skip to content

feat(text): 添加富文本效果系统和颜色标记功能#251

Merged
GeWuYou merged 8 commits into
mainfrom
feat/rich-text-effects-and-color-markers
Apr 18, 2026
Merged

feat(text): 添加富文本效果系统和颜色标记功能#251
GeWuYou merged 8 commits into
mainfrom
feat/rich-text-effects-and-color-markers

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented Apr 18, 2026

  • 实现 RichTextEffectBase 基类提供统一的标签命名和参数读取逻辑
  • 添加 RichTextBlueEffect、RichTextGoldEffect、RichTextGreenEffect 和 RichTextRedEffect 颜色标记效果
  • 添加 RichTextFadeInEffect、RichTextFlyInEffect、RichTextJitterEffect 和 RichTextSineEffect 动画效果
  • 实现 DefaultRichTextEffectRegistry 默认效果注册表
  • 创建 GfRichTextLabel 富文本标签宿主组件
  • 添加 IRichTextEffectRegistry 效果注册表接口
  • 实现 RichTextEffectEntry、RichTextEffectsController 和 RichTextProfile 配置管理类
  • 添加 RichTextMarkup 语义化标签构建辅助方法
  • 创建 RichTextMarkupTests 和 RichTextProfileTests 单元测试

Summary by CodeRabbit

  • 新功能

    • 引入富文本效果系统:颜色标签(green/red/gold/blue)、动画效果(fade_in/sine/jitter/fly_in)、效果注册与宿主节点(可在编辑器/运行时启用并刷新)。
    • 新增 BBCode 标记生成工具,参数稳定排序并校验标签/键格式。
  • 测试

    • 添加多项单元测试,覆盖标记生成、内置配置、效果创建与控制器行为。
  • 运维

    • CI 测试步骤改进,统一测试输出目录与失败汇总。
  • 其他

    • 测试项目添加全局命名空间简化引用。

- 实现 RichTextEffectBase 基类提供统一的标签命名和参数读取逻辑
- 添加 RichTextBlueEffect、RichTextGoldEffect、RichTextGreenEffect 和 RichTextRedEffect 颜色标记效果
- 添加 RichTextFadeInEffect、RichTextFlyInEffect、RichTextJitterEffect 和 RichTextSineEffect 动画效果
- 实现 DefaultRichTextEffectRegistry 默认效果注册表
- 创建 GfRichTextLabel 富文本标签宿主组件
- 添加 IRichTextEffectRegistry 效果注册表接口
- 实现 RichTextEffectEntry、RichTextEffectsController 和 RichTextProfile 配置管理类
- 添加 RichTextMarkup 语义化标签构建辅助方法
- 创建 RichTextMarkupTests 和 RichTextProfileTests 单元测试
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

新增完整富文本效果子系统:资源与条目类型、效果注册表接口与默认实现、控制器与宿主节点、多种内置静态与动画效果、BBCode 构建工具,以及覆盖这些行为的单元测试与 CI 流程调整。

Changes

Cohort / File(s) Summary
注册表与宿主接口
GFramework.Godot/Text/IRichTextEffectRegistry.cs, GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs, GFramework.Godot/Text/IRichTextEffectHost.cs
新增效果注册表接口与默认实现;按键映射创建具体 RichTextEffect;新增内部宿主接口抽象 BbcodeEnabledCustomEffects
配置与条目
GFramework.Godot/Text/RichTextEffectEntry.cs, GFramework.Godot/Text/RichTextProfile.cs
新增 RichTextEffectEntry(Key/Enabled)与 RichTextProfile,并提供 CreateBuiltInDefault() 返回固定效果键顺序。
控制器与宿主节点
GFramework.Godot/Text/RichTextEffectsController.cs, GFramework.Godot/Text/GfRichTextLabel.cs
新增控制器用于装配/刷新宿主的 CustomEffects 并管理 BbcodeEnabled;新增 GfRichTextLabel 节点,暴露 Profile、EnableFrameworkEffects、AnimatedEffectsEnabled 与刷新方法。
效果基类与工具
GFramework.Godot/Text/Effects/RichTextEffectBase.cs, GFramework.Godot/Text/RichTextMarkup.cs
新增抽象基类封装 TagName、bbcode 暴露及环境参数读取(bool/float/Color)与可见性处理;新增 RichTextMarkup 以验证标记与生成确定性参数顺序的 BBCode 字符串。
静态颜色效果
GFramework.Godot/Text/Effects/RichTextGreenEffect.cs, GFramework.Godot/Text/Effects/RichTextRedEffect.cs, GFramework.Godot/Text/Effects/RichTextGoldEffect.cs, GFramework.Godot/Text/Effects/RichTextBlueEffect.cs
新增四个简单效果类,分别绑定 green/red/gold/blue 标签并将字符颜色设为固定值。
动画效果
GFramework.Godot/Text/Effects/RichTextFadeInEffect.cs, GFramework.Godot/Text/Effects/RichTextSineEffect.cs, GFramework.Godot/Text/Effects/RichTextJitterEffect.cs, GFramework.Godot/Text/Effects/RichTextFlyInEffect.cs
新增四个动画效果(fade_insinejitterfly_in);支持通过构造参数或宿主开关禁用动画逻辑,分别实现淡入、正弦位移、噪声抖动与飞入位移与透明度处理。
测试 - 标记与配置
GFramework.Godot.Tests/Text/RichTextMarkupTests.cs, GFramework.Godot.Tests/Text/RichTextProfileTests.cs
新增单元测试:验证 RichTextMarkup 的标签/参数生成、参数键排序与无效输入校验;验证内置 profile 的效果键顺序。
测试 - 控制器
GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
新增控制器行为测试:启用时确保 BbcodeEnabled 并使用内置 profile(当 profile 为空);禁用时清空 CustomEffects;验证每次刷新使用当前 registryAccessor 实例。
测试基础
GFramework.Godot.Tests/GlobalUsings.cs
在测试项目添加 global using GFramework.Godot.Text;
CI 工作流
.github/workflows/ci.yml
调整 CI:顺序运行各测试项目并为每项目产出稳定 TRX 文件名,汇总并报告失败项目列表,调整 PR 报告条件。

Sequence Diagram(s)

sequenceDiagram
    participant GfRichTextLabel
    participant RichTextEffectsController
    participant DefaultRegistry as DefaultRichTextEffectRegistry
    participant RichTextEffect
    participant Host as RichTextLabel

    GfRichTextLabel->>RichTextEffectsController: EnsureController().Initialize()
    activate RichTextEffectsController
    RichTextEffectsController->>RichTextEffectsController: RefreshEffects()
    RichTextEffectsController->>DefaultRegistry: CreateEffects(profile, animatedEnabled)
    activate DefaultRegistry
    DefaultRegistry->>RichTextEffect: CreateEffect(key) [for each enabled entry]
    loop instantiate effects
        DefaultRegistry-->>RichTextEffectsController: effect instance
    end
    DefaultRegistry-->>RichTextEffectsController: IReadOnlyList<RichTextEffect>
    deactivate DefaultRegistry
    RichTextEffectsController->>Host: CustomEffects = Array(effects)
    deactivate RichTextEffectsController

    Note over Host,RichTextEffect: 渲染时逐字符调用
    Host->>RichTextEffect: _ProcessCustomFX(CharFXTransform)
    RichTextEffect->>RichTextEffect: 读取 env、计算变换
    RichTextEffect-->>Host: 修改字符变换
Loading
sequenceDiagram
    participant Caller
    participant RichTextMarkup
    participant BBCode

    Caller->>RichTextMarkup: Effect("Hello","fade_in", env)
    activate RichTextMarkup
    RichTextMarkup->>RichTextMarkup: 验证 tag/key 令牌
    RichTextMarkup->>RichTextMarkup: 过滤 null 值、按 Ordinal 排序键、格式化值
    RichTextMarkup-->>BBCode: "[fade_in speed=4 tick=0.1]Hello[/fade_in]"
    deactivate RichTextMarkup
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题用中文简洁地描述了主要变更——添加富文本效果系统和颜色标记功能,与PR中新增的多个效果类、注册表、控制器和标记工具的实现相符。
Docstring Coverage ✅ Passed Docstring coverage is 95.83% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rich-text-effects-and-color-markers

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (5)
GFramework.Godot/Text/RichTextMarkup.cs (1)

12-18: 公共 API 文档缺少异常契约说明。

ColorEffect 会因无效 tag 抛出 ArgumentException,建议在 XML 文档中补充 <exception>,明确调用约束。

As per coding guidelines: All public, protected, and internal types and members MUST include XML documentation comments (...) with <exception> where applicable.

Also applies to: 63-70

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Godot/Text/RichTextMarkup.cs` around lines 12 - 18, The public XML
docs for Color (and similarly Effect) are missing an <exception> clause for
invalid tags; update the XML comments for the Color method (and the Effect
method at the indicated lines) to include an <exception
cref="System.ArgumentException"> entry that states the method throws
ArgumentException when the provided tag is null, empty, or otherwise invalid
(i.e., does not constitute a valid BBCode tag), so callers know the contract and
preconditions.
GFramework.Godot/Text/IRichTextEffectRegistry.cs (1)

3-23: 作为核心 Registry 抽象,建议补齐“为何存在/何时使用/生命周期交互”文档。

当前注释说明了“做什么”,但对与 RichTextEffectsController/GfRichTextLabel 的交互时机、animatedEffectsEnabled 的语义边界说明不足。

As per coding guidelines: Core framework components such as ... Registry ... MUST include high-level explanations of responsibilities, lifecycle, interaction with other components, why the abstraction exists, and when to use it instead of alternatives.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Godot/Text/IRichTextEffectRegistry.cs` around lines 3 - 23, Update
the interface XML docs for IRichTextEffectRegistry to include high-level
responsibilities and lifecycle guidance: explain why the registry exists
(central mapping from profile keys to RichTextEffect instances), when it is used
(called by RichTextEffectsController during profile application and by
GfRichTextLabel when setting CustomEffects), expected lifetime/ownership of
returned RichTextEffect instances, and precise semantics/boundary of the
animatedEffectsEnabled parameter (what it enables/disables and when callers
should toggle it). Also note when to prefer using the registry versus creating
effects manually and reference RichTextProfile, CreateEffects, and CreateEffect
in the remarks to make interactions explicit.
GFramework.Godot/Text/Effects/RichTextEffectBase.cs (2)

15-18: bbcode 属性使用小写命名符合 Godot 约定。

这里的小写命名是 Godot RichTextEffect 的要求,建议在 XML 文档中补充说明这一点,以避免后续维护者误认为是命名规范违规。

📝 建议补充文档说明
     /// <summary>
     ///     获取 Godot 识别当前效果所需的 `bbcode` 属性。
+    ///     属性名使用小写以符合 Godot RichTextEffect 的命名约定。
     /// </summary>
     public string bbcode => TagName;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Godot/Text/Effects/RichTextEffectBase.cs` around lines 15 - 18,
The XML doc for the bbcode property should state that the lowercase name is
intentional and required by Godot's RichTextEffect convention; update the
documentation comment on the bbcode property (and/or the RichTextEffectBase
class summary) to explicitly note that Godot expects a lowercase 'bbcode'
identifier for RichTextEffect registration and that this property simply exposes
TagName for that purpose, so future maintainers won't treat the lowercase name
as a naming mistake.

27-52: GetBoolGetFloat 缺少类型校验,与 GetColor 不一致。

GetColor 在转换前检查 value.VariantType == Variant.Type.Color,但 GetBoolGetFloat 直接调用 AsBool() / AsDouble()。如果环境参数中存储了不兼容类型,可能导致意外的隐式转换行为。

建议保持一致的防御性检查,或在 XML 文档中说明当前行为(Godot 的 Variant.AsBool() / Variant.AsDouble() 对非预期类型的处理方式)。

♻️ 可选:为 GetFloat 添加类型校验
 protected float GetFloat(CharFXTransform transform, string key, float defaultValue)
 {
-    if (transform.Env.TryGetValue(Variant.From(key), out var value))
+    if (transform.Env.TryGetValue(Variant.From(key), out var value) &&
+        (value.VariantType == Variant.Type.Float || value.VariantType == Variant.Type.Int))
     {
         return (float)value.AsDouble();
     }

     return defaultValue;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Godot/Text/Effects/RichTextEffectBase.cs` around lines 27 - 52,
GetBool and GetFloat call value.AsBool()/AsDouble() without verifying
value.VariantType, risking implicit/incorrect conversions; update both methods
to mirror GetColor by checking value.VariantType (e.g., Variant.Type.Bool for
GetBool and Variant.Type.Real/Variant.Type.Int as appropriate for GetFloat)
before calling AsBool/AsDouble and return defaultValue when the type mismatches,
using the same Variant.From(key) lookup on CharFXTransform.Env to locate the
value.
GFramework.Godot/Text/Effects/RichTextJitterEffect.cs (1)

45-55: _ProcessCustomFX 中修改 _noise.Seed 可能存在状态污染风险。

每次调用时修改 _noise.Seed 依赖于 Godot 的效果处理是单线程顺序执行的假设。如果该效果实例被多个 RichTextLabel 共享或在未来版本中存在并发调用,可能导致不可预期的抖动行为。

当前实现在单线程场景下是安全的,但建议在 XML 文档中注明线程安全假设,或考虑为每次调用创建局部 FastNoiseLite 实例(会有性能开销)。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Godot/Text/Effects/RichTextJitterEffect.cs` around lines 45 - 55,
The code mutates shared _noise.Seed inside _ProcessCustomFX
(RichTextJitterEffect) which can cause state pollution if the effect or _noise
is shared or called concurrently; fix by not mutating the shared _noise: either
document the single-threaded assumption in the XML/class comments for
RichTextJitterEffect, or create a local FastNoiseLite per call (e.g.,
instantiate a new FastNoiseLite, copy necessary settings from _noise, set its
Seed using (charFx.RelativeIndex + 1) * <prime>, then call GetNoise1D on that
local instance to compute x and y before applying charFx.Offset and calling
ApplyVisibility) to avoid changing _noise.Seed globally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@GFramework.Godot.Tests/Text/RichTextMarkupTests.cs`:
- Around line 26-37: The test Effect_Should_Append_Environment_Parameters relies
on dictionary iteration order; fix by making RichTextMarkup.Effect
deterministic: when building the parameter string from the
IReadOnlyDictionary<string, object?> env, sort the keys (e.g., order by key)
before formatting key=value pairs so output is stable regardless of the
dictionary implementation; update the logic in RichTextMarkup.Effect that
iterates env to enumerate keys in a defined order and then join the pairs,
keeping the test unchanged.

In `@GFramework.Godot/Text/GfRichTextLabel.cs`:
- Around line 37-41: The EffectRegistry setter only updates _effectRegistry
leaving an already-created _controller (cached by EnsureController()) bound to
the old registry; when replacing EffectRegistry you must propagate the new
registry to the existing RichTextEffectsController instance (or recreate it).
Modify the EffectRegistry set accessor to, after assigning _effectRegistry,
check if _controller is non-null and then either set the controller's registry
property (e.g. _controller.EffectRegistry = _effectRegistry) or
dispose/clear/recreate the controller so EnsureController() will use the new
_effectRegistry; apply the same change pattern for the other analogous property
region mentioned (lines ~74-82).
- Around line 34-41: The EffectRegistry property setter can throw
ArgumentNullException when assigned a null value (it uses _effectRegistry ??=
new DefaultRichTextEffectRegistry() and the setter throws with nameof(value)),
so update the XML documentation for the internal property EffectRegistry to
include an <exception cref="System.ArgumentNullException"> entry that explains
the setter will throw if value is null; ensure the text mentions the setter and
the condition (null assignment) and keep the rest of the existing <summary>
intact.
- Around line 9-83: Add unit/integration tests for GfRichTextLabel to cover its
public API behavior: verify that toggling EnableFrameworkEffects enables
BbcodeEnabled and that AnimatedEffectsEnabled controls whether effects are
active (while still installing tags), verify Profile null fallback by asserting
EffectRegistry/default config is used when Profile is null, assert
RefreshFrameworkEffects() calls RefreshEffects on the RichTextEffectsController
(use a test double or mock for RichTextEffectsController via
EnsureController/DI), and verify replacing EffectRegistry updates installed
effects; focus tests on the methods/properties
GfRichTextLabel.RefreshFrameworkEffects, GfRichTextLabel.EnableFrameworkEffects,
GfRichTextLabel.AnimatedEffectsEnabled, GfRichTextLabel.Profile, EffectRegistry
and EnsureController behavior.
- Around line 46-51: In _Ready() the BbcodeEnabled flag is only set to true when
EnableFrameworkEffects is true, leaving it stale when effects are disabled;
change the logic to assign BbcodeEnabled directly from EnableFrameworkEffects
(i.e., BbcodeEnabled = EnableFrameworkEffects) so the two flags remain
symmetric, and ensure any related initialization in RefreshEffects() still
clears CustomEffects but does not rely on previous BbcodeEnabled state.

In `@GFramework.Godot/Text/RichTextEffectsController.cs`:
- Around line 25-39: Add XML documentation to the public constructor
RichTextEffectsController: include a <summary> describing the constructor and
add <param> entries for host, registry, profileAccessor,
frameworkEffectsEnabledAccessor, and animatedEffectsEnabledAccessor, and add
<exception cref="System.ArgumentNullException"> tags for each parameter that can
be null (host, registry, profileAccessor, frameworkEffectsEnabledAccessor,
animatedEffectsEnabledAccessor) indicating they will throw ArgumentNullException
if null; ensure the XML follows existing project style (///) and is placed
immediately above the constructor declaration.

In `@GFramework.Godot/Text/RichTextMarkup.cs`:
- Around line 72-90: The code in RichTextMarkup (the method that builds the
BBCode tag using ArgumentException.ThrowIfNullOrWhiteSpace(tag) and iterating
env pairs) currently writes raw tag and env keys into the BBCode token and can
produce invalid or injectable tokens; add a whitelist validation for the tag and
for each env key (the names used when appending pair.Key before
FormatValue(pair.Value)) to allow only a safe set of characters (e.g., ASCII
letters, digits, underscore and hyphen) and reject/throw for any key containing
whitespace or any of '[', ']', '=' or other characters outside the whitelist;
perform this check early (before building the StringBuilder) and ensure invalid
inputs result in ArgumentException (or skip/continue for env entries per current
behavior) so only validated tokens are emitted.
- Around line 80-91: Sort the env entries before building the attribute string
to ensure deterministic output: in the Effect method, enumerate env by ordering
its Keys (or the pairs by Key) prior to the foreach that appends
pair.Key/pair.Value so different IReadOnlyDictionary implementations produce
consistent BBCode; add XML doc <exception cref="ArgumentException"> tags to the
Effect method (for the ArgumentException.ThrowIfNullOrWhiteSpace(tag) case) and
to the Wrap method to document thrown exceptions; and add validation in Effect
and Wrap to reject/throw when tag or any env key contains BBCode control
characters like '[' ']' '=' (use ArgumentException) to prevent format injection.

---

Nitpick comments:
In `@GFramework.Godot/Text/Effects/RichTextEffectBase.cs`:
- Around line 15-18: The XML doc for the bbcode property should state that the
lowercase name is intentional and required by Godot's RichTextEffect convention;
update the documentation comment on the bbcode property (and/or the
RichTextEffectBase class summary) to explicitly note that Godot expects a
lowercase 'bbcode' identifier for RichTextEffect registration and that this
property simply exposes TagName for that purpose, so future maintainers won't
treat the lowercase name as a naming mistake.
- Around line 27-52: GetBool and GetFloat call value.AsBool()/AsDouble() without
verifying value.VariantType, risking implicit/incorrect conversions; update both
methods to mirror GetColor by checking value.VariantType (e.g.,
Variant.Type.Bool for GetBool and Variant.Type.Real/Variant.Type.Int as
appropriate for GetFloat) before calling AsBool/AsDouble and return defaultValue
when the type mismatches, using the same Variant.From(key) lookup on
CharFXTransform.Env to locate the value.

In `@GFramework.Godot/Text/Effects/RichTextJitterEffect.cs`:
- Around line 45-55: The code mutates shared _noise.Seed inside _ProcessCustomFX
(RichTextJitterEffect) which can cause state pollution if the effect or _noise
is shared or called concurrently; fix by not mutating the shared _noise: either
document the single-threaded assumption in the XML/class comments for
RichTextJitterEffect, or create a local FastNoiseLite per call (e.g.,
instantiate a new FastNoiseLite, copy necessary settings from _noise, set its
Seed using (charFx.RelativeIndex + 1) * <prime>, then call GetNoise1D on that
local instance to compute x and y before applying charFx.Offset and calling
ApplyVisibility) to avoid changing _noise.Seed globally.

In `@GFramework.Godot/Text/IRichTextEffectRegistry.cs`:
- Around line 3-23: Update the interface XML docs for IRichTextEffectRegistry to
include high-level responsibilities and lifecycle guidance: explain why the
registry exists (central mapping from profile keys to RichTextEffect instances),
when it is used (called by RichTextEffectsController during profile application
and by GfRichTextLabel when setting CustomEffects), expected lifetime/ownership
of returned RichTextEffect instances, and precise semantics/boundary of the
animatedEffectsEnabled parameter (what it enables/disables and when callers
should toggle it). Also note when to prefer using the registry versus creating
effects manually and reference RichTextProfile, CreateEffects, and CreateEffect
in the remarks to make interactions explicit.

In `@GFramework.Godot/Text/RichTextMarkup.cs`:
- Around line 12-18: The public XML docs for Color (and similarly Effect) are
missing an <exception> clause for invalid tags; update the XML comments for the
Color method (and the Effect method at the indicated lines) to include an
<exception cref="System.ArgumentException"> entry that states the method throws
ArgumentException when the provided tag is null, empty, or otherwise invalid
(i.e., does not constitute a valid BBCode tag), so callers know the contract and
preconditions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a98eae19-335b-4f67-88ac-71420cb6f858

📥 Commits

Reviewing files that changed from the base of the PR and between 2f4fcca and e5ad293.

📒 Files selected for processing (18)
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot.Tests/Text/RichTextProfileTests.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextBlueEffect.cs
  • GFramework.Godot/Text/Effects/RichTextEffectBase.cs
  • GFramework.Godot/Text/Effects/RichTextFadeInEffect.cs
  • GFramework.Godot/Text/Effects/RichTextFlyInEffect.cs
  • GFramework.Godot/Text/Effects/RichTextGoldEffect.cs
  • GFramework.Godot/Text/Effects/RichTextGreenEffect.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
  • GFramework.Godot/Text/Effects/RichTextRedEffect.cs
  • GFramework.Godot/Text/Effects/RichTextSineEffect.cs
  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot/Text/IRichTextEffectRegistry.cs
  • GFramework.Godot/Text/RichTextEffectEntry.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot/Text/RichTextMarkup.cs
  • GFramework.Godot/Text/RichTextProfile.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Code Quality & Security
  • GitHub Check: Analyze (C#)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable
XML documentation comments must explain intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds, compatibility constraints or edge cases, and registration order or lifecycle sequencing
Avoid obvious comments such as // increment i
Core framework components such as Architecture, Module, System, Context, Registry, Service Module, and Lifecycle types MUST include high-level explanations of responsibilities, lifecycle, interaction with other components, why the abstraction exists, and when to use it instead of alternatives
Generated logic and generator pipelines MUST explain what is generated, why it is generated, the semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling if any
Comments MUST NOT be trivial, redundant, or misleading; prefer explaining why and when, not just what
Prefer slightly more explanation over too little for framework code
Do not rely on implicit imports; declare every required using explicitly
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespac...

Files:

  • GFramework.Godot/Text/RichTextEffectEntry.cs
  • GFramework.Godot.Tests/Text/RichTextProfileTests.cs
  • GFramework.Godot/Text/Effects/RichTextRedEffect.cs
  • GFramework.Godot/Text/RichTextProfile.cs
  • GFramework.Godot/Text/Effects/RichTextGreenEffect.cs
  • GFramework.Godot/Text/Effects/RichTextBlueEffect.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/IRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextGoldEffect.cs
  • GFramework.Godot/Text/Effects/RichTextSineEffect.cs
  • GFramework.Godot/Text/Effects/RichTextFlyInEffect.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
  • GFramework.Godot/Text/RichTextMarkup.cs
  • GFramework.Godot/Text/Effects/RichTextFadeInEffect.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot/Text/Effects/RichTextEffectBase.cs
  • GFramework.Godot/Text/GfRichTextLabel.cs
**/*.{cs,csproj,xml,yaml,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation; do not use tabs

Files:

  • GFramework.Godot/Text/RichTextEffectEntry.cs
  • GFramework.Godot.Tests/Text/RichTextProfileTests.cs
  • GFramework.Godot/Text/Effects/RichTextRedEffect.cs
  • GFramework.Godot/Text/RichTextProfile.cs
  • GFramework.Godot/Text/Effects/RichTextGreenEffect.cs
  • GFramework.Godot/Text/Effects/RichTextBlueEffect.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/IRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextGoldEffect.cs
  • GFramework.Godot/Text/Effects/RichTextSineEffect.cs
  • GFramework.Godot/Text/Effects/RichTextFlyInEffect.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
  • GFramework.Godot/Text/RichTextMarkup.cs
  • GFramework.Godot/Text/Effects/RichTextFadeInEffect.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot/Text/Effects/RichTextEffectBase.cs
  • GFramework.Godot/Text/GfRichTextLabel.cs
🧠 Learnings (2)
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Godot/Text/RichTextEffectEntry.cs
  • GFramework.Godot.Tests/Text/RichTextProfileTests.cs
  • GFramework.Godot/Text/Effects/RichTextRedEffect.cs
  • GFramework.Godot/Text/RichTextProfile.cs
  • GFramework.Godot/Text/Effects/RichTextGreenEffect.cs
  • GFramework.Godot/Text/Effects/RichTextBlueEffect.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/IRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextGoldEffect.cs
  • GFramework.Godot/Text/Effects/RichTextSineEffect.cs
  • GFramework.Godot/Text/Effects/RichTextFlyInEffect.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
  • GFramework.Godot/Text/RichTextMarkup.cs
  • GFramework.Godot/Text/Effects/RichTextFadeInEffect.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot/Text/Effects/RichTextEffectBase.cs
  • GFramework.Godot/Text/GfRichTextLabel.cs
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Applies to **/*.Tests.cs : Regression fixes should include a test that fails before the fix and passes after it

Applied to files:

  • GFramework.Godot.Tests/Text/RichTextProfileTests.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
🔇 Additional comments (12)
GFramework.Godot/Text/Effects/RichTextBlueEffect.cs (1)

3-27: 实现简洁且行为明确,当前改动可接受。

TagName_ProcessCustomFX 的语义一致,颜色效果实现直接且可读性好。

GFramework.Godot.Tests/Text/RichTextProfileTests.cs (1)

14-30: 测试覆盖点合理,断言粒度到位。

该用例同时校验键集合与顺序,能有效保护默认内置配置不被无意改坏。

GFramework.Godot/Text/Effects/RichTextRedEffect.cs (1)

3-27: 实现一致性良好,改动可接受。

标签名与颜色常量匹配,_ProcessCustomFX 行为明确。

GFramework.Godot/Text/RichTextEffectEntry.cs (1)

3-22: 职责边界定义清晰,当前设计合理。

配置项模型保持轻量,仅表达键与启用状态,便于与注册表职责解耦。

GFramework.Godot/Text/Effects/RichTextGoldEffect.cs (1)

3-27: 实现风格统一,行为正确。

与同类颜色效果的结构一致,便于后续维护与扩展。

GFramework.Godot/Text/Effects/RichTextGreenEffect.cs (1)

3-27: 实现清晰且可读性好,当前改动通过。

TagName 与颜色应用逻辑一致,符合该效果类职责。

GFramework.Godot/Text/RichTextProfile.cs (1)

1-37: LGTM!

代码结构清晰,XML 文档完整。CreateBuiltInDefault() 工厂方法提供了零配置可用的默认效果组合,与 DefaultRichTextEffectRegistry 中的效果键映射保持一致。

GFramework.Godot/Text/Effects/RichTextFadeInEffect.cs (1)

1-47: LGTM!

淡入效果实现正确,使用 charFx.ElapsedTimecharFx.RelativeIndex 计算逐字符进度,alpha 值正确裁剪到 [0,1] 范围。

GFramework.Godot/Text/Effects/RichTextSineEffect.cs (1)

1-47: LGTM!

正弦波效果实现正确,相位计算考虑了时间和字符索引偏移,波形参数(amplitude、frequency、speed)可通过标签环境参数自定义。

GFramework.Godot/Text/Effects/RichTextFlyInEffect.cs (1)

1-64: LGTM!

飞入效果实现完整,结合了位置偏移和透明度渐变。EaseOutQuad 缓动函数提供平滑的减速效果,提升视觉体验。

GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs (1)

1-65: LGTM!

注册表实现清晰,效果键映射与 RichTextProfile.CreateBuiltInDefault() 中定义的 8 个内置键完全对应。键名规范化处理(Trim().ToLowerInvariant())增强了容错性,区分颜色效果和动画效果的参数传递设计合理。

GFramework.Godot/Text/RichTextEffectsController.cs (1)

52-69: 效果刷新流程清晰,回退路径明确。

禁用开关时立即清空、启用时按配置重建 CustomEffects,行为一致且可维护。

Comment thread GFramework.Godot.Tests/Text/RichTextMarkupTests.cs Outdated
Comment thread GFramework.Godot/Text/GfRichTextLabel.cs Outdated
Comment thread GFramework.Godot/Text/GfRichTextLabel.cs
Comment thread GFramework.Godot/Text/GfRichTextLabel.cs
Comment thread GFramework.Godot/Text/GfRichTextLabel.cs Outdated
Comment thread GFramework.Godot/Text/RichTextEffectsController.cs
Comment thread GFramework.Godot/Text/RichTextMarkup.cs Outdated
Comment thread GFramework.Godot/Text/RichTextMarkup.cs Outdated
- 创建 RichTextEffectBase 基类提供统一的标签命名和环境参数读取逻辑
- 实现 RichTextJitterEffect 抖动效果类,支持振幅和速度参数调节
- 添加 DefaultRichTextEffectRegistry 默认效果注册表管理内置效果映射
- 创建 GfRichTextLabel 组合式富文本标签宿主,集成效果装配逻辑
- 定义 IRichTextEffectRegistry 接口实现效果注册表抽象
- 开发 RichTextEffectsController 装配控制器负责效果集合管理
- 实现 RichTextMarkup 工具类提供语义化富文本标签构建辅助方法
- 添加相关单元测试验证效果控制器和标记工具的功能正确性
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs (1)

108-125: 建议:RecordingRegistry 可记录每次调用的 animatedEffectsEnabled 值。

当前 CapturedAnimatedEffectsEnabled 仅保留最后一次调用的值(第 117 行)。若未来测试需验证多次调用时传入的不同 animatedEffectsEnabled 值,可考虑改为列表记录。

♻️ 可选改进
 private sealed class RecordingRegistry : IRichTextEffectRegistry
 {
     public List<RichTextProfile> CapturedProfiles { get; } = [];

-    public bool CapturedAnimatedEffectsEnabled { get; private set; }
+    public List<bool> CapturedAnimatedEffectsEnabled { get; } = [];

     public IReadOnlyList<RichTextEffect> CreateEffects(RichTextProfile profile, bool animatedEffectsEnabled)
     {
         CapturedProfiles.Add(profile);
-        CapturedAnimatedEffectsEnabled = animatedEffectsEnabled;
+        CapturedAnimatedEffectsEnabled.Add(animatedEffectsEnabled);
         return System.Array.Empty<RichTextEffect>();
     }

同时更新断言:

-Assert.That(registry.CapturedAnimatedEffectsEnabled, Is.False);
+Assert.That(registry.CapturedAnimatedEffectsEnabled[0], Is.False);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs` around lines
108 - 125, The RecordingRegistry currently only keeps the last
animatedEffectsEnabled value; change CapturedAnimatedEffectsEnabled from a
single bool to a collection (e.g., List<bool> CapturedAnimatedEffectsEnabled)
and append the incoming animatedEffectsEnabled inside CreateEffects so every
call is recorded; keep CapturedProfiles behavior (List<RichTextProfile>
CapturedProfiles) and update tests to assert against
CapturedAnimatedEffectsEnabled sequence instead of a single value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs`:
- Around line 108-125: The RecordingRegistry currently only keeps the last
animatedEffectsEnabled value; change CapturedAnimatedEffectsEnabled from a
single bool to a collection (e.g., List<bool> CapturedAnimatedEffectsEnabled)
and append the incoming animatedEffectsEnabled inside CreateEffects so every
call is recorded; keep CapturedProfiles behavior (List<RichTextProfile>
CapturedProfiles) and update tests to assert against
CapturedAnimatedEffectsEnabled sequence instead of a single value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f68f449-0e00-4958-ad08-667c14877e64

📥 Commits

Reviewing files that changed from the base of the PR and between e5ad293 and 22882f6.

📒 Files selected for processing (10)
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextEffectBase.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot/Text/IRichTextEffectHost.cs
  • GFramework.Godot/Text/IRichTextEffectRegistry.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot/Text/RichTextMarkup.cs
✅ Files skipped from review due to trivial changes (4)
  • GFramework.Godot/Text/IRichTextEffectHost.cs
  • GFramework.Godot/Text/IRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextEffectBase.cs
  • GFramework.Godot/Text/RichTextMarkup.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (C#)
  • GitHub Check: Code Quality & Security
🧰 Additional context used
📓 Path-based instructions (2)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable
XML documentation comments must explain intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds, compatibility constraints or edge cases, and registration order or lifecycle sequencing
Avoid obvious comments such as // increment i
Core framework components such as Architecture, Module, System, Context, Registry, Service Module, and Lifecycle types MUST include high-level explanations of responsibilities, lifecycle, interaction with other components, why the abstraction exists, and when to use it instead of alternatives
Generated logic and generator pipelines MUST explain what is generated, why it is generated, the semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling if any
Comments MUST NOT be trivial, redundant, or misleading; prefer explaining why and when, not just what
Prefer slightly more explanation over too little for framework code
Do not rely on implicit imports; declare every required using explicitly
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespac...

Files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
**/*.{cs,csproj,xml,yaml,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation; do not use tabs

Files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
🧠 Learnings (7)
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Applies to **/*.cs : Public API changes must be covered by unit or integration tests

Applied to files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Applies to **/*.Tests.cs : Regression fixes should include a test that fails before the fix and passes after it

Applied to files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Applies to **/*.Tests.cs : When a public API defines multiple contract branches, tests MUST cover the meaningful variants, including null, empty, default, and filtered inputs when those branches change behavior

Applied to files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Before considering work complete, confirm: required comments and XML docs are present, code follows repository style and naming rules, relevant tests were added or updated, sensitive or unsafe behavior was not introduced, user-facing documentation is updated when needed, and feature adoption docs under `docs/zh-CN/` were added or updated when functionality was added, removed, or refactored

Applied to files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Every non-trivial feature, bug fix, or behavior change MUST include tests or an explicit justification for why a test is not practical

Applied to files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Godot/Text/GfRichTextLabel.cs
  • GFramework.Godot.Tests/Text/RichTextMarkupTests.cs
  • GFramework.Godot/Text/RichTextEffectsController.cs
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
  • GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs
  • GFramework.Godot/Text/Effects/RichTextJitterEffect.cs
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Applies to **/*.Tests.cs : Reuse existing architecture test infrastructure when relevant: `ArchitectureTestsBase<T>`, `SyncTestArchitecture`, `AsyncTestArchitecture`

Applied to files:

  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
🔇 Additional comments (6)
GFramework.Godot/Text/Effects/RichTextJitterEffect.cs (1)

1-62: LGTM!

实现清晰,XML 文档完整且解释了线程安全假设。噪声种子基于 RelativeIndex 的确定性重置策略保证了每个字符的抖动一致性。

GFramework.Godot/Text/DefaultRichTextEffectRegistry.cs (1)

1-68: LGTM!

注册表实现简洁,CreateEffects 方法正确处理空值和禁用项,CreateEffect 使用 switch 表达式清晰地映射效果键到具体实例。

GFramework.Godot.Tests/Text/RichTextMarkupTests.cs (1)

1-65: LGTM!

测试覆盖了 RichTextMarkup 的核心行为:颜色快捷方法、环境参数按键排序、以及非法标签/键的拒绝。实现层已通过 CollectEnvironmentPairs 确保参数排序确定性,测试断言正确。

GFramework.Godot/Text/RichTextEffectsController.cs (1)

59-69: 设计确认:BbcodeEnabled 状态管理符合文档语义。

当前实现仅在启用框架效果时设置 BbcodeEnabled = true,禁用时不重置。这与 GfRichTextLabel.EnableFrameworkEffects 属性文档的约定一致:"关闭后只会停止框架效果安装,不会覆盖调用方手动维护的其他 BBCode 解析状态"。

此设计避免了框架效果开关意外覆盖用户手动设置的 BBCode 状态。

GFramework.Godot/Text/GfRichTextLabel.cs (1)

68-76: LGTM!

EnsureController() 使用闭包捕获 EffectRegistry 访问器而非实例,确保每次 RefreshEffects() 调用时读取最新的注册表。测试 RefreshEffects_Should_Use_The_Current_Registry_From_Accessor 已验证此行为。

GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs (1)

1-99: LGTM!

测试覆盖了控制器的核心行为分支:启用时的 BBCode 开启与默认配置回退、禁用时的效果清空、以及注册表访问器的动态读取。测试替身设计简洁有效。

coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 18, 2026
- 配置GitHub Actions工作流用于PR构建和测试
- 实现代码质量检查和安全扫描功能
- 添加.NET多版本SDK支持和依赖缓存
- 集成MegaLinter和TruffleHog安全工具
- 创建RichTextEffectsController的单元测试覆盖各种场景
- 实现测试报告生成和发布功能
- 将 RichTextEffectsControllerTests 中的 GFramework.Godot.Text 引用替换为 Godot 相关命名空间
- 使用 Godot.Collections.Array 替代系统数组类型
- 在 GlobalUsings 中添加 GFramework.Godot.Text 的全局引用
- 修复返回类型以使用新的 Array<RichTextEffect> 结构
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs`:
- Around line 1-3: The test file defines a conflicting alias "using Array =
Godot.Collections.Array;" which hides System.Array and causes
Array.Empty<RichTextEffect>() to resolve to the wrong type; fix by replacing
that call with System.Array.Empty<RichTextEffect>() (or remove/rename the alias)
where it's used in RichTextEffectsControllerTests so the generic Empty<T>()
resolves to System.Array; search for Array.Empty<RichTextEffect>() in the test
class and update it to System.Array.Empty<RichTextEffect>().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7eaeba7d-4c17-4990-b18b-c658d674aa00

📥 Commits

Reviewing files that changed from the base of the PR and between 22882f6 and 1c2a813.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Code Quality & Security
  • GitHub Check: Analyze (C#)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable
XML documentation comments must explain intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds, compatibility constraints or edge cases, and registration order or lifecycle sequencing
Avoid obvious comments such as // increment i
Core framework components such as Architecture, Module, System, Context, Registry, Service Module, and Lifecycle types MUST include high-level explanations of responsibilities, lifecycle, interaction with other components, why the abstraction exists, and when to use it instead of alternatives
Generated logic and generator pipelines MUST explain what is generated, why it is generated, the semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling if any
Comments MUST NOT be trivial, redundant, or misleading; prefer explaining why and when, not just what
Prefer slightly more explanation over too little for framework code
Do not rely on implicit imports; declare every required using explicitly
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespac...

Files:

  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
**/*.{cs,csproj,xml,yaml,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation; do not use tabs

Files:

  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
🧠 Learnings (2)
📚 Learning: 2026-04-18T02:29:44.423Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T02:29:44.423Z
Learning: Applies to **/*.Tests.cs : Regression fixes should include a test that fails before the fix and passes after it

Applied to files:

  • .github/workflows/ci.yml
  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs
🪛 GitHub Check: Build and Test
GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs

[failure] 108-108:
'RichTextEffectsControllerTests.RecordingRegistry' does not implement interface member 'IRichTextEffectRegistry.CreateEffect(string, bool)'. 'RichTextEffectsControllerTests.RecordingRegistry.CreateEffect(string, bool)' cannot implement 'IRichTextEffectRegistry.CreateEffect(string, bool)' because it does not have the matching return type of 'RichTextEffect'.


[failure] 108-108:
'RichTextEffectsControllerTests.RecordingRegistry' does not implement interface member 'IRichTextEffectRegistry.CreateEffects(RichTextProfile, bool)'. 'RichTextEffectsControllerTests.RecordingRegistry.CreateEffects(RichTextProfile, bool)' cannot implement 'IRichTextEffectRegistry.CreateEffects(RichTextProfile, bool)' because it does not have the matching return type of 'IReadOnlyList'.


[failure] 121-121:
The type or namespace name 'RichTextEffect' could not be found (are you missing a using directive or an assembly reference?)


[failure] 114-114:
The type or namespace name 'RichTextEffect' could not be found (are you missing a using directive or an assembly reference?)


[failure] 108-108:
'RichTextEffectsControllerTests.RecordingRegistry' does not implement interface member 'IRichTextEffectRegistry.CreateEffect(string, bool)'. 'RichTextEffectsControllerTests.RecordingRegistry.CreateEffect(string, bool)' cannot implement 'IRichTextEffectRegistry.CreateEffect(string, bool)' because it does not have the matching return type of 'RichTextEffect'.


[failure] 108-108:
'RichTextEffectsControllerTests.RecordingRegistry' does not implement interface member 'IRichTextEffectRegistry.CreateEffects(RichTextProfile, bool)'. 'RichTextEffectsControllerTests.RecordingRegistry.CreateEffects(RichTextProfile, bool)' cannot implement 'IRichTextEffectRegistry.CreateEffects(RichTextProfile, bool)' because it does not have the matching return type of 'IReadOnlyList'.


[failure] 121-121:
The type or namespace name 'RichTextEffect' could not be found (are you missing a using directive or an assembly reference?)


[failure] 114-114:
The type or namespace name 'RichTextEffect' could not be found (are you missing a using directive or an assembly reference?)

🔇 Additional comments (3)
.github/workflows/ci.yml (2)

148-153: 顺序执行测试并预创建结果目录的改动很稳妥。

Line 148-153 将测试改为串行并提前创建 TestResults,能有效降低并发测试导致的“假红”概率。


165-190: 失败聚合与统一输出设计清晰。

Line 165-190 使用 failedfailed_projects 聚合失败项目,并在循环后统一输出,便于后续步骤做可靠失败判定。

GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs (1)

16-99: 测试场景覆盖完整,核心行为验证到位

启用/禁用分支、内置 Profile 回退、以及“每次刷新重新读取注册表访问器”的行为都被覆盖,测试目标与控制器职责一致。

Comment thread GFramework.Godot.Tests/Text/RichTextEffectsControllerTests.cs Outdated
- 添加pull-requests写入权限以支持PR评论功能
- 修改pull-request-report条件避免跨仓库触发错误
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2041 2041 0 0 0 0 37.2s    ↓222ms

Test Results

passed 2041 passed

Details

tests 2041 tests
clock 37.2s ↓222ms
tool nunit
build CI - Build & Test arrow-right build-and-test link #867
pull-request feat(text): 添加富文本效果系统和颜色标记功能 link #251

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2062 0 0 7.0s

build-and-test: Run #867

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2041 2041 0 0 0 0 0 37.2s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
Does_Not_Report_When_FieldInjectedModel_Is_Registered 4 4.0s 7.0s
Generates_Scene_Behavior_Boilerplate 4 4.1s 7.0s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 4 3.4s 4.1s
Context_Caching_Should_Improve_Performance 4 967ms 1.3s
ConfigModuleCanRunDuringArchitectureInitialization 4 644ms 1.3s
CleanupDuringAcquire_Should_NotCauseRaceCondition 4 1.1s 1.1s
RegisterCqrsHandlersFromAssembly_Should_Deduplicate_Repeated_Assembly_Registration 4 506ms 1.0s
Append_ShouldNotBlock 4 1.0s 1.0s
SendCommandCoroutine_Should_Forward_Inner_Exception_To_Error_Handler 4 285ms 537ms
Snapshot_BasicPriority 4 289ms 505ms

± Comparison with run #866 at b20c6c2 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 4 runs.

Github Test Reporter by CTRF 💚

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 18, 2026

⚠️MegaLinter analysis: Success with warnings

Descriptor Linter Files Fixed Errors Warnings Elapsed time
⚠️ CSHARP dotnet-format yes 1 no 0.79s
✅ REPOSITORY gitleaks yes no no 3.44s
✅ REPOSITORY trufflehog yes no no 3.87s

Detailed Issues

⚠️ CSHARP / dotnet-format - 1 error
Welcome to .NET 9.0!
---------------------
SDK Version: 9.0.114

----------------
Installed an ASP.NET Core HTTPS development certificate.
To trust the certificate, run 'dotnet dev-certs https --trust'
Learn about HTTPS: https://aka.ms/dotnet-https

----------------
Write your first app: https://aka.ms/dotnet-hello-world
Find out what's new: https://aka.ms/dotnet-whats-new
Explore documentation: https://aka.ms/dotnet-docs
Report issues and find source on GitHub: https://github.com/dotnet/core
Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli
--------------------------------------------------------------------------------------
Unhandled exception: System.IO.FileNotFoundException: Both a MSBuild project file and solution file found in ''. Specify which to use with the <workspace> argument.
   at Microsoft.CodeAnalysis.Tools.Workspaces.MSBuildWorkspaceFinder.FindWorkspace(String searchDirectory, String workspacePath)
   at Microsoft.CodeAnalysis.Tools.Workspaces.MSBuildWorkspaceFinder.FindWorkspace(String searchDirectory, String workspacePath)
   at Microsoft.CodeAnalysis.Tools.FormatCommandCommon.ParseWorkspaceOptions(ParseResult parseResult, FormatOptions formatOptions)
   at Microsoft.CodeAnalysis.Tools.Commands.RootFormatCommand.FormatCommandDefaultHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
   at System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)

See detailed reports in MegaLinter artifacts
Set VALIDATE_ALL_CODEBASE: true in mega-linter.yml to validate all sources, not only the diff

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

- 使用here document格式正确输出失败项目列表到GITHUB_OUTPUT
- 添加EOF分隔符确保多行内容正确传递
- 在失败步骤中读取并显示具体的失败项目名称
- 保持原有的退出码设置确保工作流正确失败
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 18, 2026
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2041 2041 0 0 0 0 37.6s    ↑438ms

Test Results

passed 2041 passed

Details

tests 2041 tests
clock 37.6s ↑438ms
tool nunit
build CI - Build & Test arrow-right build-and-test link #868
pull-request feat(text): 添加富文本效果系统和颜色标记功能 link #251

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2057 0 0 7.0s

build-and-test: Run #868

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2041 2041 0 0 0 0 0 37.6s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
Does_Not_Report_When_FieldInjectedModel_Is_Registered 5 3.7s 7.0s
Generates_Scene_Behavior_Boilerplate 5 3.7s 7.0s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 5 3.5s 4.2s
Context_Caching_Should_Improve_Performance 5 929ms 1.3s
ConfigModuleCanRunDuringArchitectureInitialization 5 552ms 1.3s
CleanupDuringAcquire_Should_NotCauseRaceCondition 5 1.1s 1.1s
RegisterCqrsHandlersFromAssembly_Should_Deduplicate_Repeated_Assembly_Registration 5 446ms 1.0s
Append_ShouldNotBlock 5 1.0s 1.0s
SendCommandCoroutine_Should_Forward_Inner_Exception_To_Error_Handler 5 243ms 537ms
Snapshot_BasicPriority 5 273ms 505ms

± Comparison with run #867 at f31bd60 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 5 runs.

Github Test Reporter by CTRF 💚

- 配置pull request触发的构建和测试流程
- 集成代码质量检查和安全扫描功能
- 设置.NET多版本SDK环境支持
- 配置NuGet包和dotnet工具缓存优化
- 实现Node.js和Bun运行时环境搭建
- 添加配置工具依赖安装和测试执行
- 配置项目构建和单元测试执行流程
- 集成测试报告生成和发布功能
- 实现失败测试项目的错误处理机制
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2041 2041 0 0 0 0 33.8s    ↓3.8s

Test Results

passed 2041 passed

Details

tests 2041 tests
clock 33.8s ↓3.8s
tool nunit
build CI - Build & Test arrow-right build-and-test link #869
pull-request feat(text): 添加富文本效果系统和颜色标记功能 link #251

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2055 0 0 7.0s

build-and-test: Run #869

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2041 2041 0 0 0 0 0 33.8s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
Does_Not_Report_When_FieldInjectedModel_Is_Registered 6 3.4s 7.0s
Generates_Scene_Behavior_Boilerplate 6 3.4s 7.0s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 6 3.6s 4.2s
Context_Caching_Should_Improve_Performance 6 904ms 1.3s
ConfigModuleCanRunDuringArchitectureInitialization 6 490ms 1.3s
CleanupDuringAcquire_Should_NotCauseRaceCondition 6 1.1s 1.1s
RegisterCqrsHandlersFromAssembly_Should_Deduplicate_Repeated_Assembly_Registration 6 405ms 1.0s
Append_ShouldNotBlock 6 1.0s 1.0s
SendCommandCoroutine_Should_Forward_Inner_Exception_To_Error_Handler 6 215ms 537ms
Snapshot_BasicPriority 6 263ms 505ms

± Comparison with run #868 at 973aefb | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 6 runs.

Github Test Reporter by CTRF 💚

- 新增 GfRichTextLabel 组件作为富文本标签宿主
- 实现 IRichTextEffectHost 接口用于效果控制器驱动
- 创建 RichTextEffectsController 处理效果装配逻辑
- 添加 RichTextProfile 配置资源类型
- 引入 RichTextEffectPlan 和 RichTextEffectPlanEntry 类型
- 在 CI 工作流中添加 GFramework.Godot.Tests 项目
- 优化 Godot 测试诊断条件判断逻辑
- 添加富文本效果控制器相关单元测试
@github-actions
Copy link
Copy Markdown

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2093    ↑52 2093    ↑52 0 0 0 0 36.8s    ↑3.0s

Test Results

passed 2093 passed ↑52

Details

tests 2093 tests ↑52
clock 36.8s ↑3.0s
tool nunit
build CI - Build & Test arrow-right build-and-test link #870
pull-request feat(text): 添加富文本效果系统和颜色标记功能 link #251

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2060 0 0 7.0s

build-and-test: Run #870

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2093 2093 0 0 0 0 0 36.8s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
Does_Not_Report_When_FieldInjectedModel_Is_Registered 7 3.2s 7.0s
Generates_Scene_Behavior_Boilerplate 7 3.1s 7.0s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 7 3.8s 4.7s
Context_Caching_Should_Improve_Performance 7 886ms 1.3s
ConfigModuleCanRunDuringArchitectureInitialization 7 445ms 1.3s
CleanupDuringAcquire_Should_NotCauseRaceCondition 7 1.1s 1.1s
RegisterCqrsHandlersFromAssembly_Should_Deduplicate_Repeated_Assembly_Registration 7 375ms 1.0s
Append_ShouldNotBlock 7 1.0s 1.0s
SendCommandCoroutine_Should_Forward_Inner_Exception_To_Error_Handler 7 195ms 537ms
Snapshot_BasicPriority 7 255ms 505ms

± Comparison with run #869 at 0b66484 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 7 runs.

Github Test Reporter by CTRF 💚

@GeWuYou GeWuYou merged commit 22f271e into main Apr 18, 2026
7 checks passed
@GeWuYou GeWuYou deleted the feat/rich-text-effects-and-color-markers branch April 18, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant