DevLog:2025年9月17日

1、昨天已经基本实现了模型添加、AI对话的基础功能,今天继续完善,首先是添加多个模型并在对话时切换模型,首先在添加两个模型之后,发现设置-可用模型的模型列表里,两个模型之间有两条分割线,而且创建新模型时,无法保存我填写的新API密钥和基础URL,而是沿用了我添加的第一个模型的API密钥和基础URL

2、首先更新了AIModel结构体,添加了apiKey和baseURL字段,移除了isDefault字段,修复了ModelEditView的保存逻辑,更新了模型测试逻辑和对话配置逻辑,使用模型自己的API配置进行对话,而不是使用全局的API配置(早就应该这样了),然后移除了modelRow函数中的Divider():,去掉了多余的分割线,再次测试,两个问题成功解决

3、但AI对话窗口里又出现了回答在上、问题在下的情况,另外切换模型的弹窗显示也有问题,先修复切换模型的弹窗的显示效果,同时修复一下AI对话列表的选中状态,目前根本看不出来选中了哪个对话,修改后仍然不能在对话列表中标示出当前选中的对话,还需要再修改

4、先用硅基流动的DeepSeek R1 API测试了一个需要联网获取最新信息的问题,发现目前思考过程没有展示、AI回答内容没有经Markdown渲染、看不到Tavily提供的资料链接,决定让Cursor同时修复这些问题,并明确要求使用MarkdownUI来进行Markdown渲染,其实之前已经有了一部分支持这些功能的代码,但功能不完整,Cursor列出了Todo,一步步修改,稍后一并给Cursor反馈问题

5、Cursor一次修改了思考过程展示/折叠和展开、Markdown渲染、Tavily资料链接显示等功能,其中在Markdown渲染上,先创建了一个新的文件MarkdownView,但没有添加到项目里,提示构建失败,于是又重新启用现有的MarkdownRenderer,并且引入了MarkdownUI,同时还保留了自定义AttributedString实现作为备选方案,原因貌似是MarkdownUI只支持14.0以上的macOS,我觉得没有必要保留备选方案,之前修改NoteWith时已经验证了MarkdownUI的渲染效果,于是要求Cursor去掉了自定义实现相关代码,使用MarkdownUI作为唯一的渲染方案,MarkdownRenderer代码更加简洁了

6、接下来测试一下思考过程、Markdown渲染、Tavily链接的显示效果,先把AI对话内容的显示顺序搞定,然后处理了一下点击AI对话右上角无法切换模型的问题(原因是ChatView的模型选择回调中代码被注释掉了,没有实际实现模型切换功能,而且每个对话都显示第一个可用模型,而不是用户选择的模型,模型切换没有保存到对话中,我需要为每个对话独立保存选择的模型),Cursor自称目前已经实现如下目标:新对话默认使用第一个可用模型、点击右上角的模型名称选择其它模型、选择的模型立即保存到该对话中、每个对话都有自己独立的模型选择、重启应用后每个对话仍然使用之前选择的模型

7、模型可以正常切换了,但试了几个问题,发现无法触发应用通过Tavily获取最新信息,Cursor分析发现虽然Tavily密钥已经存储在模型中,但实际的消息发送逻辑中没有使用Tavily服务,需要实现Tavily集成,创建了一个新的Tavily服务类TavilyService,并修改了OpenAIService,表示当提问时应用会自动通过Tavily获取最新信息

8、测试发现即使是不支持深度思考的模型,回答内容里也会出现思考过程区域,而且回答内容没有经过Markdown渲染,也看不到Tavily的资料链接,在用MarkdownUI来实现Markdown渲染效果的过程中,Cursor多次创建和删除Package文件(因为一直没有真正引入MarkdownUI),多次用命令行修改MarkdownRenderer,多次尝试不使用MarkdownUI,而是换用SwiftUI的原生功能来实现基本的Markdown渲染,不知道为啥今天反复出现这种“退步”的操作,我多次打断,反复强调要用MarkdownUI来渲染

9、已经有部分文字可以呈现渲染后的效果,但表格还是无法正常显示,参考NoteWith,可能要对表格和代码块的显示进行单独的优化,猜测上面重复同样的操作可能是因为这个对话的上下文太长了导致的,后面在Cursor里开一个新对话再修改这些内容

10、又遇到了刚刚进行的问答没有被保存到对话里的问题,在修改ChatWith,将用户消息和AI消息更新后都调用onUpdate将其保存到Core Data后,问题解决

