🔒 TouchQuill jest w fazie zamkniętych testów.Chcesz go wypróbować? Napisz do nas →
Lens

Historia funkcji, nie tylko plików

Zwykły blame odpowiada na pytanie „kto zmienił linijkę 40 w pliku X”. Lens odpowiada na pytanie, które naprawdę zadajesz: co się działo z tą konkretną funkcją, także wtedy, gdy plik po drodze zmienił nazwę, a kod przewędrował do innego modułu. Dotyczy to też Blueprintów Unreala, nie tylko kodu. Poniżej dokładnie: co śledzi, w jakich językach, jak dopasowuje i gdzie ma granice. Bez obietnic na wyrost.

Co to daje

Jedno pytanie, pełna odpowiedź

Pytasz o funkcję po nazwie. Dostajesz jej cały życiorys, sklejony przez wszystkie zmiany nazw i przeprowadzki między plikami. Zmiany czysto kosmetyczne (formatowanie, komentarze, nazwy zmiennych) nie zaśmiecają wyniku.

tq lens blame --symbol calculate_damage

CREATED        ch-6f9  rev:1   krzysztof   „pierwsza wersja”
MODIFIED       ch-a12  rev:3   marta       „buff obrażeń”
MOVED+RENAMED  ch-c73  rev:5   krzysztof   (z compute_damage w Weapon.rs)  [~86%]

Liczba w nawiasie, na przykład [~86%], to pewność dopasowania. Gdy nazwa i kod pasują dokładnie, jest to 100%. Gdy funkcję przemianowano i przepisano naraz, Lens pokazuje, jak bardzo jest pewny, że to wciąż ten sam byt.

Zakres

Co dokładnie śledzi

Lens rozpoznaje i śledzi symbole kodu, czyli nazwane elementy programu. Konkretnie osiem rodzajów:

Funkcje i metody

Wolne funkcje i metody wewnątrz klas. Metoda ma nazwę kwalifikowaną, na przykład Enemy::TakeDamage, żeby dwie różne metody o tej samej nazwie się nie myliły.

Typy

Klasy, struktury, enumy, interfejsy oraz trait'y (w Rust). Śledzone tak samo jak funkcje, przez zmiany nazw i przenosiny.

Moduły

Jednostki grupujące kod (moduł, namespace, pakiet), na tyle na ile dany język je wyraża.

Grafy Blueprintów

Blueprinty Unreala (.uasset): EventGraph, funkcje, makra i ConstructionScript. „Kto zmienił funkcję Interact w BP_Door?" działa też bez linijki kodu.

Czego Lens nie śledzi: zmiennych, pól klas, stałych ani makr. To celowe. Lens operuje na poziomie funkcji i typów, bo to one mają sensowną „historię”, którą chcesz prześledzić.
Języki

Prawdziwy parser tam, gdzie się da

Dla większości języków Lens używa pełnego parsera składni (tree-sitter), więc rozumie strukturę kodu, a nie zgaduje z tekstu. Kilka języków bez gotowego parsera obsługuje prostszym mechanizmem zapasowym.

SposóbJęzykiDokładność
Pełny parser (tree-sitter)Rust, C, C++, C#, Python, JavaScript, TypeScript, Go, Java, Luawysoka
Blueprinty UE (natywny)pliki .uasset / .umap — grafy Blueprintu: EventGraph, funkcje, makra, ConstructionScriptgrafy
Ekstraktor zapasowy (heurystyka)Verse (UEFN), GDScript, ActionScript, shadery HLSL / GLSL / USF / USHprzybliżona

Ekstraktor zapasowy czyta kod linia po linii i rozpoznaje deklaracje po wcięciach i słowach kluczowych. Działa, ale jest wrażliwy na nietypowe formatowanie, bloki w jednej linii czy mieszanie tabów ze spacjami. Rozszerzenia plików można też domapować ręcznie w pliku .tqlens.toml (na przykład potraktować .inc jak C++).

Odporność

Co przeżywa przy refaktoringu

Sedno Lens: rozpoznaje, że symbol to wciąż ten sam symbol, nawet po sporych zmianach. Wykrywa:

SytuacjaCo robi Lens
Zmiana nazwy pliku lub przeniesienie funkcji do innego plikuŚledzi dalej, niezależnie od ścieżki.
Zmiana nazwy samej funkcjiRozpoznaje po strukturze kodu, z oceną pewności.
Zmiana nazwy i przepisanie ciała narazDopasowuje rozmyto, pokazuje pewność (na przykład [~72%]).
Zamiana nazw dwóch funkcji miejscamiRozstrzyga po strukturze, nie po nazwie.
Wydzielenie fragmentu do nowej funkcji albo wklejenie jej z powrotemWykrywa jako podział albo scalenie.
Skopiowanie funkcjiOznacza jako kopię wciąż żywego oryginału.

Porównuje strukturę, nie tekst

Lens sprowadza kod do znormalizowanej postaci: nazwy zmiennych zamienia na anonimowe znaczniki, pomija formatowanie i komentarze. Dzięki temu zmiana nazw w środku funkcji nie gubi jej tożsamości. Odporne jest nawet na lawinę zmian nazw wywoływanych funkcji.

Nie zgaduje na siłę

Gdy dwie funkcje pasują niemal tak samo dobrze, Lens nie wybiera po cichu jednej. Oznacza wynik jako niejednoznaczny i pokazuje kandydatów. Rozstrzygasz sam komendą tq lens link albo w Studio jednym kliknięciem, a Twoja decyzja wygrywa z heurystyką.

