[{"data":1,"prerenderedAt":563},["ShallowReactive",2],{"seite-\u002Fopen-source\u002Feditor-suche\u002F":3},{"id":4,"title":5,"body":6,"description":554,"extension":555,"meta":556,"navigation":557,"path":558,"robots":559,"seo":560,"stem":561,"__hash__":562},"seiten_de\u002Fopen-source\u002Feditor-suche.md","Sieben Monate auf der Suche nach einem Editor",{"type":7,"value":8,"toc":544},"minimark",[9,13,17,20,25,28,31,35,38,58,72,76,79,87,90,94,97,297,304,308,314,321,332,336,341,352,358,487,494,497,504,507,511,514,518,521,532,540],[10,11,5],"h1",{"id":12},"sieben-monate-auf-der-suche-nach-einem-editor",[14,15,16],"p",{},"VS Code war mein erster und einziger Editor. Doch die Leistung störte mich:\nmanchmal verbraucht er unheimlich viel Prozessor und Arbeitsspeicher. Also habe\nich angefangen, nach etwas Schnellerem zu suchen.",[14,18,19],{},"Meine Anforderungen waren überschaubar: Vorschau für PDF und Bilder, ein\nTerminal, und Git im Editor.",[21,22,24],"h2",{"id":23},"terminal-editoren-sind-schnell-aber-blind","Terminal-Editoren sind schnell, aber blind",[14,26,27],{},"Der erste Weg führte in den Terminal. Dort ist die Geschwindigkeit kein\nProblem. Die Vorschau schon: kein Bild, kein PDF, kein gerendertes Markdown.",[14,29,30],{},"Also habe ich versucht, es nachzurüsten. Bei Fresh sind die Plugins dafür zu\neingeschränkt. Bei LazyVim funktioniert es, aber nicht überall. Nicht jedes\nTerminal spielt mit, und stabil war es auch nicht: bei Bildvorschauen im\nExplorer stürzte LazyVim ab. Über allem stand die Ahnung, dass ich irgendwann\ndoch an eine Decke stosse, die im Terminal eingebaut ist.",[21,32,34],{"id":33},"die-hülle-tauschen-statt-das-plugin-flicken","Die Hülle tauschen statt das Plugin flicken",[14,36,37],{},"Daraus wurde der erste eigene Ansatz, und er kehrt die Aufgabe um. Wenn die\nVorschau nicht in den Terminal passt, dann muss der Terminal-Editor eben in\nein Fenster.",[14,39,40,41,45,46,49,50,53,54,57],{},"Zwei Versuche gingen in diese Richtung. ",[42,43,44],"code",{},"neoview"," bettet Neovim über ",[42,47,48],{},"nvim-rs","\nin eine Oberfläche aus gpui ein, dem Framework, mit dem auch Zed gebaut ist.\nDie Oberfläche redet dabei über msgpack-rpc mit Neovim. ",[42,51,52],{},"freshview"," macht\ndasselbe mit dem Editor Fresh, nur enger: Fresh läuft als Bibliothek im selben\nProzess, egui liefert das Fenster, ",[42,55,56],{},"egui_ratatui"," übersetzt dazwischen, und\nmupdf zeichnet PDF und Bilder in schwebende Fenster daneben.",[14,59,60,61,64,65,68,69,71],{},"Die nächsten Anläufe, ",[42,62,63],{},"flexed"," und ",[42,66,67],{},"editor-framework",", sind keine Wrapper\nmehr, sondern Gerüste auf gpui, in denen nichts Kern ist und alles Plugin.\nBei ",[42,70,67],{}," sind die Plugins in Lua und lassen sich ohne Neubau\nnachladen.",[21,73,75],{"id":74},"warum-rust-wegfiel","Warum Rust wegfiel",[14,77,78],{},"Zed ist ein guter Editor, aber ohne PDF-Vorschau. Und Zed ist in Rust\ngeschrieben.",[14,80,81,82,64,84,86],{},"Rust war mir zu langsam im Bauen. ",[42,83,44],{},[42,85,52],{}," hatten ihre\nSchwierigkeiten, träge Darstellung hier, ein Absturz beim Schliessen der\nPDF-Vorschau dort. Das hätte man vielleicht in den Griff bekommen, vielleicht\nauch nicht. Entschieden hat etwas anderes: mit diesen Übersetzungszeiten kam\nich nicht schnell genug voran. Und gpui ist Rust, also fiel es mit.",[14,88,89],{},"Gesucht war eine andere schnelle Sprache, mit der sich Zed Konkurrenz machen\nlässt. Go wirkte verstaubt, V zu wenig bekannt, und Zig stand gerade im\nDurchbruch als Konkurrent zu Rust. Also Zig, und dort baut es sich für mich\nangenehm schneller.",[21,91,93],{"id":92},"elf-anläufe-acht-oberflächen","Elf Anläufe, acht Oberflächen",[14,95,96],{},"Jede Zeile ist ein eigenes Repo, in der Reihenfolge, in der sie entstanden\nsind. Manche haben einen Tag gelebt, manche eine Woche. Alle elf liegen in\nfünf Wochen zwischen Anfang März und Anfang April 2026.",[98,99,100,122],"table",{},[101,102,103],"thead",{},[104,105,106,110,113,116,119],"tr",{},[107,108,109],"th",{},"Begonnen",[107,111,112],{},"Anlauf",[107,114,115],{},"Sprache",[107,117,118],{},"Oberfläche",[107,120,121],{},"Abbruchgrund",[123,124,125,142,155,168,182,197,214,231,248,265,281],"tbody",{},[104,126,127,131,133,136,139],{},[128,129,130],"td",{},"2. März",[128,132,44],{},[128,134,135],{},"Rust",[128,137,138],{},"gpui",[128,140,141],{},"Buildzeiten",[104,143,144,146,148,150,153],{},[128,145,130],{},[128,147,52],{},[128,149,135],{},[128,151,152],{},"egui, egui_ratatui",[128,154,141],{},[104,156,157,160,162,164,166],{},[128,158,159],{},"8. März",[128,161,63],{},[128,163,135],{},[128,165,138],{},[128,167,141],{},[104,169,170,173,175,177,180],{},[128,171,172],{},"9. März",[128,174,67],{},[128,176,135],{},[128,178,179],{},"gpui, mlua",[128,181,141],{},[104,183,184,187,190,192,195],{},[128,185,186],{},"14. März",[128,188,189],{},"slint-rust-editor",[128,191,135],{},[128,193,194],{},"Slint",[128,196,141],{},[104,198,199,202,205,208,211],{},[128,200,201],{},"15. März",[128,203,204],{},"mojo-nuklear-editor",[128,206,207],{},"Mojo, C-Brücke",[128,209,210],{},"Nuklear",[128,212,213],{},"Mojo ungeeignet, um Editoren damit zu schreiben",[104,215,216,219,222,225,228],{},[128,217,218],{},"17. März",[128,220,221],{},"slint-editor",[128,223,224],{},"Mojo",[128,226,227],{},"Slint über Python",[128,229,230],{},"Slint nur über Python erreichbar",[104,232,233,236,239,242,245],{},[128,234,235],{},"22. März",[128,237,238],{},"v-gui-editor",[128,240,241],{},"V",[128,243,244],{},"GUI-Framework von V",[128,246,247],{},"Scrollen brach nach Einbau von Explorer und Tabs",[104,249,250,253,256,259,262],{},[128,251,252],{},"25. März",[128,254,255],{},"zed-clone",[128,257,258],{},"Zig",[128,260,261],{},"dvui",[128,263,264],{},"Absturz beim Scrollen, grosse Dateien langsam",[104,266,267,270,273,275,278],{},[128,268,269],{},"26. März",[128,271,272],{},"sokol-nanovg-zig-editor",[128,274,258],{},[128,276,277],{},"sokol, NanoVG",[128,279,280],{},"Schrift nach Umbau auf Vulkan weg, Game-Loop von sokol kostete CPU",[104,282,283,286,289,291,294],{},[128,284,285],{},"2. April",[128,287,288],{},"qt-ziged",[128,290,258],{},[128,292,293],{},"Qt 6 über libqt6zig",[128,295,296],{},"Blieb technische Demonstration",[14,298,299,300,303],{},"Am 3. April begann ",[42,301,302],{},"zid",". Seither gab es keinen neuen Anlauf mehr.",[21,305,307],{"id":306},"was-daraus-wurde","Was daraus wurde",[14,309,310,311,313],{},"Der Editor heisst ",[42,312,302],{}," und ist in Zig geschrieben. Er zeichnet über wgpu,\nim Renderer auf das Vulkan-Backend festgelegt. Das Layout macht Clay. Die\nTextdarstellung ist eigen: Glyphen-Atlas und GPU-Renderer über FreeType.",[14,315,316,317,320],{},"Der Editor selbst ist eigen: Eingabe, Bearbeitungsbefehle, Suche,\nZeilenumbruch, Zeilennummern, Tastenbelegung. Darunter liegt Fremdes, und\nzwar bewusst. Die Textspeicherung übernimmt ",[42,318,319],{},"flow-core",", die Kernbibliothek\ndes Editors Flow Control, mit Puffer, Cursor- und Auswahltypen. Die\nSyntaxhervorhebung kommt aus demselben Haus über tree-sitter. Das Terminal\nist die Emulation von Ghostty, Markdown rendert zigdown, PDF zeichnet mupdf.",[14,322,323,324,64,326,328,329,331],{},"Das ist ein anderer Schnitt als bei ",[42,325,44],{},[42,327,52],{},". Dort war der\nganze Editor fremd und nur die Hülle eigen. Bei ",[42,330,302],{}," ist es umgekehrt: der\nEditor ist eigen, fremd sind die Bausteine darunter, die nichts mit dem\nEditieren zu tun haben.",[21,333,335],{"id":334},"regeln-gehören-in-den-code-nicht-in-den-prompt","Regeln gehören in den Code, nicht in den Prompt",[14,337,338,340],{},[42,339,302],{}," hat einen eingebauten Agenten, der gegen ein lokales Sprachmodell\narbeitet, llama-server mit Qwen3-4B. Ein Agent im Editor braucht Werkzeuge,\nund Werkzeuge brauchen Grenzen. Der naheliegende Weg ist, die Grenzen in den\nSystemprompt zu schreiben. Bei einem Modell dieser Grösse ist eine\nPrompt-Zeile aber nur eine Bitte, und sie kostet bei jeder Anfrage Platz in\neinem Kontext von 8192 Tokens. Deshalb stehen die Grenzen im Code. Dort\nmüssen sie allerdings lückenlos sein.",[14,342,343,344,347,348,351],{},"Ein Beispiel. Wer eine bestehende Datei überschreiben will, bekommt einen\nBestätigungsdialog. Das Modell hat ihn beim ersten Versuch umgangen: statt\n",[42,345,346],{},"write_file"," schickte es ein ",[42,349,350],{},"replace_text",", dessen Suchtext die ganze Datei\nwar. Formal keine Überschreibung, praktisch genau das.",[14,353,354,355,357],{},"Seither zählt auch ",[42,356,350],{}," als Überschreiben, sobald es die halbe\nDatei oder mehr ersetzt:",[359,360,365],"pre",{"className":361,"code":362,"language":363,"meta":364,"style":364},"language-zig shiki shiki-themes github-light github-dark","\u002F\u002F\u002F replace_text mit `old` = (fast) ganzer Datei ist ein verkapptes Überschreiben und\n\u002F\u002F\u002F braucht dieselbe Bestätigung wie write_file auf eine bestehende Datei.\npub fn replaceCountsAsRewrite(file_len: usize, old_len: usize) bool {\n    if (file_len == 0) return false;\n    return old_len * 2 >= file_len;\n}\n","zig","",[42,366,367,376,382,429,458,481],{"__ignoreMap":364},[368,369,372],"span",{"class":370,"line":371},"line",1,[368,373,375],{"class":374},"sJ8bj","\u002F\u002F\u002F replace_text mit `old` = (fast) ganzer Datei ist ein verkapptes Überschreiben und\n",[368,377,379],{"class":370,"line":378},2,[368,380,381],{"class":374},"\u002F\u002F\u002F braucht dieselbe Bestätigung wie write_file auf eine bestehende Datei.\n",[368,383,385,389,392,396,400,404,407,410,413,416,418,420,423,426],{"class":370,"line":384},3,[368,386,388],{"class":387},"szBVR","pub",[368,390,391],{"class":387}," fn",[368,393,395],{"class":394},"sScJk"," replaceCountsAsRewrite",[368,397,399],{"class":398},"sVt8B","(",[368,401,403],{"class":402},"s4XuR","file_len",[368,405,406],{"class":398},": ",[368,408,409],{"class":387},"usize",[368,411,412],{"class":398},", ",[368,414,415],{"class":402},"old_len",[368,417,406],{"class":398},[368,419,409],{"class":387},[368,421,422],{"class":398},") ",[368,424,425],{"class":387},"bool",[368,427,428],{"class":398}," {\n",[368,430,432,435,438,440,443,447,449,452,455],{"class":370,"line":431},4,[368,433,434],{"class":387},"    if",[368,436,437],{"class":398}," (",[368,439,403],{"class":402},[368,441,442],{"class":387}," ==",[368,444,446],{"class":445},"sj4cs"," 0",[368,448,422],{"class":398},[368,450,451],{"class":387},"return",[368,453,454],{"class":387}," false",[368,456,457],{"class":398},";\n",[368,459,461,464,467,470,473,476,479],{"class":370,"line":460},5,[368,462,463],{"class":387},"    return",[368,465,466],{"class":402}," old_len",[368,468,469],{"class":387}," *",[368,471,472],{"class":445}," 2",[368,474,475],{"class":387}," >=",[368,477,478],{"class":402}," file_len",[368,480,457],{"class":398},[368,482,484],{"class":370,"line":483},6,[368,485,486],{"class":398},"}\n",[14,488,489,490,493],{},"Dasselbe gilt für Pfade. Statt dem Modell zu sagen, es solle im Projekt\nbleiben, löst eine Funktion den Pfad auf und gibt nichts zurück, wenn er\nausserhalb liegt. Ein Pfad, der über ",[42,491,492],{},".."," oder absolut aus dem Projekt\nhinausführt, kann dann gar keine Dateioperation erzeugen.",[14,495,496],{},"Solche Regeln sind reine Funktionen, und reine Funktionen kann man testen.\nBeide haben Unit-Tests. Dazu kommt ein End-to-End-Skript, das den Editor\nheadless gegen das echte Modell fährt und den Ablehnungsweg prüft: Überschreiben\nverlangen, Dialog abwarten, ablehnen, Datei unverändert, und ein Pfad\nausserhalb des Projekts wird abgewiesen. Eine Prompt-Zeile kann man nur\nhoffen.",[14,498,499,500,503],{},"Umgekehrt gilt dasselbe für Fähigkeiten. Das Werkzeug ",[42,501,502],{},"command"," bekommt\nseine Auswahl aus der Kommando-Aufzählung des Editors erzeugt. Jedes Menü und\njedes Tastenkürzel ist damit automatisch für den Agenten erreichbar, ohne\ndass irgendwo eine zweite Liste gepflegt werden müsste.",[14,505,506],{},"Auch die Frage, in welchem Fenster eine vom Agenten geöffnete Datei\nerscheint, ist keine Anweisung an das Modell, sondern eine Funktion mit\nUnit-Test. Der Systemprompt ist auf drei Sätze geschrumpft: die Rolle, die\nKonvention, dass Pfade relativ zum Projekt gemeint sind, und die Bitte, nach\nWerkzeugergebnissen kurz in der Sprache des Nutzers zu antworten. Alles\nandere steht im Code, wo es geprüft wird, statt im Prompt, wo es erbeten\nwird.",[21,508,510],{"id":509},"was-offen-bleibt","Was offen bleibt",[14,512,513],{},"Es gibt Grenzen, die bewusst stehenbleiben. Der Editor lädt genau einen\nSchriftschnitt, deshalb zeigt die Markdown-Ansicht fett und kursiv über\nFarben statt über echte Schnitte. Solche Punkte stehen als Entscheidung in der\nProjektdokumentation, nicht als offene Aufgabe.",[21,515,517],{"id":516},"wo-es-heute-steht","Wo es heute steht",[14,519,520],{},"Von den drei Anforderungen aus der Einleitung sind zwei erfüllt: PDF und\nBilder öffnen sich im Tab, das Terminal ist eingebaut. Git ist erst zur\nHälfte da. Der Explorer zeigt den Status jeder Datei, Diff und Blame fehlen\nnoch. Dazu gekommen sind Dinge, die nicht auf der Liste standen:\nMarkdown-Vorschau, Folien aus Markdown mit Export nach PDF, Sprung zur\nDefinition über einen Sprachserver, Schnellöffner und Befehlspalette, und der\nAgent. Gebaut wird für Linux und Windows.",[14,522,523,524,531],{},"Der Quelltext liegt offen: ",[525,526,530],"a",{"href":527,"rel":528},"https:\u002F\u002Fgithub.com\u002Fgstrainovic\u002Fzid",[529],"nofollow","github.com\u002Fgstrainovic\u002Fzid",".\nDie elf Anläufe davor sind ebenfalls öffentlich, jeder unter seinem Namen aus\nder Tabelle.",[14,533,534,535,539],{},"Wie der Agent den Editor ohne Fenster bedient und prüft, steht im nächsten\nArtikel: ",[525,536,538],{"href":537},"\u002Fopen-source\u002Fki-testet-ohne-fenster\u002F","Ein KI-Agent testet meinen Editor ohne Fenster",".",[541,542,543],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":364,"searchDepth":378,"depth":378,"links":545},[546,547,548,549,550,551,552,553],{"id":23,"depth":378,"text":24},{"id":33,"depth":378,"text":34},{"id":74,"depth":378,"text":75},{"id":92,"depth":378,"text":93},{"id":306,"depth":378,"text":307},{"id":334,"depth":378,"text":335},{"id":509,"depth":378,"text":510},{"id":516,"depth":378,"text":517},"Von VS Code über Terminal-Editoren und gpui zu Zig. Elf Anläufe und warum Werkzeuggrenzen für einen KI-Agenten in den Code gehören.","md",{},true,"\u002Fopen-source\u002Feditor-suche",null,{"title":5,"description":554},"open-source\u002Feditor-suche","WweYIGuMxmGgt6HP0JLv7hBF9yCmJHof8Rr-ALyi6A4",1791100802032]