11、在修改MarkdownRenderer以支持对表格和代码块的渲染优化时,Cursor反复检查MarkdownUI的版本、添加MarkdownUI默认的表格和代码块渲染样式、添加自定义的表格和代码块渲染样式,然后删除这些内容,多次操作后相当于没有做任何的修改

12、决定试试让Cursor创建单独的文件来处理表格和代码块的渲染,并且使用MarkdownUI,Cursor创建了TableRenderer和CodeBlockRenderer,并将新文件添加到项目,但多次尝试后,即使已经将这两个新文件集成到AssistantMessageView之后,仍然未能实现对表格的正常渲染

13、由于目前的ChatWith是由iOS应用修改而来,且在修改过程中对代码和架构进行了大量的调整,怀疑目前有部分文件功能是重复的,让Cursor列举结构和分工后发现ChatWrapper是多余的、ChatView过于庞大、且组件职责不清晰,比如ChatMessageListSection和ChatMessageListView功能重复、ChatInputSection和ChatInputView功能重复,Cursor建议简化架构、删除冗余文件、重新组织文件结构,决定让Cursor实施这些优化

14、修改完成后架构更清晰(每个文件职责单一,易于维护,减少了不必要的中间层),代码更简洁(ChatView从436行减少到约280行,移除了重复的组件子定义),维护性更好(组件独立,便于单独测试和修改,文件结构更符合SwiftUI最佳实践),当然每次Cursor在修改完后都会这么说,还是要实际测试一下修改成果

15、继续测试具体的功能,首先发现在与支持深度思考的DeepSeek R1模型对话时,思考内容和回答内容混在了一起,未能像之前规划的那样分成两块,并且思考内容要可以折叠,可以展开,Cursor在分析后修改了OpenAIService中的seperateThinkAndAnswer函数,以正确解析思考内容,但仍然没有解决问题

16、我现在觉得可能将iOS版的ChatWith修改成Mac版,再逐个测试、恢复功能,可能是做了大量的重复工作,既然之前NoteWith for Mac已经基本可用了,那其实可以对它进行简化,实现我对ChatWith for Mac的一系列需求,于是复制了一份NoteWith for Mac的源文件,并要求Cursor将应用的名字改成ChatWith,这一过程包括将应用名称由NoteWith改为ChatWith、更新XCode项目文件中的名称引用、更新Swift文件中的名称引用、更新Info.plist文件、重命名相关文件夹和文件等

17、Cursor很快完成了修改,并且按照我的反馈替换掉了一些漏网之鱼,接下来就是去掉待办事项模块、测试功能了,后面可能还要把备忘录替换为收藏,去掉待办事项模块及相关功能包括了分析待办事项模块的组件和依赖、移除待办事项相关的数据模型、移除待办事项相关的视图、移除待办事项相关的视图模型、从DataManager中移除待办事项相关代码、从导航中移除待办事项相关项目、从项目文件中移除待办事项相关文件等步骤,并且根据我的反馈删掉了两处遗留的待办事项相关功能

18、构建成功后,整理了文件结构,特别是Views文件夹下既有AIChat和Notes两个文件夹来存放AI对话和备忘录相关的视图文件,又有大量视图文件散落在Views文件夹下,ViewModels文件夹也有类似问题,移动文件并更新project.pbxproj中的路径后,问题解决,结构清晰了一些

DevLog:2025年9月16日

1、今天首先解决昨天的遗留问题,统一一下应用的布局,改成三栏布局,最左边是应用的名字,以及对话、收藏、设置 三个按钮,中间栏是对话列表、收藏列表和设置大项,第三栏是对应的详情,Cursor延续了昨天的NavigationSplitView,并且创建了AppSidebar和MiddleSideBar组件(都在ContentView里,后面可能也要拆分这个文件了),然后修改了多个文件来匹配三栏布局

2、最左侧导航栏的颜色、图标、文字大小等样式都还可以,但目前对话界面缺少了创建对话按钮,设置界面的详情显示也都比较局促,需要继续调整布局和功能,比如:

1.模型设置界面需要有多模型管理功能,可以添加、删除、测试模型,并且增加Tavily联网搜索能力的支持,Base URL需要具备自动补全能力

2.增加回收站功能,可以管理已删除的对话和收藏,并且按钮放在数据统计和外观设置之间

3.外观设置的样式也需要改一下,现在这种横向三个按钮切换显得很局促

