În prezent, sunt în căutarea de a cunoaște și înțelege mai bine instrumentele bazate pe treesitter pentru R. Pentru a fi scurt, treesitter este un instrument pentru analizarea codului, de exemplu, recunoașterea a ceea ce este o funcție, un argument, o logică într-un șir de cod. Cu instrumentele construite pe treesitter, puteți căuta, reformata, scame și repara etc. codul dvs. Lucruri interesante, care rulează local și determinist pe mașina dvs.
Vorbind despre „etc.”, Etienne Bacher a sugerat cu ajutor să mă uit și la instrumentele bazate pe treesitter pentru alte limbi pentru a vedea ce mai lipsește din ecosistemul nostru. Așa am dat peste difftastic de Wilfred Hughes, „un instrument structural diff care înțelege sintaxa”. ✨ Aceasta înseamnă că difftastic nu compară doar linia sau „cuvintele”, ci și sintaxa reală, uitându-se la liniile din jurul liniilor care s-au schimbat (în mod implicit, 3), și mai bine, înțelege R din cutie.
Mulțumesc mult lui Etienne Bacher nu numai pentru că m-a făcut să descopăr difftastic, ci și pentru feedback-ul util despre această postare!
Instalarea difftastic
difftastic pe două fișiere
Puteți rula difftastic pe două fișiere, un pic așa cum ați folosi pachetul Waldo R pe două obiecte.
Să comparăm:
a <- gsub("bad", "good", x)
la
a <- stringr::str_replace(x, "bad", "good")
cu respect salvat în old.R şi new.R. CLI se numește difft nu difftastic. Folosesc afișarea „inline” în loc de cele două coloane implicite pentru a economisi spațiu orizontal.
difft old.R new.R --display inline
Am ajunge la această diferență frumoasă:

Parantezele și "bad" şi "good" argumentele sunt ignorate.
De asemenea, putem obține versiunea JSON a acestui difer, care este o caracteristică instabilă, care necesită setarea unei variabile de mediu:
export DFT_UNSTABLE=yes difft old.R new.R --display json
Asta ne prinde
{"aligned_lines":((0,0),(1,1)),"chunks":(({"lhs":{"line_number":0,"changes":({"start":5,"end":9,"content":"gsub","highlight":"normal"},{"start":23,"end":24,"content":",","highlight":"normal"},{"start":25,"end":26,"content":"x","highlight":"normal"})},"rhs":{"line_number":0,"changes":({"start":5,"end":12,"content":"stringr","highlight":"normal"},{"start":12,"end":14,"content":"::","highlight":"keyword"},{"start":14,"end":25,"content":"str_replace","highlight":"normal"},{"start":26,"end":27,"content":"x","highlight":"normal"},{"start":27,"end":28,"content":",","highlight":"normal"})}})),"language":"R","path":"content/post/2026-03-26-difftastic/new.R","status":"changed"}
Acum, nimic din toate acestea nu este foarte util pentru că nu aș compara niciodată fișierele în acest fel… Folosesc controlul versiunilor!
difftastic cu Git
Putem seta difftastic ca instrument de diff extern pentru Git la nivel global sau pentru proiectul curent.
De exemplu, cu pachetul gert R, pentru a-l seta local:
gert::git_config_set("diff.external", "difft")
Dacă vreau să folosesc afișajul inline, aș seta:
gert::git_config_set("diff.external", "difft --display inline")
Apoi git diff va folosi în mod implicit difftastic. Cel mai interesant pentru mine, git show --ext-diff va folosi difftastic. Nu folosesc niciodată git diff direct, dar mă uit foarte mult la comiterile mai mult sau mai puțin recente.
Să spunem că sunt interesat de commit-ul care a eliminat dependența lui roxygen2 de stringi, voi rula:
git show 7a1dd39866699a2b0a034bb15244c07698a1e2e7 --ext-diff
și obțineți:


Acest lucru nu este spectaculos pentru că acesta este o mică diferență, dar îmi place evidențierea parantezelor apelului imbricat eliminat și a celui logic.
Caracteristici interesante ale difftastic
Pornind de la două exemple ale paginii de pornire difftastic…
Ignorarea modificărilor de formatare
Deoarece formatatorii vă pot aplica atât de util preferințele de formatare, revizuirea modificărilor de formatare într-un patch care se referă la cu totul altceva este inutilă și enervantă. Imaginați-vă că aveți o definiție a funcției care se potrivește pe o singură linie, apoi adăugați un argument la ea.
Trecand de la
f <- function(myarg1 = foo, myarg2 = bar) {}
la
f <- function(
myarg1 = foo,
myarg2 = bar,
myarg3 = baz
) {}
Deoarece definiția are acum mai mult de 80 de caractere, formatatorul poate schimba definiția pentru a fi pe mai multe linii. Dar schimbarea de fapt interesantă este adăugarea unui argument.
Diferența Git nativă ar arata:


Git cu difftastic ar arăta:


Potrivirea delimitatorilor este motivul pentru care mi s-a părut mai plăcută afișarea roxygen2 de către difftastic.
Potrivirea delimitatorilor în ambalaje
Diferența Git poate arăta puțin urâtă atunci când pur și simplu mutați codul de la o funcție la alta.
Să zicem că plecăm de la
f <- function() {
1 + 1
}
la
f <- function() {
g()
}
g <- function() {
1 + 1
}
Diferența Git ar arăta:


În timp ce Git cu difftastic ar arăta:


Voi folosi difftastic?
Îmi place foarte mult conceptul din spatele difftastic și cele câteva comite-uri Git la care m-am uitat cu el redate frumos. Acum, ceea ce îmi lipsește pentru a folosi difftastic mult este integrarea sa cu instrumentele în care folosesc de fapt Git:
- Positron inclusiv extensia GitLens;
- Fila GitHub Pull Request Files.
În orice caz, voi continua să învăț despre instrumente bazate pe treesitter, dintre care unele precum Air și Jarl le pot utiliza deja direct din IDE-ul meu. 😸
