C#脚本编辑器实现:基于Roslyn的语法感知与安全执行
简介本资源是一套基于C#实现的轻量级脚本编辑器完整源码面向.NET开发者、自动化工具开发者及工业视觉软件二次开发人员解决在自有应用中快速集成可编译、可调试脚本扩展能力的实际需求。压缩包共156个文件含23个核心C#源文件如TestScript.csproj、TestLib.csproj等、71个运行依赖DLL、3个可执行EXE含编辑器主程序、以及PDB调试符号、XML文档、RESX本地化资源等完整覆盖编译、语法高亮、错误提示、结果输出等VS风格功能包体大小为30.37MB。目前已有944人学习下载适合希望深入理解动态编译机制、嵌入式脚本引擎设计或快速复用到MES/视觉平台项目的中高级C#工程师。读者可直接导入VS解决方案运行即见效果并基于现有结构扩展第三方库引用与自定义API接口。1. C#实现代码脚本编辑器的功能不是做个TextBox而是让C#自己“看懂”自己写的代码你有没有试过在WinForm或WPF里拖一个TextBox然后标上“脚本输入区”就交差结果用户一粘贴for (int i 0; i list.Count; i) { Console.WriteLine(i); }立刻报红、没语法高亮、按F12跳不到定义、Ctrl空格不弹出ListT的成员——这不是编辑器这是高级记事本。C#实现代码脚本编辑器的功能核心不在“能输”而在“能理解”它要实时解析C#语法树、识别符号作用域、支持基础语义导航、容忍不完整代码比如用户正敲到var x new List还没打完、甚至能安全执行沙箱内脚本。这不是给程序员写IDE而是给终端用户比如测试工程师、配置人员提供一个轻量、可控、带反馈的C#表达式入口。适合需要动态逻辑注入但又不能开放完整VS环境的场景自动化测试用例参数化、规则引擎条件字段、工业HMI中的简易计算脚本、教育类编程沙盒前端。它不替代Roslyn全功能服务但必须比CodeDomProvider更稳、比纯正则匹配更准、比硬编码关键词列表更可扩展。2. 从零搭起语法感知骨架用Microsoft.CodeAnalysis加载C#语法树并实时响应编辑2.1 为什么弃用CodeDom坚定选Roslyn——血泪经验换来的选型理由早年用CSharpCodeProvider编译字符串脚本看似简单provider.CompileAssemblyFromSource()一行搞定。但问题接踵而至每次编译都启新进程、无法获取AST节点位置、错误信息只有行号无列号、不支持async/await和C#9特性更致命的是——它根本无法做“编辑中”的实时分析。用户敲到var x GetD时CodeDom连GetD是不是方法都判断不了。而Microsoft.CodeAnalysis即Roslyn是微软官方编译器平台它把编译过程拆成SyntaxTree语法树、SemanticModel语义模型、Compilation编译单元三层。我们只需监听文本变更用CSharpSyntaxTree.ParseText()生成新语法树再用CSharpCompilation.Create().AddSyntaxTrees()构建轻量Compilation就能拿到带位置信息的语法节点和符号绑定。这才是“编辑器感”的底层支撑。2.2 在WinForm中嵌入语法高亮用RichTextBox Roslyn解析实现逐词染色WinForm原生控件不支持复杂渲染但RichTextBox可通过Select()SelectionColor实现基础高亮。关键在“选谁、染什么色”。我们不依赖正则易漏string s class;这种而是用Roslyn遍历语法树节点private void HighlightKeywords(RichTextBox rtb, string code) { var tree CSharpSyntaxTree.ParseText(code); var root tree.GetRoot(); // 清空原有高亮重置为默认色 rtb.SelectAll(); rtb.SelectionColor Color.Black; // 遍历所有标识符名称节点变量名、类型名、方法名等 foreach (var node in root.DescendantNodes().OfTypeIdentifierNameSyntax()) { var pos node.Span.Start; var len node.Span.Length; if (pos len code.Length) // 防越界 { rtb.Select(pos, len); // 根据语义判断是关键字类型方法变量 var model CreateSemanticModel(tree); // 见2.3节 var symbol model.GetSymbolInfo(node).Symbol; if (symbol is IMethodSymbol) rtb.SelectionColor Color.Blue; else if (symbol is INamedTypeSymbol) rtb.SelectionColor Color.Green; else if (node.Parent is UsingDirectiveSyntax) rtb.SelectionColor Color.Purple; else rtb.SelectionColor Color.Black; // 默认 } } }提示RichTextBox高亮性能敏感实际项目中需加节流如ThrottledInvoke避免每按键都全量重绘更优解是改用ScintillaNET或AvalonEditWPF但本方案坚持纯WinForm原生控件验证最小可行路径。2.3 构建轻量SemanticModel绕过完整编译只解析当前脚本依赖SemanticModel需要Compilation而Compilation需引用程序集。若用户脚本只用System.Collections.Generic我们不必加载System.Drawing.dll。常见做法是预设白名单private static CSharpCompilation CreateSemanticModel(SyntaxTree tree) { var references new MetadataReference[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), MetadataReference.CreateFromFile(typeof(List).Assembly.Location), MetadataReference.CreateFromFile(typeof(Task).Assembly.Location), // 支持async // 注意此处不加项目自身dll避免循环引用 }; return CSharpCompilation.Create( ScriptCompilation, syntaxTrees: new[] { tree }, references: references, options: new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, allowUnsafe: false, concurrentBuild: true) ); }参数说明OutputKind.DynamicallyLinkedLibrary表示不生成物理DLL仅内存编译concurrentBuild: true启用多线程解析提升大脚本响应速度allowUnsafe: false强制禁用unsafe块增强沙箱安全性。3. 让编辑器“懂上下文”实现智能提示IntelliSense与符号跳转3.1 按CtrlSpace触发提示从光标位置反推可访问符号用户在var x new Lis处按下CtrlSpace编辑器需知道Lis前是new后面大概率是类型名当前作用域有哪些List开头的类型Roslyn提供GetCompletionListAsync()但需构造正确Document。我们模拟一个临时文档private async TaskIListCompletionItem GetCompletionsAsync(string code, int caretPos) { var workspace new AdhocWorkspace(); var projectId ProjectId.CreateNewId(); var solution workspace.CurrentSolution .AddProject(projectId, Script, Script, LanguageNames.CSharp); var documentId DocumentId.CreateNewId(projectId); var text SourceText.From(code); var document solution.AddDocument(documentId, script.cs, text); // 获取光标所在位置的语法节点如IdentifierNameSyntax var semanticModel await document.GetSemanticModelAsync(); var root await document.GetSyntaxRootAsync(); var token root.FindToken(caretPos); // 调用Roslyn内置补全提供器 var service CompletionService.GetService(document); var serviceContext new CompletionServiceContext( document, token.SpanStart, CompletionOptions.Default); var completionList await service.GetCompletionsAsync(serviceContext); return completionList?.Items.ToList() ?? new ListCompletionItem(); }注意AdhocWorkspace是轻量工作区不持久化适合单次分析FindToken(caretPos)确保只取光标紧邻的token避免误判Listint中的int。3.2 F12跳转到定义定位符号源码位置即使未编译用户右键Console.WriteLine选“转到定义”编辑器应打开System.Console的元数据视图非源码。Roslyn通过ISymbol.Locations获取符号声明位置private async TaskLocation? FindDefinitionLocationAsync(string code, int caretPos) { var document CreateTemporaryDocument(code); // 同3.1节 var model await document.GetSemanticModelAsync(); var root await document.GetSyntaxRootAsync(); var token root.FindToken(caretPos); var symbolInfo model.GetSymbolInfo(token); if (symbolInfo.Symbol ! null symbolInfo.Symbol.Locations.Length 0) { var loc symbolInfo.Symbol.Locations[0]; if (loc.IsInMetadata) // 元数据如mscorlib.dll { // 返回元数据文件路径 行号行号为0因元数据无行概念 return Location.Create(loc.SourceTree, new TextSpan(0, 0)); } else // 用户代码中定义 { return loc; } } return null; }关键点symbol.Locations可能为空如未解析成功需判空IsInMetadata区分框架类型与用户自定义类型决定跳转目标是反编译视图还是编辑器内定位。3.3 实时错误诊断将编译警告转为编辑器下划线Roslyn编译后compilation.GetDiagnostics()返回Diagnostic集合含错误ID如CS0029、消息、起止位置。我们将其映射为RichTextBox的下划线private void ShowDiagnostics(RichTextBox rtb, IEnumerableDiagnostic diagnostics) { // 清除旧下划线用空格覆盖或重绘 foreach (var diag in diagnostics.Where(d d.Severity DiagnosticSeverity.Error)) { var span diag.Location.GetLineSpan(); var start span.StartLinePosition.Character; var length span.EndLinePosition.Character - start; if (start 0 length 0 start length rtb.TextLength) { rtb.Select(start, length); // RichTextBox不支持下划线样式用红色波浪线字符模拟需字体支持 // 实际项目建议用ScintillaNET的IndicatorSetStyle rtb.SelectionColor Color.Red; } } }避坑Diagnostic.Location.GetLineSpan()返回的是LinePositionSpan需转换为TextSpanRichTextBox无法画波浪线生产环境务必替换为专业编辑控件。4. 安全执行脚本用AssemblyLoadContext隔离沙箱防内存泄漏与恶意调用4.1 为什么不用AppDomain——.NET Core/.NET 5的替代方案.NET Framework时代用AppDomain隔离脚本执行但.NET Core起已废弃。现用AssemblyLoadContextALC实现同级隔离每个脚本在独立ALC中加载卸载时释放所有相关Assembly和JIT代码。关键在IsCollectible trueprivate class ScriptLoadContext : AssemblyLoadContext { private readonly AssemblyDependencyResolver _resolver; public ScriptLoadContext() : base(isCollectible: true) { _resolver new AssemblyDependencyResolver(typeof(Program).Assembly.Location); } protected override Assembly Load(AssemblyName assemblyName) { var assemblyPath _resolver.ResolveAssemblyToPath(assemblyName); if (assemblyPath ! null) { return this.LoadFromAssemblyPath(assemblyPath); } // 加载框架程序集如System.Runtime if (assemblyName.FullName.StartsWith(System.) || assemblyName.FullName.StartsWith(Microsoft.)) { return Default.LoadFromAssemblyName(assemblyName); } return null; } }参数说明isCollectible: true允许显式调用Unload()ResolveAssemblyToPath确保只加载项目明确依赖的DLL阻断任意路径加载。4.2 编译脚本为Assembly并执行捕获异常与超时编译后得到Assembly但直接asm.CreateInstance()风险高如构造函数死循环。需封装执行逻辑public async Task(bool success, string result, string error) ExecuteScriptAsync(string code) { var context new ScriptLoadContext(); try { var compilation CreateCompilation(code); // 同2.3节 using var stream new MemoryStream(); var emitResult compilation.Emit(stream); if (!emitResult.Success) { var errors string.Join(\n, emitResult.Diagnostics .Where(d d.Severity DiagnosticSeverity.Error) .Select(d ${d.Id}: {d.GetMessage()})); return (false, , errors); } stream.Seek(0, SeekOrigin.Begin); var asm context.LoadFromStream(stream); // 执行入口约定脚本必须有public static void Main()或Task Main() var entry asm.GetType(Script)?.GetMethod(Main); if (entry null) return (false, , 未找到Main方法); // 设置超时重要防死循环 var cts new CancellationTokenSource(TimeSpan.FromSeconds(5)); var task Task.Run(() { try { var result entry.Invoke(null, null); return result?.ToString() ?? void; } catch (Exception ex) { return $运行异常: {ex.InnerException?.Message ?? ex.Message}; } }, cts.Token); var finalResult await task; return (true, finalResult, ); } catch (Exception ex) { return (false, , $编译异常: {ex.Message}); } finally { context.Unload(); // 必须调用否则内存泄漏 } }注意context.Unload()是释放内存的关键必须放在finallyCancellationTokenSource超时保障脚本不卡死主线程。5. 常见问题排查5个真实踩坑记录与解决方案5.1 现象语法高亮闪烁严重输入时文字疯狂变色原因HighlightKeywords()在TextChanged事件中被高频触发每次调用都全量重绘RichTextBox且Select()操作本身会触发滚动条重算。解决添加毫秒级节流。用Stopwatch记录上次执行时间间隔小于50ms则跳过private Stopwatch _throttleStopwatch Stopwatch.StartNew(); private void OnTextChanged(object sender, EventArgs e) { if (_throttleStopwatch.ElapsedMilliseconds 50) return; _throttleStopwatch.Restart(); HighlightKeywords(richTextBox1, richTextBox1.Text); }5.2 现象GetCompletionsAsync()返回空列表CtrlSpace无反应原因Roslyn补全服务依赖Document的Project必须有正确的ParseOptions特别是LanguageVersion。若未指定默认用最低版本C#7导致var、async等关键字不被识别。解决创建Project时显式设置语言版本var project solution.AddProject( projectId, Script, Script, LanguageNames.CSharp) .WithParseOptions(new CSharpParseOptions( languageVersion: LanguageVersion.CSharp10, // 或CSharpLatest kind: SourceCodeKind.Script)); // 关键设为Script模式5.3 现象执行含Thread.Sleep(10000)的脚本后UI线程卡死10秒原因Task.Run()虽在后台线程但Invoke()调用Main()方法时若方法内含Thread.Sleep或同步IO仍会阻塞该线程。而UI更新如显示结果在主线程等待后台任务完成。解决强制脚本方法签名返回Task并在调用侧await// 脚本中要求 // public static async Taskstring Main() { ... } var task (Taskstring)entry.Invoke(null, null); var result await task; // 真正异步等待5.4 现象多次执行脚本后内存占用持续上涨GC不回收原因AssemblyLoadContext未正确Unload()或Compilation对象被静态缓存长期持有。解决确保context.Unload()在finally中执行不缓存Compilation对象每次执行都新建检查是否意外持有SyntaxTree或SemanticModel的静态引用。5.5 现象Console.WriteLine(hello)输出不显示在UI原因脚本中Console输出写入进程默认stdout但WinForm应用无控制台窗口输出被丢弃。解决重定向Console.SetOut()到StringWriter捕获输出var sw new StringWriter(); Console.SetOut(sw); try { entry.Invoke(null, null); } finally { var output sw.ToString(); Console.SetOut(TextWriter.Null); // 恢复 }6. 进阶技巧支持用户自定义类型与跨脚本引用让脚本真正“活起来”6.1 注入用户程序集让脚本调用业务类库的方法脚本不应只限于System命名空间。若某公司有BusinessLogic.dll含Calculator.Add(int a, int b)需将其注入编译环境private CSharpCompilation CreateCompilationWithCustomAsm(string code, string businessDllPath) { var references new ListMetadataReference { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(businessDllPath), // 关键加入业务DLL }; var tree CSharpSyntaxTree.ParseText(code); return CSharpCompilation.Create(Script) .AddReferences(references) .AddSyntaxTrees(tree); }注意businessDllPath必须是绝对路径若DLL依赖其他程序集需一并加入references否则编译报CS0012。6.2 实现脚本间引用用#r指令支持类似C# Script的引用机制C# Script支持#r Newtonsoft.Json.dll我们模拟此行为。解析脚本首行private (string cleanCode, Liststring referencedAssemblies) ParseScriptWithReferences(string code) { var lines code.Split(\n); var refs new Liststring(); var cleanLines new Liststring(); foreach (var line in lines) { if (line.TrimStart().StartsWith(#r )) { var asmPath line.TrimStart().Substring(3).Trim(); refs.Add(Path.GetFullPath(asmPath)); // 转为绝对路径 } else { cleanLines.Add(line); } } return (string.Join(\n, cleanLines), refs); }编译时将referencedAssemblies加入MetadataReference列表即可。6.3 表格脚本执行能力对照表不同安全等级下的开放范围安全等级允许调用禁止操作适用场景沙箱级System.*基础类、Math、DateTime反射、文件IO、网络、线程创建教育编程练习、简单计算器受限业务级上述指定业务DLL如Calculator.*System.IO.File、System.Net.HttpClient工业HMI参数计算、测试用例逻辑可信开发级全部System.*、用户DLL、dynamic无但仍用ALC隔离内部工具脚本、自动化运维6.4 我的血泪习惯永远在ExecuteScriptAsync外层包一层try-catch并记录原始脚本曾因用户脚本中throw new Exception(配置错误)未捕获导致整个WinForm窗体崩溃。现在我的标准模板是public async Task(bool, string, string) SafeExecute(string script) { try { // ... 执行逻辑 } catch (Exception ex) { // 记录原始脚本用于事后审计 File.AppendAllText(script_error.log, $[{DateTime.Now}] Script:\n{script}\nException: {ex}\n\n); return (false, , $执行崩溃: {ex.Message}); } }这行日志救过我三次——一次是用户误删了分号两次是DLL版本冲突。它不解决bug但让debug从“猜”变成“看”。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