3、接下来一步步修改,先从模型的添加、修改、删除、测试功能开始,第一次修改后效果不佳,我发现DetailView好像包含了对话、收藏、设置三个模块的最右侧区域,于是让Cursor将其拆分为单独的文件,ConversationDetailView、FavoriteDetailView、SettingsDetailView,拆分后DetailView由596行代码缩减成了42行,并且新创建的三个文件每个文件都专注于特定功能,代码结构清晰了一些

4、现在添加模型的弹窗显示不正常,可填写信息的窗口只有很小一块,存在大片空白,无法正常使用,让Cursor修复,同时删除可用模型列表顶部的API配置按钮,我不需要在列表里配置API Key和BASE URL

5、然后调整弹窗的功能,包括给弹窗增加Tavily密钥字段,放在API配置的最后,弹窗底部增加取消和保存两个按钮,去掉“默认模型”相关的设置等等,现在弹窗信息可以完整显示,并且效果还可以,然后删除了部分按钮的边框线,去掉了“默认”标识,但Cursor标识在删除当前使用的模型时会自动切换到第一个可用的模型,看样子还是有类似默认模型、当前模型的设置,还是要清理掉

6、开始添加模型,测试后决定,删掉应用预置的默认模型配置,所有的模型都由用户来自行设置,另外在点击测试时,无需通过弹窗提示测试结果,直接在列表里模型名称的下方显示测试结果,比如错误信息、响应时间等,然后修正部分问题,比如在添加模型后重启应用模型信息会消失,创建新模型时可以看到之前填写的API KEY和Base URL

7、发现SettingsView里目前还有一些AI模型相关设置,但刚刚这些修改都不涉及SettingsView,怀疑可能有部分代码未被使用,询问后发现整个文件都未被使用,并且SidebarView里也有部分过时代码,一并进行了清理

7、看起来暂时没有引发新的问题,目前已经添加了第一个模型,继续测试AI对话功能,首先就是对话界面缺少了创建新对话按钮,把这个按钮加在对话界面右上角,测试发现即使是经过测试提示连接成功的模型,也无法正常对话,Cursor表示目前没有实现真正的模型测试功能,没有真正调用API,怪不得每次测试连接时间都是1.2s,并且ChatView使用的是全局的AppStorage值,而不是用户选择的模型配置,在修改过程中Cursor添加了一些调试信息,发现可能是因为currentModelID为空字符串,导致无法找到匹配的模型,系统回退到默认配置gpt-3.5-turbo,而不是我自己配置的模型

8、这就是上面说的“当前模型”的设置,要求Cursor去掉这个增加了应用复杂性的功能,在开启对话时,直接用可用模型列表里的第一个模型

9、测试了几次对话,但发送消息后会报错400,结合Cursor添加的调试信息,多次反馈后定位了问题,然后修正了AI对话内容无法保存的问题,可能是未能将新对话和更新的对话保存到Core Data,至此已经基本实现了添加模型、AI对话的基础操作

10、修改了AI对话消息的显示顺序,改成问题在上、回答在下,明天再继续完善功能,比如添加多个模型、测试模型的切换效果,完善AI对话列表的选中状态提示、更新时间、置顶/取消置顶等右键菜单操作

DevLog:2025年9月15日

