[{"data":1,"prerenderedAt":563},["ShallowReactive",2],{"seite-\u002Fit\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_it\u002Fopen-source\u002Feditor-suche.md","Sette mesi alla ricerca di un 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},"sette-mesi-alla-ricerca-di-un-editor",[14,15,16],"p",{},"VS Code è stato il mio primo e unico editor. Ma le prestazioni mi davano\nfastidio: a volte consuma tantissimo processore e memoria. Così ho iniziato a\ncercare qualcosa di più veloce.",[14,18,19],{},"I miei requisiti erano pochi: anteprima per PDF e immagini, un terminale, e\nGit nell'editor.",[21,22,24],"h2",{"id":23},"gli-editor-da-terminale-sono-veloci-ma-ciechi","Gli editor da terminale sono veloci, ma ciechi",[14,26,27],{},"La prima strada portava al terminale. Lì la velocità non è un problema.\nL'anteprima sì: niente immagini, niente PDF, niente Markdown renderizzato.",[14,29,30],{},"Così ho provato ad aggiungerla. In Fresh i plugin sono troppo limitati per\nfarlo. In LazyVim funziona, ma non ovunque. Non tutti i terminali collaborano,\ne non era nemmeno stabile: con le anteprime delle immagini nell'explorer\nLazyVim andava in crash. Sopra tutto aleggiava il sospetto che prima o poi\navrei sbattuto contro un tetto insito nel terminale stesso.",[21,32,34],{"id":33},"cambiare-il-guscio-invece-di-rattoppare-il-plugin","Cambiare il guscio invece di rattoppare il plugin",[14,36,37],{},"Da qui è nato il mio primo approccio, e ribalta il problema. Se l'anteprima\nnon entra nel terminale, allora è l'editor da terminale che deve entrare in\nuna finestra.",[14,39,40,41,45,46,49,50,53,54,57],{},"Due tentativi sono andati in questa direzione. ",[42,43,44],"code",{},"neoview"," incorpora Neovim\ntramite ",[42,47,48],{},"nvim-rs"," in un'interfaccia costruita con gpui, il framework con cui\nè costruito anche Zed. L'interfaccia comunica con Neovim tramite msgpack-rpc.\n",[42,51,52],{},"freshview"," fa lo stesso con l'editor Fresh, ma in modo più stretto: Fresh\ngira come libreria nello stesso processo, egui fornisce la finestra,\n",[42,55,56],{},"egui_ratatui"," traduce tra i due, e mupdf disegna PDF e immagini in finestre\nfluttuanti accanto.",[14,59,60,61,64,65,68,69,71],{},"I tentativi successivi, ",[42,62,63],{},"flexed"," e ",[42,66,67],{},"editor-framework",", non sono più wrapper,\nma impalcature su gpui in cui niente è nucleo e tutto è plugin. In\n",[42,70,67],{}," i plugin sono in Lua e si possono ricaricare senza\nricompilare.",[21,73,75],{"id":74},"perché-rust-è-stato-scartato","Perché Rust è stato scartato",[14,77,78],{},"Zed è un buon editor, ma senza anteprima PDF. E Zed è scritto in Rust.",[14,80,81,82,64,84,86],{},"Per me Rust era troppo lento da compilare. ",[42,83,44],{},[42,85,52],{}," avevano le\nloro difficoltà, una visualizzazione lenta qui, un crash alla chiusura\ndell'anteprima PDF là. Forse si sarebbero potute risolvere, forse no. A\ndecidere è stato altro: con quei tempi di compilazione non avanzavo\nabbastanza in fretta. E gpui è Rust, quindi è caduto anche lui.",[14,88,89],{},"Cercavo un altro linguaggio veloce con cui fare concorrenza a Zed. Go\nsembrava datato, V troppo poco conosciuto, e Zig stava proprio emergendo come\nconcorrente di Rust. Quindi Zig, e lì per me la compilazione è piacevolmente\npiù veloce.",[21,91,93],{"id":92},"undici-tentativi-otto-interfacce","Undici tentativi, otto interfacce",[14,95,96],{},"Ogni riga è un repository a sé, nell'ordine in cui sono nati. Alcuni sono\nvissuti un giorno, altri una settimana. Tutti e undici stanno in cinque\nsettimane, tra inizio marzo e inizio aprile 2026.",[98,99,100,122],"table",{},[101,102,103],"thead",{},[104,105,106,110,113,116,119],"tr",{},[107,108,109],"th",{},"Iniziato",[107,111,112],{},"Tentativo",[107,114,115],{},"Linguaggio",[107,117,118],{},"Interfaccia",[107,120,121],{},"Motivo dell'abbandono",[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 marzo",[128,132,44],{},[128,134,135],{},"Rust",[128,137,138],{},"gpui",[128,140,141],{},"Tempi di compilazione",[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 marzo",[128,161,63],{},[128,163,135],{},[128,165,138],{},[128,167,141],{},[104,169,170,173,175,177,180],{},[128,171,172],{},"9 marzo",[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 marzo",[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 marzo",[128,203,204],{},"mojo-nuklear-editor",[128,206,207],{},"Mojo, ponte C",[128,209,210],{},"Nuklear",[128,212,213],{},"Mojo inadatto a scrivere editor",[104,215,216,219,222,225,228],{},[128,217,218],{},"17 marzo",[128,220,221],{},"slint-editor",[128,223,224],{},"Mojo",[128,226,227],{},"Slint tramite Python",[128,229,230],{},"Slint raggiungibile solo tramite Python",[104,232,233,236,239,242,245],{},[128,234,235],{},"22 marzo",[128,237,238],{},"v-gui-editor",[128,240,241],{},"V",[128,243,244],{},"Framework GUI di V",[128,246,247],{},"Lo scorrimento si è rotto dopo l'aggiunta di explorer e schede",[104,249,250,253,256,259,262],{},[128,251,252],{},"25 marzo",[128,254,255],{},"zed-clone",[128,257,258],{},"Zig",[128,260,261],{},"dvui",[128,263,264],{},"Crash durante lo scorrimento, file grandi lenti",[104,266,267,270,273,275,278],{},[128,268,269],{},"26 marzo",[128,271,272],{},"sokol-nanovg-zig-editor",[128,274,258],{},[128,276,277],{},"sokol, NanoVG",[128,279,280],{},"Font sparito dopo il passaggio a Vulkan, il game loop di sokol costava CPU",[104,282,283,286,289,291,294],{},[128,284,285],{},"2 aprile",[128,287,288],{},"qt-ziged",[128,290,258],{},[128,292,293],{},"Qt 6 tramite libqt6zig",[128,295,296],{},"Rimasto una dimostrazione tecnica",[14,298,299,300,303],{},"Il 3 aprile è iniziato ",[42,301,302],{},"zid",". Da allora non c'è più stato alcun nuovo\ntentativo.",[21,305,307],{"id":306},"che-cosa-ne-è-uscito","Che cosa ne è uscito",[14,309,310,311,313],{},"L'editor si chiama ",[42,312,302],{}," ed è scritto in Zig. Disegna tramite wgpu, con il\nrenderer fissato sul backend Vulkan. Il layout lo fa Clay. La resa del testo\nè mia: atlante di glifi e renderer GPU basato su FreeType.",[14,315,316,317,320],{},"L'editor stesso è mio: input, comandi di modifica, ricerca, a capo\nautomatico, numeri di riga, assegnazione dei tasti. Sotto c'è codice di\nterzi, ed è voluto. La memorizzazione del testo la gestisce ",[42,318,319],{},"flow-core",", la\nlibreria centrale dell'editor Flow Control, con i tipi per buffer, cursore e\nselezione. L'evidenziazione della sintassi viene dalla stessa casa tramite\ntree-sitter. Il terminale è l'emulazione di Ghostty, il Markdown lo\nrenderizza zigdown, il PDF lo disegna mupdf.",[14,322,323,324,64,326,328,329,331],{},"È un taglio diverso rispetto a ",[42,325,44],{},[42,327,52],{},". Lì tutto l'editor era\ndi terzi e solo il guscio era mio. Con ",[42,330,302],{}," è il contrario: l'editor è mio,\ndi terzi sono i mattoni sottostanti, che non hanno niente a che fare con la\nmodifica del testo.",[21,333,335],{"id":334},"le-regole-vanno-nel-codice-non-nel-prompt","Le regole vanno nel codice, non nel prompt",[14,337,338,340],{},[42,339,302],{}," ha un agente integrato che lavora con un modello linguistico locale,\nllama-server con Qwen3-4B. Un agente nell'editor ha bisogno di strumenti, e\ngli strumenti hanno bisogno di limiti. La via più ovvia è scrivere i limiti\nnel prompt di sistema. Con un modello di queste dimensioni, però, una riga di\nprompt è solo una preghiera, e a ogni richiesta occupa spazio in un contesto\ndi 8192 token. Per questo i limiti stanno nel codice. Lì però devono essere\nsenza lacune.",[14,342,343,344,347,348,351],{},"Un esempio. Chi vuole sovrascrivere un file esistente riceve una finestra di\nconferma. Il modello l'ha aggirata al primo tentativo: invece di\n",[42,345,346],{},"write_file"," ha inviato un ",[42,349,350],{},"replace_text"," il cui testo da cercare era l'intero\nfile. Formalmente non una sovrascrittura, in pratica esattamente quello.",[14,353,354,355,357],{},"Da allora anche ",[42,356,350],{}," conta come sovrascrittura non appena sostituisce\nmetà del file o più:",[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],{},"Lo stesso vale per i percorsi. Invece di dire al modello di restare nel\nprogetto, una funzione risolve il percorso e non restituisce nulla se si\ntrova all'esterno. Un percorso che esce dal progetto tramite ",[42,491,492],{},".."," o in forma\nassoluta non può quindi generare alcuna operazione sui file.",[14,495,496],{},"Regole del genere sono funzioni pure, e le funzioni pure si possono testare.\nEntrambe hanno unit test. In più c'è uno script end-to-end che fa girare\nl'editor headless contro il modello reale e verifica il percorso del rifiuto:\nchiedere una sovrascrittura, attendere la finestra, rifiutare, file\ninvariato, e un percorso fuori dal progetto viene respinto. Una riga di\nprompt la si può solo sperare.",[14,498,499,500,503],{},"Al contrario, lo stesso vale per le capacità. Lo strumento ",[42,501,502],{},"command"," riceve le\nsue opzioni generate dall'enumerazione dei comandi dell'editor. Ogni menu e\nogni scorciatoia da tastiera è così automaticamente raggiungibile per\nl'agente, senza che da qualche parte si debba mantenere una seconda lista.",[14,505,506],{},"Anche la questione di in quale finestra compare un file aperto dall'agente\nnon è un'istruzione al modello, ma una funzione con unit test. Il prompt di\nsistema si è ridotto a tre frasi: il ruolo, la convenzione che i percorsi si\nintendono relativi al progetto, e la richiesta di rispondere brevemente nella\nlingua dell'utente dopo i risultati degli strumenti. Tutto il resto sta nel\ncodice, dove viene verificato, invece che nel prompt, dove viene chiesto.",[21,508,510],{"id":509},"che-cosa-resta-aperto","Che cosa resta aperto",[14,512,513],{},"Ci sono limiti che restano volutamente. L'editor carica esattamente uno stile\ndi carattere, per questo la vista Markdown mostra grassetto e corsivo tramite\ncolori invece che con veri stili di carattere. Punti come questi sono\nregistrati come decisioni nella documentazione del progetto, non come\ncompiti aperti.",[21,515,517],{"id":516},"a-che-punto-è-oggi","A che punto è oggi",[14,519,520],{},"Dei tre requisiti dell'introduzione, due sono soddisfatti: PDF e immagini si\naprono in una scheda, il terminale è integrato. Git c'è solo a metà.\nL'explorer mostra lo stato di ogni file, diff e blame mancano ancora. Si sono\naggiunte cose che non erano sulla lista: anteprima Markdown, slide da\nMarkdown con esportazione in PDF, salto alla definizione tramite un language\nserver, apertura rapida e palette dei comandi, e l'agente. Viene compilato\nper Linux e Windows.",[14,522,523,524,531],{},"Il codice sorgente è aperto: ",[525,526,530],"a",{"href":527,"rel":528},"https:\u002F\u002Fgithub.com\u002Fgstrainovic\u002Fzid",[529],"nofollow","github.com\u002Fgstrainovic\u002Fzid",".\nAnche gli undici tentativi precedenti sono pubblici, ognuno con il suo nome\ndella tabella.",[14,533,534,535,539],{},"Come l'agente usa e verifica l'editor senza finestra lo racconta il prossimo\narticolo: ",[525,536,538],{"href":537},"\u002Fit\u002Fopen-source\u002Fki-testet-ohne-fenster\u002F","Un agente IA testa il mio editor senza finestra",".",[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},"Da VS Code agli editor da terminale, poi da gpui a Zig. Undici tentativi e perché i limiti degli strumenti di un agente IA vanno nel codice.","md",{},true,"\u002Fopen-source\u002Feditor-suche",null,{"title":5,"description":554},"open-source\u002Feditor-suche","YDG4DiDcbP7ZylOi3GnRLmvlg46xXMmRbo4mKcuDU8Q",1790517213135]