用SDL3重新实现Emacs 的图形窗口系统

非常务实的想法,Emacs 过去几十年的持续发展,拥有非常宝贵的生态体系,不应该与过去隔绝。

继续在本帖下更新作者的最新想法:

The Emacs Widget Prototype《Emacs 组件原型》

I had to fork rune in order to make it usable for my project. I provide some reflections on some of the ideas that I would like nail in the next stage of the project.

为了使它对我的项目可用,我不得不 fork rune 。我提供了一些关于我在项目下一阶段想要解决的一些想法的反思。

Brief recap 简要回顾

I started a series of articles on the limitations of the current Emacs binary. I wrote a rather disparaging post about the code quality of the code, as a consequence of a failed attempt to find a way to make the project upstream-merge-able by incremental changes. The current plan of action is to produce a demo, a stripped down version of Emacs, that is plainly an alternative GUI, a slightly modified Elisp interpreter with more internals and a direct form of programming graphical elements in it.

我开始了一系列关于当前 Emacs 二进制文件限制的文章。由于尝试寻找通过增量更改使项目可以上游合并的途径失败,我写了一篇相当贬低代码质量的帖子。目前的行动计划是制作一个演示,一个精简版的 Emacs,它是一个替代 GUI,一个稍作修改的 Elisp 解释器,具有更多内部结构和直接编程图形元素的方式。

So let’s go into more detail.

让我们更详细地了解一下。

What Emacs is, to me, is a graphical programming environment. It is an IDE of sorts, but it is not only that. It is a place you could play tetris, not very efficiently, mind you, but still. It is a place that allows one to transform plain text markup such as Org, into a comfortable writing environment with Headings marked with bigger numbers, prose alignment functions, a comfortable middle column to write into, that doesn’t require hard newlines to make the text easily readable. The amount of technological effort needed to make this program display a PDF inside the buffer is not huge, so it does that too. It has a decent file manager built in, called dired. I don’t like it much, personally, but I don’t mind using it either, especially given that it offers some insights that other file managers prefer to hide by default.

对我而言,Emacs 是一个图形化编程环境。它算是一种集成开发环境,但不止于此。它是一个可以玩俄罗斯方块的地方——虽然效率不高,但确实可以。它是一个能让用户将纯文本标记(如 Org)转化为舒适写作环境的地方,通过用更大的数字标记标题、文本对齐功能、一个舒适的中间列供书写,且无需硬换行就能让文本易于阅读。让这个程序在缓冲区中显示 PDF 所需的科技工作量并不大,所以它也能做到这一点。它内置了一个不错的文件管理器,名为 dired 。我个人不太喜欢它,但也不介意使用,尤其是考虑到它提供了一些其他文件管理器默认隐藏的见解。

Emacs owes its flexibility to the incredible amount of Emacs Lisp that is written. The quality of that Emacs lisp differs greatly, but the beauty of it, is that since it wasn’t a corporate mandated language, where any inefficiency was deemed a flaw to be removed, but rather as a form of artistic expression. The usage of cl-loop is not an inconsistency, but a preference. This is like one’s handwriting.

Emacs 的灵活性归功于大量 Emacs Lisp 代码的编写。这些 Emacs Lisp 代码的质量差异很大,但它的美妙之处在于,它并非企业强制的语言,任何低效都被视为需要移除的缺陷,而是一种艺术表达形式。使用 cl-loop 并非不一致,而是一种偏好。这就像一个人的笔迹。

Unfortunately, Elisp is far too forgiving, and some of the elements that were adopted with the intention of providing better performance are now the very reason why Emacs is sluggish.

不幸的是,Elisp 过于宽容,一些原本为了提供更好性能而被采用的元素,如今却成了 Emacs 迟缓的真正原因。

Emacs is not slow Emacs 并不慢

Emacs is not slow. It has bad architecture.

Emacs 并不慢。它的架构有问题。

The Emacs lisp interpreter is capable of producing extremely well-behaved programs. It owes that to its simplicity. Because of its simplicity, e.g. things like dynamic scoping, lack of namespaces, conventions over mechanisms, and a few other things can work. Simply put, you never reach the level of complexity such that imperfect solutions to programming management problems become problems.

Emacs lisp 解释器能够生成非常优秀的程序。这得益于它的简洁性。因为它的简洁性,例如动态作用域、缺乏命名空间、约定优于机制以及其他一些特性都能正常工作。简单来说,你永远不会达到一个复杂的程度,以至于编程管理问题的不完美解决方案会变成问题。

Now the trouble is that most of the time, the complexity debate comes down to less is more and stops there. The suckless people tend to say “JSON good, XML bad; complexity”. That is a rather superficial critique, because it ignores the fact that complexity is a price paid for functionality.