1、目前ChatWith for Mac使用的数据存储方式是UserDefaults,虽然目前应用的功能还很少,UserDefaults足矣,但这种存储方式不适合大量数据存储,数据量大时读写较慢,只能存储基本类型和可编码对象,且不支持复杂查询,决定趁现在应用功能还少(并且参考NoteWith的教训,将数据存储方式切换到Core Data之后基本上所有功能都要重新测试、大量修改),先把对话数据切换到Core Data,设置类的数据仍然用UserDefaults
2、Cursor拆解步骤包括:设置Core Data模型和持久化容器、创建Core Data实体模型、更新ConversationManager使用Core Data、迁移现有的UserDefaults数据到Core Data,修改过程中Cursor创建了新的文件,但没有直接修改项目文件,反而又把新文件删除了,打断操作后纠正了这种无故回退的操作,而且反复创建版本化的模型文件
3、为了优先保证成功构建,Cursor先创建CoreDataManager,并通过CoreDataManager管理对话数据,但底层先使用了UserDefaults,在我的要求下切换到了Core Data,创建了ChatWith.xcdatamodeld模型文件,定义了ConversationEntity和MessageEntity实体,设置了正确的属性和关系映射(之前用Trae时创建模型文件、定义实体和设置属性、关系映射都需要手动操作),同时还实现数据迁移机制,自动检测并迁移现有的UserDefaults数据到Core Data
4、但目前这个应用还不需要数据迁移机制,于是修改了CoreDataManager和ConversationManager,移除了数据迁移相关代码,至此,对话数据使用Core Data进行持久化存储,设置数据继续使用UserDefaults
5、测试发现有多个文件出现了onChange相关的警告,这是因为在macOS 14.0中,onChange(of:perform)语法被弃用了,需要使用新的语法,修改后警告消除
6、还有一处警告信息:ChatWith isn’t code signed but requires entitlements. It is not possible to add entitlements to a binary without signing it.这是因为应用中又entitlements权限文件,但没有进行代码签名,macOS要求又权限文件的应用必须进行代码签名,Cursor认为目前应用不需要特殊权限,于是将其删除,后续如果需要将应用发布到App Store或者需要特殊权限时可以重新创建entitlements文件并配置签名代码、添加必要的权限声明
7、接下来修改应用的布局,先修改对话和收藏界面,左侧是列表,右侧是详情,Cursor使用了NavigationSplitView来替代以前的TabView,并且创建了左侧边栏SidebarView、右侧详情DetailView
8、之后扫了一遍所有的文件,删除了未被使用的FavoritesView和ConversationListView
9、接下来测试具体的功能,从添加模型、发起对话开始,首先在设置中添加模型时,目前的设置界面显示非常局促,不能完整显示具体的设置内容,要求Cursor将其改成分栏布局,即使用NavigationSplitView,并且调整了界面的文字和图标大小等等,但多次调整后依然有部分元素被遮挡,看来还得重新规划一下应用界面的布局,可能NoteWith目前在使用的三栏布局的确是比较好的方案

DevLog:2025年9月12日

