Wrong Spacetime
Life is composed of choices. But not all choices have only "making a choice" as the option.
After completing the MVP of the typst-concealer plugin, I deeply felt the weakness of Neovim's image rendering capability support stemming from its underlying abstraction as a terminal editor. The biggest issue is: reasonable inline formula rendering requires support for variable line height, to accommodate formulas slightly taller than the line height for aesthetically pleasing rendering. However, the terminal emulator's line height model is fixed. Therefore, for some taller formulas, we must make a trade-off between "font consistency with the editor" and "displaying the complete formula". Achieving the latter means scaling the formula to line height dimensions, which causes the human eye to constantly refocus between different font sizes, leading to eye strain over time. Achieving the former inevitably encounters clipping behavior for formulas like . Neither is "perfect".
Thus, I thought, since I have already implemented baseline alignment logic for Typst SVG embedded mathematical formulas on the web (as you can see, the above mathematical formula correctly expands the line height and its baseline essentially aligns with the original text), why not implement this feature in other GUI editors? The basic requirement is: to achieve Obsidian's Typst preview experience without interrupting the daily note-taking workflow.
First, I attempted the same technical path as Obsidian, i.e., using a Tauri backend to bridge the Typst crate for syntax tree analysis and extracting mathematical formula positions, and using CodeMirror 6 on the frontend for aesthetically pleasing formula rendering, where
- The baseline alignment logic I implemented on the web can be replaced with decoration SVG embedding in CodeMirror.
- The fine-grained conceal logic I implemented in math-conceal.nvim (i.e., expanding when the cursor moves over a folded field) can also be directly reused.
Therefore, with these accumulated experiences and coding agents, the first draft reached a usable stage in just one afternoon.
As you can see, this implementation already achieves aesthetically pleasing formula rendering. It is much better than battling with the kitty image protocol for three hundred rounds in Neovim, and it can naturally express variable line height behavior for tall inline formulas.
However, problems then emerged: from a "functionally usable first draft" to a "truly reusable editor product in a production environment", there exist more gaps than imagined:
- Typst's multi-file editing and completion experience heavily depend on LSP.
- As a heavy Neovim user, my workflow is strongly bound to a series of LSPs and formatters, as well as some small but commonly used tools based on Tree-sitter (such as automatically switching Chinese/English input methods in mathematical regions, using
textobjecttextobjectto edit mathematical formula nodes, etc.). When these tools are not supported, I feel my originally intuitive workflow is forcibly interrupted. - Editors built on web frontend technology exhibit noticeable lag in large file projects.
Of course, initially I still hoped these problems could be properly resolved, but as time progressed, I gradually realized that building extensive plugin and customization logic on such a completely from-scratch architecture is not a very smart thing to do: I would be reinventing the wheel—after implementing auto-completion comes multi-LSP server support, after LSP comes TextMate highlighting, plus Vim emulator integration. After doing all these, they still need to be moved to a unified CodeMirror plugin compatibility layer, ensuring they don't conflict when actually working. While each task can be solved, this prolonged process of reimplementing capabilities I already have (and worse, not even reaching a usable level) quickly exhausted my patience.
Later I also tried other different solutions, such as writing an Emacs plugin, deeply modifying VSCodium's source code to implement variable line height support. Each of these efforts had its merits, but always had shortcomings. Most importantly, during the practice with these editors, I found myself falling into a standard loop:
- Utilizing the GUI editor's specific mechanisms, quickly implementing variable line height mechanisms that Neovim finds difficult to achieve, along with corresponding preview mechanisms.
- After the formula preview mechanism stabilizes, begin seeking to replicate Neovim's daily workflow.
The former usually succeeds because GUI editors inherently have many typographical advantages over Neovim; the latter usually fails because Neovim has various editing workflows bound to its terminal design abstraction. While modern GUIs could essentially inherit these, they are typically not the primary implementation goal of these GUI editors.
Clearly, this is not a simple "selection mistake", but a misjudgment of requirements.
When I tried to replace Neovim under the TUI framework with a GUI editor, what I was actually doing was: for a rendering improvement that only accounts for of the overall experience, leveraging the other of already mature shortcuts, configuration scripts, and workflows. The problem is not that the is unattractive, but that it is fundamentally insufficient to constitute a reason for a full migration. Yet once a choice is made, one naturally directs of effort toward that , as if making it sufficiently beautiful would automatically make the choice correct. But when the dust settles, what truly determines whether a tool is usable remains that that was never replenished. Thus, what is ultimately obtained is often not a new production tool, but merely a finely crafted toy.
Rather than hastily making a choice and immediately putting it into practice, perhaps more important is to ask why one finds oneself in a "choice" environment at this moment.
Looking back, in my actual workflow, "tall formulas being clipped in fixed line height" was never a truly troubling problem. Such formulas are inherently infrequent; even when they appear, since the formulas are input by me personally, I can completely "complete" them from context and memory. The value of the preview plugin is merely reducing the cost of this pattern matching, not replacing work that was originally impossible.
Then, since essentially there is no demand, why did I spend an extremely long time implementing these solutions, traversing three schemes before finally realizing this obvious truth?
Actually, what truly made me invest so much time is this fact: a locally more beautiful, more advanced prototype too easily makes one mistakenly believe they have grasped the real problem. Yet the success of a prototype only proves that a local mechanism can work; it never equates to this system being able to integrate into my existing life. It is precisely here that decision and execution become misaligned: when making the decision, I saw the 10% gain; when actually starting to work, I paid the cost of rebuilding the entire workflow.
When a thought appears in the mind and tempts forward with many benefits, true wisdom may not be to directly move forward toward a certain fork in the road, but to step back: step back to examine the cost behind the temptation, examine one's "real" situation, examine those obvious truths that are used daily yet unseen.
People often say "stepping back is actually moving forward", indeed it is so: choices lead one left or right, thinking that entering a certain path must symbolize progress. But sometimes, stepping back to examine often finds a third direction beyond left and right. This direction does not lead to any foreseeable destination, yet because it holds unprecedented clarity and awareness, it leads to a higher and farther future.
Loading comments...
Please login with GitHub to post a comment.