现在的问题是,大多数时候,关于复杂性的争论往往归结为少即是多,然后就此止步。Suckless 的人倾向于说“JSON 好,XML 坏;复杂性”。这是一种相当肤浅的批评,因为它忽略了复杂性是功能付出的代价这一事实。

Saying something is simple is like saying something is cheap. It means that the amount of work that went into that something had a very crude model of the world, and a very plain model of interaction. Emacs lived in a different world; one in which computational power was quite constrained, and if you needed to have programs talk to each other, that communication was largely unidirectional, and pipe-lined.

说某件事简单就像说某件事便宜。这意味着为这件事投入的工作量对世界的理解非常粗糙,交互模型也非常简单。Emacs 存在于一个不同的世界;一个计算能力相当受限的世界,如果你需要让程序相互通信,这种通信基本上是单向的,并且通过管道传输。

Now the world is different. Unix is not the dominant way of designing operating systems, most programmers can’t write a bash script to save their life, and the main way of connecting to the internet is through an HTML + CSS + JavaScript execution environment, that has the complexity of an operating system. To account for the changes in how the world operates today, Emacs would have needed to accumulate a kind of complexity.

现在世界已经不同了。Unix 不再是设计操作系统的主导方式,大多数程序员连救命的 bash 脚本都写不了,而连接互联网的主要方式是通过一个具有操作系统复杂度的 HTML + CSS + JavaScript 执行环境。为了适应当今世界运作方式的变化,Emacs 需要积累某种程度的复杂性。

The complexity accumulated naturally. It responded to small changes with small changes. And this led to some problems that are now harder to solve than they need to be.

复杂性自然而然地累积起来。它以小变应小变。而这导致了现在有些问题比原本更难解决。

In the previous post it sounded like I was disparaging to a project that I very much started this one because of. The Emacs Reader owes most of its complexity to work necessary to circumvent technical considerations of the olden times. I started the work on this editor specifically to provide more maintainable methods of achieving the same functionality. When I say that this should have been a weekend project, I mean that the complexity that has gone into the project is a problem.

在之前的文章中,我听起来好像在贬低一个我非常想开始的项目。Emacs Reader 的复杂性主要源于为了绕过旧时代的技术考虑而进行的工作。我专门开始这项编辑器的工作,是为了提供更可维护的方法来实现相同的功能。当我说这应该是一个周末项目时,我的意思是这个项目中涉及的复杂性是一个问题。

Status 状态

I now have a fork of the Rune project. It was something I wanted to look at anyway, and has the potential to be useful long term. As it stands, it’s going in a different direction to what I need. I will get into more details shortly.

我现在有一个 Rune 项目的分支。这是我本来就想看的,并且有长期使用的潜力。但就目前而言,它的发展方向与我所需要的不同。我很快会详细说明。

I have a graphical editor, based on Vello and winit, which provide a sufficient level of flexibility and performance. This is not necessarily what the end product would be implemented in, just a convenient starting point.

我有一个基于 Vello 和 winit 的图形编辑器,它提供了足够的灵活性和性能。这不一定就是最终产品的实现方式,只是一个方便的起点。

At the end of the weekend, I plan to have a text editor with some ability to read elisp configuration. Simply put, this is to avoid technical debt accumulated by working on two separate projects and bringing the two back together.

周末结束时,我计划开发一个能够读取 elisp 配置的文本编辑器。简单来说,这是为了避免因同时处理两个独立项目而积累的技术债务,并将这两个项目合并在一起。

Plan 计划

I over-estimated the amount of free time that I would have to work on this. The setbacks were not at all unforeseen, though their frequency was a bit of a surprise. I have a cadence which allows some progress to be made, so I will subscribe to the mantra of “slow and steady wins the race” and hope that many of the people that have kindly offered to help can be given something to work on soon.

我高估了自己可以用来完成这项工作的空闲时间。虽然这些挫折并非完全出乎意料,但它们的频率确实有些出乎意料。我有一个节奏,允许取得一些进展,因此我将信奉“慢而稳胜”的箴言,并希望那些善意提供帮助的人们很快就能得到一些可以着手的工作。

Experiments 实验

I want to try different variations on the theme.

我想尝试主题的不同变体。

Truth be told, the whole reason for using Elisp at all is to have native day-one compatibility with Emacs packages. That means that a bug-compatible Elisp interpreter is a good idea. But that also constitutes a form of golden handcuffs. We will never grow beyond what was already done, and for compatibility’s sake, limit the architectural improvements.

说实话,使用 Elisp 的全部原因是为了与 Emacs 包实现原生的一键兼容。这意味着一个与 Bug 兼容的 Elisp 解释器是个好主意。但这也会构成一种金手铐。我们将永远无法超越已经完成的工作,并且出于兼容性的考虑,会限制架构上的改进。