1、继续修改备忘录模块,目前已经应用了MarkdownUI,但仍然没有实现我希望的所见即所得的效果,仍然需要点击编辑按钮才能修改内容,修改之后变成了点击备忘录内容区域就能进入编辑模式,在编辑模式下使用TextEditor进行纯文本编辑,在预览模式下显示MarkdownUI渲染的效果,并且支持文本选择
2、接下来尝试用MarkdownUI优化AI回答内容的渲染效果,先用MarkdownUI优化除代码块和表格之外的内容的渲染效果,因为代码块和表格已经有单独的文件在渲染,Cursor通过在UnifiedMarkdownView中添加import MarkdownUI,并将.text组件的渲染从简单的Text替换为Markdown(text),实现了这一需求
3、然后用MarkdownUI渲染了AI回答中的表格,让普通文本和表格渲染效果一致,再将MarkdownUI用到代码块的渲染中,我发现在这个过程中Cursor修改的文件是UnifiedMarkdownView,并不是专门用于渲染代码块的CodeBlockView和MarkdownWithCodeBlocksView,以及专门用于渲染表格的TableView和MarkdownWithTablesView,询问后Cursor表示这些文件目前没有被使用,于是删除并修改了项目文件,移除对这些文件的引用,之后测试了一个新的问题,删除这四个文件的确对AI回答的渲染没有任何影响,现在AI问答中所有的Markdown内容都通过MarkdownUI进行统一渲染
4、真真切切感受到了使用成熟的三方库给应用开发带来的效率提升,之前为了实现对代码块和表格的渲染不知道修改了多少次代码才让这两个模块的显示效果基本可用
5、但现在还有CodeBlockParser、TableParser、MarkdownTableCell 三个文件,不知道是否还在使用,询问Cursor后得到的答复是只有TableParser还在使用,它定义了TableRow结构体,是UnifiedMarkdownView中表格解析的核心数据结构,所以仍然保留了这个文件,另外两个文件已经不再使用,直接删除并修改了项目文件,实测对目前的AI回答内容渲染效果无影响
6、发现在AI对话列表里,有部分对话只显示了标题,没有显示摘要,这和我之前的规划不符,再次明确标题默认是我在这个对话中提出的最后一个问题,下面小字默认是最后一个回答内容的前50字
7、由于近期对应用的修改较为频繁,猜测可能还有部分文件也没有被使用,但依然存在于文件目录中,于是直接让Cursor检查目前还有哪个文件未被使用,并明确“先检查下,不要直接删除”防止像上面第3步那样直接删除多个文件,虽然没有什么实际影响
8、检查发现MarkdownTextView、MarkdownRenderer都已被MarkdownUI取代,还有多余的DataManger,以及前边经过分析认为有用的TableParser,都可以删除,决定让Cursor逐个删除并测试构建,确认没有依赖关系,在将这些文件删除,并且将原本在TableParser中定义的TableRow结构体移到了UnifiedMarkdownView中之后,构建成功,并且AI问答和备忘录的渲染依然正常,今天一共删除了大概9个文件,这下项目更干净了,且功能没受影响
9、AI问答的内容,与消息气泡的边缘的距离有些太近了,需要适当增加一点边距,询问Cursor了解当前的边距设定之后,将用户消息和AI消息的下边距统一由4增加到8,现在看来稍微好些了
10、发现不知道从啥时候开始,在AI对话、备忘录和待办事项三个界面,第二栏和第三栏之间无法通过拖动分割线调整比例了,我记得之前已经将这三个界面的第二栏和第三栏统一用HSplitView,并且设置了最大宽度、最小宽度和理想宽度,检查后发现AIChatSessionView、NotesListView和TodoListView都设置了固定的宽度300,会阻止用户通过拖动分割线调整比例,并且待办事项列表页也设置了最小宽度,也会影响待办事项列表(分组)的宽度
11、在修改过程中,我提出希望Cursor能够保存用户通过拖动调节的宽度值,Cursor创建了新的InterfaceSettings数据模型和ResizableHSplitView组件,前者用于持久化保存宽度设置,后者用于监听用户拖动分割线时的宽度变化,多次修改后默认宽度依然是400,虽然可以通过拖动分割线调整宽度,但调整后的宽度不会被保存,切换到其它界面再切回来,宽度依然是400,后续再修改
12、突然想看看最近Trae多次更新之后水平有没有什么提升,于是复制了一份ChatWith,改名为ChatWith for Mac,让Trae把这个iOS应用改成Mac应用,经历了修改项目文件、Info.plist、ContentView、ConversationListView、ChatWith、MessageViews等等文件,以移除iOS特有、在macOS上不适用的代码,接下来就是漫长的构建失败-查找原因-修改-继续构建失败-清理缓存-继续构建失败的过程,在这一过程中遇到了6次“模型思考次数已达上限”的提示,即使经历了如此漫长的修改,仍然构建失败,没想到Trae的Auto模式还是这么难用,第七次提示模型思考次数已达上限之后终于还是没耐心了
13、由Cursor接手继续修改,指令“这是一个由iOS应用改成的macOS应用,但在修改过程中反复出现构建错误,看一下原因”,Cursor在构建一次之后直接定位了问题所在,于是创建了任务列表来修复错误,只用了几分钟就构建成功,为什么Trae连快速定位问题都做不到呢?
14、而且Trae在修改过程中,还在项目文件夹里创建了很多个扩展名为.o的文件,Cursor表示这是编译过程中的中间产物,包含机器码,但通常应该在DerivedData目录下,而不是在源代码目录,于是让Cursor直接删掉了这些文件
15、然后让Cursor评估是否还需要原本iOS应用的启动画面文件SplashView,macOS应用通常直接显示主界面,不需要启动画面,删除此文件后Cursor同步从项目文件中移除了SplashView的引用
16、测试发现应用可以打开,但在Dock栏没有图标,且打开的应用没有直接出现在所有窗口最前,让Cursor修改之后解决了应用未显示在所有窗口最前的问题,但应用的图标不是macOS应用默认的图标,接下来让Cursor排查目前未被使用的文件,包括了由Trae创建的测试文件TestFile.swift,以及Package.swift(Swift Package Manager文件,但项目使用的Xcode项目,又是一个Trae的迷之操作),果断删掉了这两个文件,然后在Xcode中重新打开项目所在文件夹,图标问题解决了
17、接下来可以测试和完善功能了,首先就是设置界面和AI对话界面弹窗太小的问题,完全看不到其中的内容(可能macOS上不太适合这种弹窗sheet的交互方式吧),Cursor同步修改了对话列表界面的弹窗、AI对话界面的模型选择器、设置界面的模型编辑弹窗、收藏界面的弹窗,但修改效果不佳
18、发现Cursor在最近更新后,修改过程中会标出哪个操作使用了用户的习惯或规则
19、接下来,优先把应用的数据存储方式由UserDefaults改成User Defaults和Core Data混用

DevLog:2025年9月11日

1、继续修改备忘录界面,现在有两行同样的标题、两个更新时间,需要简化一下,只保留最顶部的标题(这一点没能实现),只保留一个更新时间,并且把更新时间和字数统计放在同一行,然后把字数统计和更新时间挪到了备忘录详情界面的底部
2、但备忘录详情界面仍然有些复杂,比如标题显示了两个,标题和编辑按钮之间有一个空白的工具栏,从NoteEditView代码中找到了对应工具栏的几行代码,并Add to Chat,让Cursor删掉这个多余的工具栏,Cursor同步删除了toolbarView的定义,并移除了多余的Divider()分隔线,这下备忘录界面干净多了,但依然会显示两个标题