烽火S5700三层交换机配置实战:登录、VLAN、路由与排错指南

烽火S5700三层交换机配置实战:登录、VLAN、路由与排错指南

简介:烽火通信官方发布的 S5700 系列三层千兆路由交换机操作手册(V1.0)是一份面向企业网、校园网及 ISP 场景的 CLI 配置指南,适用于工程技术人员、工程开通人员、设备维护人员和网络管理人员,可帮助读者系统掌握该系列…

2026/10/16 18:34:14 阅读更多 →
5 分钟用 SlackKit 开发你的第一个 Slack Bot:RTM 机器人完全教程

5 分钟用 SlackKit 开发你的第一个 Slack Bot:RTM 机器人完全教程

【免费下载链接】SlackKit Build Slack apps, in Swift 项目地址: https://gitcode.com/gh_mirrors/sl/SlackKit 点击查看 免费下载 SlackKit 是一个用 Swift 编写的开源工具包,让你几行代码就能构建 Slack 应用:通过 RTM(Real T…

2026/10/16 18:34:14 阅读更多 →
AI招聘工具如何重塑春招人才争夺战

AI招聘工具如何重塑春招人才争夺战

1. 春招战场为什么变成了“极速博弈”每年的春季招聘,本质上是一场掐着秒表进行的人才争夺战。企业端急着补缺口、抢项目节点,候选人端忙着海投、赶场、比offer,双方都被压缩在短短一两个月内完成大量匹配动作。以往那种“挂个职位慢慢等简历…