My current understanding is that the killer apps, such as magit and gnus and potentially org would have to be rewritten anyway to take advantage of the new features. Smaller packages are easier to port. So a bug-compatible Elisp interpreter is not necessary for the project to succeed, they are a trap, in fact.

我目前的理解是,像 magitgnus 以及可能的 org 这样的杀手级应用无论如何都需要重写以利用新特性。小型的包更容易移植。所以一个与 Bug 兼容的 Elisp 解释器并不是项目成功所必需的,事实上它们是一个陷阱。

We can go with a flavour of Elisp. It could be that a different environment, such as the new editor, provides some differences that can be taken into account with a macro. It’s possible to write a package that works both there and in Emacs, and the work comes down to using some macros for compatibility. This is a compromise that I think should be taken as a baseline, because it keeps things relatively simple.

我们可以选择一种 Elisp 方言。也许不同的环境,比如新的编辑器,会提供一些可以通过宏来考虑的差异。可以编写一个在那些地方和 Emacs 中都能工作的包,而工作内容归结为使用一些宏来实现兼容。我认为这是一个应该被视为基线的折衷方案,因为它保持了相对的简单性。

Another, thing to try is Scheme. Because Scheme and Guile are much more wide spread than Emacs Lisp, and have certain advantages in general, it is a good idea to consider building a brand new editor that takes a larger departure from the status quo.

再试一下 Scheme。因为 Scheme 和 Guile 比 Emacs Lisp 更广泛使用,并且在总体上有一定优势,所以考虑构建一个全新且与现状有较大差异的编辑器是个好主意。

This can be a blessing for people who daily drive Gnu Guix, this should be a blessing for the whole community, as the consensus is that Emacs lisp, while being vastly superior to e.g. Lua and JavaScript, is still not the best Lisp. There is already a project for an editor that uses Common Lisp, called Lem. For symmetry, I believe that my project could experiment with a different branch of the lisp family.

这对每天使用 Gnu Guix 的人来说是个福音,对整个社区来说也应该是福音,因为共识是 Emacs Lisp 虽然远优于 Lua 和 JavaScript,但仍然不是最好的 Lisp。已经有一个使用 Common Lisp 的编辑器项目,叫做 Lem。为了保持对称性,我认为我的项目可以尝试 Lisp 家族的不同分支。

Another thing I want to try, is to break away from the standard architecture entirely. Having played around with ACME for a bit, I can probably borrow some more ideas from the Unix-style of interaction. A protocol and API-driven development is something that I find much more appealing.

我还想尝试彻底摆脱标准架构。稍微玩了玩 ACME 后,我可能会从 Unix 风格的交互中借鉴更多想法。基于协议和 API 的开发让我觉得更有吸引力。

If this approach works, the language for orchestration becomes irrelevant. You could have modules written in Rust, in C, in Guile, in Common Lisp, and in Emacs lisp. How can this be possible? Think about BSPWM.

如果这种方法奏效,那么用于协调的语言就变得无关紧要了。你可以用 Rust、C、Guile、Common Lisp 和 Emacs Lisp 编写模块。这是如何可能的?想想 BSPWM。

The idea there would be that you have a process-isolation type system, resources, and implementations for components in a variety of programming languages. Then you can have competition for the “glue” language. But that in and of itself is a program. This way, you can have evolution where entire components simply go out of time-related scope. You don’t create a reader plugin, that has to be maintained, you just use muPDF, and the programs of origin simply implement the protocol.

那里的想法是,你有一个进程隔离型系统、资源和多种编程语言组件的实现。然后你可以有关于"胶水"语言的竞争。但本身这就是一个程序。这样,你可以实现进化,整个组件可以简单地超出时间范围。你不需要创建一个需要维护的阅读器插件,你只需使用 muPDF,原始程序只需实现协议。

This is a bit more ambitious, but things like that are neither unheard of (think about suckless utilities), nor unsuccessful. How this would work in a post-Wayland world remains to be seen, but I have a feeling that at least trying this approach should be useful. I am not wasting anyone else’s work, as the only work that went into this project is mine. Later on, when the project is already on solid footing (if such a time ever comes), this can be changed.

这稍微有些雄心勃勃,但类似的事情既不鲜见(想想 suckless 工具),也不失败。这种做法在一个 Wayland 世界之后会如何运作还有待观察,但我感觉至少尝试这种方法应该是有用的。我没有浪费任何人的工作,因为这个项目中唯一投入的工作就是我的。后来,当项目已经稳固(如果这样的时刻真的到来)时,这可以改变。

Truth be told, there’s also the question of the implementation language. Contrary to the fact that the prototype is written in Rust, it being the language of choice is uncertain.

说实话,还有实现语言的问题。尽管原型是用 Rust 编写的,但选择它作为首选语言并不确定。