DevLog:2025年9月10日

1、关于Markdown渲染三方库,Cursor之前建议了SwiftUI-Markdown和MarkdownUI,但追问之后它更建议使用MarkdownUI,原因在于它完全基于SwiftUI构建,与项目架构完美匹配,且渲染性能更好,维护活跃,API简洁,支持表格、代码块、链接等所有常用的Markdown功能,说的这么好,实际用起来如何还得测试一下
2、除了AI问答之外,我还希望能将MarkdownUI用在备忘录模块,并且实现所见即所得的渲染,不再使用预览和编辑双视图,Cursor表示完全可以,并且所见即所得的渲染正是MarkdownUI的优势之一,优势包括:内容变化时自动重新渲染、可以只显示渲染后的效果,无需双视图、渲染流畅、支持所有Markdown语法、可以自定义样式和主题
3、Cursor还给出了三种实现方案,纯预览模式(类似Notion)、混合模式(小区域显示原始Markdown代码)、编辑模式,个人比较倾向于第一种,希望能够解决这段时间一直没能解决的AI对话、备忘录对Markdown语法的渲染问题
4、先修改备忘录模块,这次Cursor创建了一个使用MarkdownUI的备忘录编辑器组件MarkdownEditorView,并且修改了其它关联文件来使用这个组件,移除不再需要的工具栏和预览切换功能,因为MarkdownEditorView已经内置了这些功能,然后通过Swift Package Manager添加了MarkdownUI库,据称已经实现了真正的所见即所得编辑体验
5、测试发现备忘录界面有一行多余的“备忘录编辑器”,另外备忘录的内容显示有问题,当切换到不同备忘录时,内容没有正确更新,然后我还发现在打开某条备忘录,并且在列表中右键删除这条备忘录时,右侧应该显示“选择一个备忘录开始编辑”的界面,而不是仍然能看到已经删除的备忘录,Cursor移除了MarkdownEditView中的if !isEditing的条件判断,确保当外部内容改变时,编辑内容总是会更新,然后移除了NoteEditView工具栏中的“备忘录编辑器”文字(但现在仍然还有多余的修改时间,也需要删掉),并且修改了NotesListView来监听备忘录列表的变化
6、然后优化了备忘录页面的标题显示,备忘录列表顶部固定显示“备忘录”三个字,备忘录详情顶部根据我选中的备忘录标题而变化,未选中任何备忘录时则显示“备忘录”三个字
7、我其实不需要现在的编辑按钮,更倾向于直接点击备忘录内容区域就能编辑,所见即所得,并实时保存修改,类似Notion,明天看看Cursor能否在继续使用MarkdownUI的前提下实现这一功能

DevLog:2025年9月9日

1、继续昨天的修改,昨天为了实现对表格较好的渲染效果,拆分出了UnifiedMarkdownView,用于渲染普通文本,表格和代码块都已有专用的文件来渲染,但UnifiedMarkdownView使用了简单的Text组件,丢失了Markdown渲染效果,还是需要换成NSTextView,以实现良好的Markdown渲染效果、文字选择、右键菜单等功能
2、为了实现除表格和代码块之外的文本内容的渲染效果,Cursor创建了新的文件MarkdownTextView,至此明确了组件的职责,MarkdownTextView专门渲染普通文本,TableView专门渲染表格内容,CodeBlockView专门渲染代码块内容,UnifiedMarkdownView统一协调各个组件
3、接下来又是漫长的添加调试信息、定位问题的过程,在此过程中出现了应用卡死、文本不显示等问题,一直没能实现用NSTextView来渲染AI问答的文本内容,目前还是用的Text,可以正常显示文本、选择并复制文本,但没能搞定用AttributedString来解析Markdown,暂时搁置
4、先修改表格的样式,发现目前的表格第二行显示了一堆分隔符,而非正常的表格内容,而且Cursor给表格增加了最大高度限制和滚动功能,我也用不到,让Cursor修改下,Cursor创建了MarkdownTableCell组件来渲染表格单元格,但导致了应用卡死,在恢复到简单的Text组件后暂时不会卡死了,但表格里还是混合了Markdown语法标记,尤其是加粗标记
5、先保存粗体处理试试看,目前测试过的两个表格,都是粗体字比较常见,没想到只想使用这一个功能,也会导致应用卡死,只能先撤销了这一步修改,接下来准备试试Cursor建议的第三方Markdown库,比如SwiftUI-Markdown或MarkdownUI,如果可以的话,应该可以搞定AI对话中的文本、表格,以及备忘录的Markdown渲染