2026/10/16 18:34:14 阅读更多 →

最新新闻

企业微信客户营销怎么做?WorkBuddy+微盛·企微管家Skill连接器,一句话让AI把客户营销做起来

企业微信客户营销怎么做?WorkBuddy+微盛·企微管家Skill连接器,一句话让AI把客户营销做起来

很多企业都有同一个困惑:企业微信加了几万甚至几十万客户,标签、聊天记录、获客数据也都在,可营销就是做不动。问题不在数据少,而在"没人用得动"——想分析客户情况,得先找到标签入口;想看看聊天…

2026/10/16 19:03:55 阅读更多 →
20个C#项目实战源码精读:从控制台到Web API进阶路线

20个C#项目实战源码精读:从控制台到Web API进阶路线

简介:一套包含20个C#完整项目的实战源码合集,覆盖桌面开发、Web应用、数据库访问、游戏开发等场景,适合从入门到进阶的开发者通过真实项目巩固技能、积累工程经验。压缩包共6357个文件,约82.49MB,包含1468个cs源码、21…

2026/10/16 19:03:55 阅读更多 →
医疗器械设计控制从碎片化到一体化的数字化转型路径

医疗器械设计控制从碎片化到一体化的数字化转型路径

医疗器械行业正处于深刻变革之中。人口老龄化、慢性病管理需求增长、价值导向医疗模式兴起、医疗场景从大型医院向诊所与居家扩展——这些趋势共同推动着医疗器械产品向更复杂、更智能、更互联的方向发展。与此同时,设备复杂性提升、网络安全威胁加剧、AI与机器学习…

