• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Stworzenie edytora kodu w HTML z podświetlaniem składni od podstaw

Object Storage Arubacloud
+2 głosów
269 wizyt
pytanie zadane 5 października 2022 w JavaScript przez Wally Bywalec (2,840 p.)

Chcę zrobić od podstaw w HTML (js, jquery, frameworki - nie ważne jakie) edytor kodu z podświetlaniem składni, wpisywanego tekstu (wsparcie dla markdown, java, wiele więcej). Coś na podobieństwo VSCode, który jest między innymi w HTMLu zrobiony. Mam z tym duży problem. Udało mi się zrobić to podejściem, że jest główny DIV z atrybutem contentEditable. A w środku każda linia edytora to kolejne DIVy. Każdą linię mogę stylować dodając w środku SPAN. 

Klikam w edytor tekstu, pobieram pozycję kursora i zapisuję do pamięci. Następnie fokusuję się na elemencie TEXTAREA, który jest niewidoczny. Wciskam literkę na klawiaturzę (wprowadzam znak do TEXTAREA zfocusowanego) i wpisuję ten znak do tekstu wyświetlanego (do zmiennej w której trzymam kopię to co wyświetlam na UI) ponieważ mam w pamięci pozycję kursora.

Potrafię kliknąć w DIV contentEditable i pobrać pozycję kursora. Ale problem jest gdy robię zaznaczenie tekstu. Następuje zmiana FOCUS pomiędzy dzieci DIVu contentEditable, a także pomiędzy moim ukrytym TEXTAREA. Finalnie zwrócona pozycja kursora wtedy to UNDEFINED. Będąc jednak już zfocusowanym na tym DIVie, przy następnym kliku pozycja zwracana jest poprawna. 

Czy ktokolwiek jest w stanie poradzić z doświadczenia przy tych rzeczach, zarzucić linkiem do czegoś takiego? Szukałem wiele i nie widzę nic konkretnego. Próbowałem "debugować" jak działa https://vscode.dev/ ale nie potrafię tego zrozumieć, zbyt skomplikowane dla mnie debugować taki skomplikowany frontend. Mamy 2022 rok i napisanie syntax highlighting edytora tekstu w HTML + JS jest niebywale trudne. Nie wierzę, że ktokolwiek jest w stanie pomóc. Ale może akurat ktoś tutaj zna ten temat.

Stąd wziąłem kod na funkcję, która zwraca pozycję kursora w DIV contentEditable: https://stackoverflow.com/a/53128599/2209414

Tutaj wrzuciłem demo swoje: https://jsfiddle.net/710znv5a/

Można myszką zrobić akcję MOUSEDOWN na kolejnych wierszach. Dopiero przy drugim naciśnięciu na wiersz, dostajemy poprawną pozycję (kwestia zmiany focusu pewnie) - widać to w konsoli w logach. 

PS: W demo wyżej nie ma TEXTAREA i wprowadzania tekstu, bo tak jest krócej na wklejkę jsfiddle.

1
komentarz 5 października 2022 przez ScriptyChris Mędrzec (190,190 p.)

1 odpowiedź

+2 głosów
odpowiedź 5 października 2022 przez Comandeer Guru (600,730 p.)

Jeśli masz już [contenteditable], to nie dokładałbym do tego dodatkowo ukrytego textarea. Samo zrobienie dobrze synchronizacji między tymi dwoma elementami jest czymś ekstremalnie trudnym – na tyle, że powstaje całe nowe API, które to próbuje eliminować. Mimo wszystko szedłbym w stronę próby operowania bezpośrednio na tym div, bez przerzucania selekcji i focusu do innego, ukrytego elementu.

VSCode, co prawda, ma urkyty textarea, ale to, co widzi użytkownik, nie jest [contenteditable]. To jest całkowicie niestandardowa implementacja edytora, w której zarówno selekcja, jak i kursor, są tworzone przy pomocy kodu. Widać to choćby po tym, że jest możliwość wstawiania kilku kursorów naraz lub zaznaczania kilku fragmentów tekstu naraz – coś, na co przeglądarki nie pozwalają. Zamiast próbować wzorować się na aż tak skomplikowanym edytorze, raczej bym spojrzał, jak to robi choćby CodeMirror – zwłaszcza, że jego źródła są na GitHubie. I tak, jest to zdecydowanie mniej skomplikowana rzecz od VSCode, ale wciąż jest niezwykle skomplikowana.