DevLog:2025年9月8日

1、上周在修改NoteWith时,通过调试信息发现目前AI对话并不是真正的流式输出,而是在完整回答后模拟流式输出,Cursor建议使用真正的流式API,实现增量渲染(只渲染新增部分),并且缓存已渲染的组件,避免重复解析,今天先修改这个问题
2、在修改过程中,遇到了AI回答内容不完整显示(但调试信息里是完整的)、问题只有一行时下方有一行空白、流式输出内容的汉字显示为乱码等问题,最终实现了真正的流式API调用,通过修改AIService,新增streamAIModel方法,实现了流式响应和实时解析数据,AI一开始生成内容就立即显示,用户能更快看到回答开始,使用起来更流畅了,并且测试发现思考过程也可流式输出
3、至于汉字显示为乱码,是因为之前的逐字节处理流式数据,但UTF-8编码的中文字符,一个字符能占用2-4个字节,这就会导致中文字符被截断,从而显示为乱码
4、有意思的是Cursor竟然从我发送的全是乱码的AI回答内容中看出了我真实的问题,并在修改代码后问我“关于您提到的OpenRouter vs Anthropic官方API的对比,这是一个很好的技术选择问题。如果您需要进一步的建议或想要实现特定的API集成,请告诉我!”
5、用百度云千帆的DeepSeek-R1-250528写了一个斜体字Markdown语法正则表达式,试试看能否解决备忘录预览界面斜体字无法正常渲染的问题,测试发现没能解决,斜体字依然无法显示为斜体
6、AI回答内容中的表格一直无法正常渲染,特别像是仅仅把表格中的文字复制出来,根本不像个表格,于是询问Cursor能否用类似CodeBlocksView的形式,创建一个单独的文件来渲染AI回答内容中的表格?Cursor创建表格渲染组件,包含表格解析器TableParser、表格视图TableView、表格渲染视图MarkdownWithTablesView
7、创建新文件之后,经历了多次测试和修改,仍然无法正常渲染,包括看不见我提出的问题,看不见AI回答中的文本内容(基本上除了表格之外,其它的对话内容都看不到,但深度思考内容和参考链接区域没有受影响)等等,多次添加调试信息、反馈调试信息后仍然无果,决定发起一个新的Cursor对话再试试
8、看了一眼Cursor网站的DashBoard,出现了“Analytics are currently degraded and showing incomplete data. We’re working on resolving this issue. You can subscribe to updates here.”这样的提示,看来Cursor终于发现了数据统计功能的问题
9、询问Cursor发现当前AI问答内容全都是在使用新创建的MarkdownWithTablesView来渲染,和我理解的不一样,我希望的是在AI回答中有表格时使用MarkdownWithTablesView来渲染表格,在AI回答中有代码块时,使用MarkdownWithCodeBlocksView来渲染代码块,于是让Cursor创建了一个新的组件UnifiedMarkdownView来统一处理文本内容,并修改MessageView来使用分离的渲染逻辑,这样避免了功能冲突,可以看到AI问答中表格以外的其它内容了
10、但UnifiedMarkdownView对普通文本的渲染使用了简单的Text组件,丢失了Markdown渲染效果,后续还是要换成NSTextView,以实现良好的Markdown渲染效果、文字选择、右键菜单等功能,明天再完善UnifiedMarkdownView

DevLog:2025年9月5日