Rune showed that Rust does not give us a magic bullet w.r.t. abstractions that would let us be faster than C. Some functions under #[defun] have to contain unsafe blocks, and what happens with the root-ing of the objects is a subject for debate. I could spend time and make safe wrappers for those behaviours, and that would be essentially wasted time.

Rune 表明,在抽象方面,Rust 并没有给我们提供一种神奇的解决方案,让我们比 C 更快。在 #[defun] 下的某些函数必须包含不安全代码块,而对象的生命周期管理问题则是一个争论的焦点。我可以花时间去为这些行为制作安全的包装器,但这基本上是浪费时间。

The second problem is that the facilities for compile-time code generation in Rust are not sufficient to greatly simplify code generation. Rust is not designed with this form of flexibility in mind, and doesn’t like to bend that way.

第二个问题是,Rust 在编译时代码生成方面的设施不足以极大地简化代码生成。Rust 并不是以这种形式的灵活性为设计目标,也不喜欢以这种方式弯曲。

Thirdly, Rust is a project that has a community that is rather hostile to the ideals of the FSF, the GNU project and Emacs. The standard practices in Rust would be a problem. The people already involved in the project find Rust to be a boring language, and the whole point of going with it rather than C, is to precisely attract more attention.

第三,Rust 是一个拥有一个对 FSF、GNU 项目和 Emacs 的理想相当敌对的社区的项目。Rust 的标准实践会成为一个问题。已经参与该项目的人认为 Rust 是一种无聊的语言,而选择 Rust 而不是 C 的整个目的,恰恰是为了吸引更多关注。

This leaves the door open to trying other languages. I personally would not mind trying out Zig in this regard, as it has robust compile-time programming support. It lacks the graphical libraries that Rust has, as it is a smaller community of programmers, but makes up for it, by being ABI-compatible with C. And this could be the big break. 这为尝试其他语言打开了大门。我个人在这方面不介意尝试 Zig,因为它具有强大的编译时编程支持。虽然它不像 Rust 那样拥有图形库,因为它的程序员社区较小,但它通过与 C 语言 ABI 兼容来弥补了这一点。而这可能是关键突破。

C is a contender that has the small disadvantage of requiring more effort on my end to make the code make sense. Allocations are inevitable, and the unsafe in Rust makes almost every defun a potential source of undefined behaviour. As such, a better Emacs, with none of the technical debt of GNU Emacs would work just as well. Plus it could be C with the modern features, such as designated initialisers, the booleans, and defer.

C 是一个竞争者,唯一的缺点是它需要我在代码上付出更多努力才能使其有意义。分配是不可避免的,而 Rust 中的 unsafe 会让几乎每个 defun 成为未定义行为的潜在来源。因此,一个更好的 Emacs,没有任何 GNU Emacs 的技术债务,效果会同样好。而且它可以是带有现代特性的 C,例如指定初始化器、布尔值和 defer。

Call to Action 行动号召

At the moment, the best that you can do, is participate in the discussions. The dedicated telegram channel is not the best way to do that, at the moment, given that it is not very active. I plan to create a dedicated site, with a proper domain, forum and hosting to discuss these things.

目前,你能做的最好的事情就是参与讨论。鉴于当前这个专门的 Telegram 频道并不活跃,它并不是进行讨论的最佳方式。我计划创建一个专门的网站,拥有正式的域名、论坛和托管服务,来讨论这些事情。

Next week, I plan to finalise the prototype and create a small recording to be uploaded to Peer and You tubes, to get some feedback.

下周,我计划完成原型并制作一个简短的录制视频上传到 Peer 和 YouTube,以获取一些反馈。

I want to get things rolling slowly, and to keep the door open to insightful input. Truth be told, I have a bit of a thicker skin than in June, so perhaps some limited discussions on some social media are warranted. I may not be allowed to participate in the Emacs reddit, but I no longer think that taking the discussion there is a strict violation of my wishes. I will do my best to chase up any comments, but keep in mind, I do have a limited number of hours.

我想慢慢来,并保持开放以接受有见地的意见。说实话,我现在比六月份更有耐心一些,所以或许在一些社交媒体上有限度地讨论是合理的。我可能不被允许参与 Emacs 的 reddit,但我不再认为在那里进行讨论是严格违反我的意愿的。我会尽力跟进任何评论,但请记住,我的时间有限。

Stay tuned. 保持关注。

1 个赞

是否想得有些太多了……吐槽的大部分感觉都不是和窗口系统问题相关的,想一下子解决各种历史遗留问题可不现实。

我觉得其实只要把 PGTK 的工作换成一个更简单同时保持跨平台的 GUI 库重新做一遍就很不错了,Emacs 本身的界面好像也没有用到很多 GTK 的 widget。这个目标显然是可行的因为 PGTK 已经做过一次了。

1 个赞

:grinning_face_with_smiling_eyes: 很正常, 每个想改emacs的源码的人, 看源码看着看着就想大规模重构了

1 个赞