Ogólnie tego typu edytory składają się z dwóch części: modelu (stanu) oraz widoku. Model to ich wewnętrzna struktura danych, która przechowuje treść, dodatkowe ustawienia, różne informacje o stylowaniu poszczególnych części itd. Widok z kolei jest odpowiedzialny za wyświetlanie modelu użytkownikowi. To on odpowiada za selekcję, generowanie HTML-a, który będzie odzwierciedlał informacje w modelu, itd. Do tego dochodzi cała warstwa czegoś, co można nazwać kontrolerem, która będzie dbała o to, by przechwytywać zdarzenia z widoku, mielić wpisywaną przez użytkownika treść do modelu oraz następnie aktualizować widok. Przykład:

  • User wpisuje "function" w widoku.
  • Kontroler (słuchający np. na zdarzeniu input) wyłapuje to i przesyła do modelu.
  • Model to parsuje (np. filtruje usuwając zbędne stylowanie) i zapisuje w sensownej formie.
  • Kontroler aktualizuje widok w oparciu o nową postać modelu, czyli np. "function" jest odpowiednio pokolorowane.

No i trzeba dbać przy tym, żeby nam się selekcja nie rozjechała po aktualizacji widoku, bo byłoby średnio, gdyby nagle po pokolorowaniu "function" wyleciała gdzieś w kosmos.

Jest też drugie podejście, starsze i (w teorii) prostsze: robienie wszystkiego bezpośrednio na DOM. W tym podejściu widok i model to jedno, bo jedynym źródłem prawdy jest zawartość naszego elementu [contenteditable]. I tutaj problem sprowadza się do wyszukiwania odpowiednich słów kluczowych w treści – co samo w sobie nie jest proste.

Samo kolorowanie składni to zupełnie inny problem. Są dwie szkoły: regexy i AST. W VSC używane są regexy – tyle że w składni TextMate'a. I ten sposób wydaje się prostszy, bo mamy do czynienia wyłącznie z tekstem przez cały czas. No ale właśnie: traktowanie kodu jako tekstu w niektórych brzegowych przypadkach może generować niepoprawne rezultaty.

Dlatego istnieje drugi sposób: parsowanie poszczególnych języków do AST (struktury drzewiastej podobnej do DOM), co pozwala na wykrycie poszczególnych typów tokenów (zmiennych, ciągów tekstowych, słów kluczowych itd.). CodeMirror ma do tego cały podprojekt, Lezer. I każdy język tak naprawdę ma swój własny parser, ponieważ każdy ma inną gramatykę, więc inne zasady parsowania, co ostatecznie przekłada się na osobne sposoby kolorowania składni.

I teraz wracamy do architektury takiego edytora: kolorowanie jest na tyle skomplikowanym zadaniem, że o wiele lepiej pasuje do edytora, w którym model i widok są od siebie oddzielone. Zwłaszcza, że przeglądarki lubią dodawać sporo swojego "fluffu" do [contenteditable] (np niełamliwe spacje w losowych miejscach czy br czające się na końcach linii/pustych elementów), który może przeszkadzać w sensownym parsowaniu i kolorowaniu składni. A model jest (powinien być) zaprojektowany tak, żeby zawsze trzymać czyste dane i to w poprawnej formie. I mając taką zawsze poprawną strukturę danych, możemy bez problemu parsować jej zawartość.

Pomijam tutaj już wszystkie kwestie wydajnościowe, czyli np. kolorowanie w workerze czy robienie tego fragmentami, żeby za każdym razem nie przekolorowywać całej zawartości edytora.

Ogólnie: to jest zabawa na długie miesiące, jak nie lata (zwłaszcza, jeśli to Twoje pierwsze zetknięcie się z [contenteditable] i ogólnie edytowaniem tekstu w przeglądarce).

Podobne pytania

0 głosów
1 odpowiedź 540 wizyt
pytanie zadane 2 maja 2018 w Offtop przez Hiskiel Pasjonat (22,830 p.)
+1 głos
1 odpowiedź 268 wizyt
+1 głos
2 odpowiedzi 481 wizyt
pytanie zadane 30 maja 2022 w HTML i CSS przez okti00 Obywatel (1,300 p.)

92,539 zapytań

141,382 odpowiedzi

319,476 komentarzy

61,928 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...