1、继续测试和优化体验,前两天盘了下各个API平台的余额,发现百度云千帆和硅基流动上还各有五六十块钱,先用硅基流动的API来测试NoteWith的AI对话功能了
2、首先就是在添加模型时,硅基流动官方文档里提到base url是https://api.siliconflow.cn/v1,但我直接填写这个url之后,在测试时仍然提示404错误,去掉后面的v1就好了,可能是因为之前我让Cursor添加了base url自动补全功能,所以现在只需要填写AI服务的根地址就行了
3、然后是在AI对话中切换模型时,选择AI模型的界面,每个模型都显示了模型的名称和“自定义模型”两行文字,我不需要“自定义模型”,我需要在这个页面看到每个模型的备注和模型名称两个字段的信息,Cursor删除了AIModelSelectorView中“硬编码”的“自定义模型”文字,并且完成了修改
4、接下来优化一下流式输出,发现AI回答内容像是在一段一段地输出,并且在AI回答内容输出之前就会有一条白色的区域,然后“AI正在思考中”前面的加载图标也比较大
5、Cursor表示目前的流式输出回答内容的分块是160字符,减少到了50字符,同时将思考过程的分块从80字符减少到了40字符,输出间隔时间也有缩减,至于在AI回答内容输出之前的白色区域,通过修改MessageView,只有当消息内容不为空时才显示消息内容区域,只有消息有内容时才会显示操作按钮(收藏、复制、删除),避免了空消息占位符显示白色背景区域的问题,然后缩小了“AI正在思考中”前面的加载图标
6、流式输出回答内容的分块还是有点大,还可以再缩小一些,另外由于目前AI回答中的文本内容渲染采用了NSTextView,虽然可以看到渲染后的结果,但语法标记所占的位置都显示成了空格,效果不是很好,这样做的原因是之前想要复制部分回答内容
7、尝试继续完善文本的渲染效果,将语法标记完全移除而不是设置为透明,这次竟然真的搞定了!真是万万没想到
8、然后调整下AI对话的标题,之前已经修改了AIChatView,目前它只负责AI对话详情页,也就是AI对话模块的第三栏,这页左上角的标题目前固定显示为“AI对话”,决定将其改为显示当前AI对话的标题,如果我没有打开任何对话,则显示为“AI对话”,如果我打开了某个对话,就显示当前对话的标题
9、发现AI对话内容(无论是提问还是回答)的底部都有一小条空白,Cursor表示这是因为消息容器的边距和内容区域的边距叠加导致的,稍微缩减了一下,目前显示效果还行
10、在测试时我发现调试信息里很早就已经出现了API返回的回答内容,但迟迟不见AI对话界面显示回答内容,猜测可能是API返回回答内容之后,先用MarkdownWithCodeBlocksView完成渲染,再流式输出到AI对话界面,实际上是API返回完整回答(AIService),然后分块流式输出(AIViewModel),再实时渲染(MessageView+MarkdownWithCodeBlocksView)
11、这不是真正的流式API,而是完整回答后模拟流式输出,由于这种方式每次内容更新都会重新渲染整个Markdown内容,可能会在长回答时造成性能开销,导致渲染闪烁(特别是复杂格式),Cursor建议使用真正的流式API,实现增量渲染(只渲染新增部分),并且缓存已渲染的组件,避免重复解析

DevLog:2025年9月3日

1、参考Xcode的建议和Cursor的解释,对项目进行了死代码剥离(Dead Code Stripping),Cursor称这是一个编译优化功能,可以移除未使用的代码和数据,减小最终应用程序的大小,提高应用程序的加载性能,并且这是一个安全的优化
2、继续调整细节,比如将备忘录中的“笔记”替换为“备忘录”,和应用中备忘录模块名字保持一致,搜索界面按钮的顺序调整和文字修改,删除NotesListView也就是备忘录列表中未被使用的搜索功能,等等,让代码更干净一些
3、继续想办法解决从NoteWith还是手机应用时就一直存在的老大难问题:备忘录,询问了Cursor,有没有一些比较好用的Markdown编辑器,可以替换掉目前正在使用的NSTextView,Cursor给我推荐了SwiftUI Markdown、MarkdownUI、AttributedString+Markdown解析、以及MarkdownEditor、RichTextEditor两个第三方开源组件、和WebView+JavaScript方案
4、选择了第一个方案,但Cursor建议将现有的单视图编辑器改为双视图模式,即将编辑和预览分开,在编辑时可以实时更新预览,再具体一些,它推荐内联预览模式,可以同时看到编辑和预览,上面是编辑区域,下面是预览区域,可以展开/收起、可以拖拽调整高度,先试试看
5、修改过程中发现编辑区域已经显示了渲染效果,但预览区域显示的是未渲染的效果,这是因为之前创建的WYSIWYGMarkdownEditor是一个所见即所得编辑器,在编辑时就已经渲染了Markdown,按照Cursor的建议替换成了TextEditor
6、测试发现预览界面依然存在一些Markdown语法标记,可能是因为MarkdownRenderer不够完善,于是让Cursor修改,之后又是漫长的修正MarkdownRenderer的过程,因为Cursor在修改过程中认为之前的MarkdownRender太过复杂,于是删掉、重新创建了一个
7、目前应用内包含了两个Markdown渲染器,一个是AI对话使用的MarkdownWithCodeBlocksView,一个是备忘录使用的MarkdownRenderer