Zszywa przeprowadzki między commitami

Gdy funkcja znika w jednym commicie i pojawia się w innym w ciągu 7 dni (okno konfigurowalne), Lens skleja to w jedno przeniesienie, zamiast pokazać osobno „usunięto” i „utworzono”.

Przykład z życia

Funkcja, która przeżyła refaktoring

Metoda obrażeń w projekcie Unreal: zaczyna w jednym pliku, po drodze trafia do osobnego modułu i zmienia nazwę. Zwykły blame zgubiłby ślad przy każdym z tych kroków. Lens skleja to w jeden życiorys:

tq lens trace --symbol ApplyDamage

CREATED   rev:1   Source/Combat/Enemy.cpp          TakeDamage
MODIFIED  rev:4   Source/Combat/Enemy.cpp          (balans obrażeń)
MOVED     rev:7   Source/Combat/DamageSystem.cpp   (z Enemy.cpp)               [~100%]
RENAMED   rev:9   Source/Combat/DamageSystem.cpp   TakeDamage → ApplyDamage    [~91%]

Przeniesienie między modułami rozpoznaje po dokładnym odcisku (100%), a rename razem z drobną edycją ciała dostaje ocenę pewności (91%). Gdy później wydzielisz kawałek tej metody do osobnej funkcji, Lens pokaże to jako podział:

tq lens blame --symbol UpdateCooldowns

CREATED   rev:12  Source/Combat/DamageSystem.cpp   (wydzielone z ApplyDamage)  [~78%]
Unreal C++. Kod Unreala Lens traktuje pierwszoklasowo. Śledzi Twoje klasy i metody przez zmiany nazw i przenosiny między modułami, także w kodzie obudowanym makrami Unreala (UCLASS, UFUNCTION, UPROPERTY, GENERATED_BODY). Historia symbolu żyje tam, gdzie logika, czyli w Twoich metodach, niezależnie od tego, do którego pliku czy modułu je przeniesiesz.
Komendy

Jak z tego korzystać

KomendaCo robi
tq lens blame --symbol <nazwa>Historia symbolu. Przyjmuje pełną nazwę albo samą końcówkę (TakeDamage znajdzie Enemy::TakeDamage).
tq lens trace --symbol <nazwa>Pełny życiorys przez wszystkie nazwy, jakie symbol nosił po drodze.
tq lens symbols <plik>Lista symboli w pliku w bieżącej wersji.
tq lens link <nowszy> <starszy>Ręcznie zszywasz dwie historie, gdy heurystyka się zawahała. unlink to cofa.
tq lens reindex / indexPrzebudowa indeksu albo dociągnięcie zaległych rewizji.

Każda komenda przyjmuje --json, więc łatwo wpiąć Lens w skrypty i narzędzia.

W edytorze

Lens w VS Code

Rozszerzenie do VS Code. Nad każdą funkcją i klasą pokazuje napis Lens: nazwa (CodeLens). Klik otwiera historię symbolu. To samo działa z menu kontekstowego na symbolu pod kursorem, a wynik ląduje w panelu. Pod spodem to tq lens blame --json, więc edytor i terminal pokazują dokładnie to samo. Na dziś to jedyna gotowa wtyczka; pełne Visual Studio i JetBrains Rider są w planach (patrz „Plany rozwoju” niżej).
Wydajność

Liczy się tylko to, co nowe

Wyniki parsowania są zapamiętywane pod odciskiem treści pliku. Ponieważ magazyn adresuje pliki po zawartości, plik niezmieniony albo identyczny z innym nie jest parsowany drugi raz.

Indeksowanie 64 plikówCzas
pierwszy raz (zimny cache)135 ms
ponownie (ciepły cache)19 ms
Formaty binarne

Blueprint i assety: co jest, a czego nie

Lens rozumie tekst. Pliki binarne, jak Blueprint czy .uasset, to inna bajka i tu trzeba mówić uczciwie.

✓ Jest: mechanizm wtyczek

Lens ma działający host wtyczek (WASM) razem z zestawem narzędzi (SDK) do napisania własnego ekstraktora symboli dla dowolnego formatu, także binarnego. Taki ekstraktor liczy własny odcisk, a Lens śledzi te symbole tak samo jak tekstowe: przez zmiany nazw i przenosiny.

≈ Blueprinty: w planach rozwoju

Blueprintów ani plików .uasset Lens jeszcze nie czyta. Obsługa Blueprintów jest w planach rozwoju i powstanie właśnie na tym mechanizmie wtyczek. Na razie Lens śledzi symbole w kodzie tekstowym.

Plany rozwoju

Co jest w drodze

Uczciwie oddzielamy to, co działa dziś, od tego, co dopiero planujemy. Na liście najbliższych rzeczy:

Lens dla Blueprintów

Śledzenie symboli wprost w grafach Blueprint i plikach .uasset, zbudowane na istniejącym mechanizmie wtyczek. Historia węzła czy funkcji Blueprinta tak samo jak dla kodu tekstowego.

Wtyczki do IDE

Obok istniejącego rozszerzenia do VS Code planujemy wtyczki do pełnego Visual Studio oraz JetBrains Rider, żeby historia symbolu była pod ręką także tam, gdzie realnie piszecie kod gry.

Granice

Gdzie Lens się kończy

Żeby nie było niespodzianek, oto rzeczy, których Lens nie robi albo robi z ograniczeniami:

Chcesz zobaczyć Lens w akcji na własnym repo? Napisz do nas. Więcej o codziennej pracy jest w dokumentacji.