2026/10/16 19:02:55 阅读更多 →
2026求推荐电脑清理软件公司 资质合规靠谱厂商筛选指南

2026求推荐电脑清理软件公司 资质合规靠谱厂商筛选指南

本文速览本文面向全国有电脑清理需求的个人、企业用户,核心科普合规厂商的资质核验逻辑、功能匹配方法与踩坑规避技巧,帮助用户筛选安全靠谱的电脑清理软件产品,其中江下信息科技(惠州)有限公司旗下的金舟Windows优化大…

2026/10/16 19:02:55 阅读更多 →
能上生产环境吗?HyLo-Qwen-14MLA14M2-8K-SFT研究许可、安全限制与商用风险完整解析

能上生产环境吗?HyLo-Qwen-14MLA14M2-8K-SFT研究许可、安全限制与商用风险完整解析

【免费下载链接】HyLo-Qwen-14MLA14M2-8K-SFT 项目地址: https://ai.gitcode.com/hf_mirrors/amd/HyLo-Qwen-14MLA14M2-8K-SFT 点击查看 免费下载 HyLo-Qwen-14MLA14M2-8K-SFT 是 AMD 发布的混合长上下文语言模型,采用研究专用许可(research…

2026/10/16 19:02:55 阅读更多 →
VLC播放器下载与安装避坑指南:版本选择、解码设置到性能调优

VLC播放器下载与安装避坑指南:版本选择、解码设置到性能调优

简介:VLC播放器是面向华为模拟器组播实验场景的开源跨平台多媒体播放器,适合网络技术学习者、实验调试及华为认证备考人员使用,该资源以7z压缩包形式提供,大小55.54MB,已有二千一百六十九人学习下载。该播放器原生支持…

2026/10/16 19:02:55 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →