Tvoříme vlastní Syntax Highlighter

C# .NET Pro pokročilé Tvoříme vlastní Syntax Highlighter

Nejprve je třeba si rozvrhnout, jak vlastně bude náš program fungovat. Nejjednodušší co určitě většinu z vás napadne je: mít nějakou kolekci tu projet cyklem a podle toho obarvovat. A přesně tak to uděláme. Samozřejmě nesmíme očekávat extra výkon a chtít jej použít pro větší text. Hodí se spíše pro jednorázové zvýraznění. Ale my si vyzkoušíme i realtime.

Nejprve tedy najdeme nějaká klíčová slova. Já zašel za strejdou a poprosil o "C# keywords" a "PHP keywords". Hned první odkaz mě zavedl sem: http://msdn.microsoft.com/…ary/x53a06bb(v=vs.71).aspx a sem: http://php.net/…keywords.php
Tyto slova jsem jednoduše zkopíroval, vložil do editoru a jednoduše je ořezal tak, aby z nich vznikl dlouhý řádek jednotlivých slov oddělených čárkou.

abstract,event,new,struct,as,explicit,null,switch,base,extern,this,false,operator,throw,break....

Teď je třeba smazat duplicitní slova. To jsem udělal jednoduše. Všechny slova jsem splitnul a cyklem přidal do Listu. A při přidávání jsem kontroloval, zda v Listu již je obsaženo. Pokud ne tak jsem si ho vypsal. Console.Write(keyword + ","); a zkopíroval výsledek.

Teď když máme klíčová slůvka. Je dobré je roztřídit. Na datové typy, fce atp. prostě na kolekci slov, které ve výsledku budeme odlišovat barvou. Klíčová slova budou třeba zelená, kdežto datové typy modré.

Takže budeme mít:

string CSharpKeywords = "abstract,event,new....";
string PHPFunctions = "mb_strlen,mb_strpos...";
string PHPKeywords = "and,array,clone...";
string DataTypes = "bool,object,byte,int...";

Nyní si vytvoříme třídu SyntaxHighlighter a přidáme statickou kolekci Dictionary s datovými typy string a Color.

private static Dictionary<string, Color> keywords;

Nyní veřejnou statickou metodu void InitializeKey­words, ve které deklarujeme kolekci a vložíme naše klíčová slova. Můžeme přidat také jednoduché ošetření if (keywords != null) return; Aby metoda neproběhla vícekrát.

No a teď už jen jednoduše projedeme cyklem jednotlivá slůvka a přidáme je do kolekce.

foreach (string word in CSharpKeywords.Split(','))
        keywords.Add(word, Color.Green);

Tuto metodu zavoláme v konstruktoru Formu.

public Form1()
{
        InitializeComponent();

        SyntaxHighlighter.InitializeKeywords();
}

Když už jsme ve formu, tak si otevřeme Designer a přidáme RichTextBox a Button.

RichTextBox bude moci příjímat Tabulátor AcceptsTab

Tlačítku vytvoříme událost OnClick

Nyní se přesuneme zpět a přidáme veřejnou statickou metodu HighlightText, která vrací string a jejím parametrem je text typu string

Vytvoříme si instanci RichTextBoxu.

RichTextBox rtb = new RichTextBox();
rtb.Text = text;
rtb.Font = new Font(FontFamily.GenericMonospace, 8.75f, FontStyle.Regular);

A nyní projedeme všechna klíčová slova, vyhledáme je v textu a obarvíme.

int index;
foreach (var entry in keywords)
{
        index = 0;
        while ((index = rtb.Find(entry.Key, index, RichTextBoxFinds.WholeWord)) != -1)
        {
                rtb.Select(index, entry.Key.Length);
                rtb.SelectionFont = new Font(rtb.Font.FontFamily, rtb.Font.Size, FontStyle.Bold);
                rtb.SelectionColor = entry.Value;
                index += 1;
        }
}

Teď si popíšeme co vlastně kód dělá.

Je zde jakási proměnná index ta určuje současnou pozici v textu. Při hledání dalšího slova se postupuje od pozice přechozího. Přičítá se k němu 1, protože je v něm obsažena pozice, kde začíná dané slovo a program by se zacyklil, takhle slovo usekneme a bude se hledat dál.

Metoda Find vyhledá dané slovo, začíná hledat od dané pozice a hledá pouze samostatná slova tzn. "in" najde, ale "indeed" už ne. Vrátí pozici, kde dané slovo začíná. Pokud se v textu nevyskytuje vrátí -1.

Metoda Select vybere text, který začíná na dané pozici a označí zadaný počet znaků. Dělá to samé jako když klepnete a táhnete myší přes text.

Nyní když je text vybrán zvolí se barva a písmo výběru pomocí SelectionFont a SelectionColor.

Můžete si dále zvýraznit komentáře:

index = 0;
while ((index = rtb.Text.IndexOf("//", index)) != -1)
{
        rtb.Select(index, rtb.Text.IndexOf("\n", index) - index);
        rtb.SelectionFont = new Font(rtb.Font.FontFamily, rtb.Font.Size, FontStyle.Regular);
        rtb.SelectionColor = Color.Gray;
        index += 2; // zde se přičítá dvojka kvůli popiskům tzv. summary, kde jsou /// závorky já je beru jako komentář.
}

Nebo i string "můj text" či více řádkové komentáře /* můj komentář */, které lze jednoduše přidat stejným způsobem jako jednořádkový komentář.

Nyní si zvýrazňovač "syntax hajlajtr" vyzkoušíme. Pouze do události tlačítka přidáme

richTextBox1.Rtf = SyntaxHighlighter.HighlightText(richTextBox1.Text);

Spustíme a vyzkoušíme.

Nyní si zkusíme real time zvýrazňování. Tzn. že budeme psát a bude se nám text ihned zvýrazňovat. Tlačítko smažeme i s událostí. RichTextBoxu nastavíme dock - aby se nám pěkně roztáhnul. A přidáme mu event KeyDown

Pokud jste někteří zkoušeli z předstihem, narazili jste na problém, že se vlastně nedá psát, protože při prvním klíčovém slovu nás začne vracet nazačátek. To ošetříme jednoduše uložením současné pozice kurzoru SelectionStart, zvýrazněním a následným nastavním pozice kurzoru zpět.

int lastSelectionStart = richTextBox1.SelectionStart;
richTextBox1.Rtf = SyntaxHighlighter.HighlightText(richTextBox1.Text);
richTextBox1.SelectionStart = lastSelectionStart;

Bystří z vás narazí na problém, že pokud chci něco označit a smazat - nejde to. To se dá snadno ošetřit kontrolou zda je něco vybraného - tzn. délka výběru.

if (richTextBox1.SelectionLength > 0) return;

A náš vlastní Highli.. to je slovo hajlajtr je na světě. A pak, že je to ňáká věda :)


 

Stáhnout

Staženo 305x (49.16 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (1)

Článek pro vás napsal David Jančík [sczdavos]
Avatar
Autor je vášnivý programátor v .NET C# a PHP. Nezná slovo "nelze", nebojí se zkoušet nepoznané a pronikat do nových technologií.

Jak se ti líbí článek?
Celkem (4 hlasů) :
4.754.754.754.754.75


 


Miniatura
Všechny články v sekci
C# - Pro pokročilé
Miniatura
Následující článek
Jak zabíjet Windows Update

 

 

Komentáře

Avatar
jackm18
Redaktor
Avatar
jackm18:

Super :)

 
Odpovědět 24.9.2012 23:14
Avatar
Daniel Vítek
Tým ITnetwork
Avatar
Daniel Vítek:

Hezký ;)
Ale když tam dáš něco delšího tak se to seká :(

 
Odpovědět 21.10.2012 14:44
Avatar
Odpovídá na Daniel Vítek
David Jančík [sczdavos]:

To je nejprimitivnější způsob jak si udělat vlastní Syntax Highlighter. Já ho chtěl použít za účelem, že jednou ten text zformátuje a konec.
V praxi při tvorbě Syntax Highlighteru by se měl udělat lexikální rozbor, aby ten program věděl, kde zrovna se nachází a uměl podle toho reagovat. Nebo tak nějak mi to Kit vysvětloval.
Oni jsou i nějaké projekty, na Syntax Highlighter. Jsem zkoušel myslím tento: http://scintillanet.codeplex.com/
Ale také není nejrychlejší a to je o dost složitější.

Odpovědět 21.10.2012 15:08
Čím více času dostaneš, tím méně ho máš.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Jančík [sczdavos]
Kit:

Pokud se to dělá "opravdově", tak se text smí procházet pouze 1×. Bere se slovo za slovem (resp. token za tokenem) a hledá se v kontextovém slovníku. Kontextovém proto, že třeba slovo "public" má jiný význam jako klíčové slovo a jiný jako řetězec. Kontext se dá sledovat pomocí zásobníkového automatu.

Primitivní "hajlajtr" si však vystačí i s jednoduchým slovníkem. Schválně píši slovník, ne seznam. Slovo bude klíčem, barva hodnotou. Načtu slovo (resp. token) ze vstupu, nechám vyhledat ve slovníku, obarvím a vypíšu. Pokud slovo ve slovníku nenajdu, použiji implicitní barvu.

Výhodou tohoto postupu je, že program nezabírá zbytečně paměť ani když vstupní soubor bude mít desítky GB. V paměti je jen slovník, který není velký. Samozřejmě i rychlost je někde úplně jinde.

Odpovědět  +1 21.10.2012 15:41
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Však zde je také použit slovník... Spíše mi vrtá hlavou - jak může text projít jen jedou - když budu psát? Druhá věc je ten kontext - to nechápu, jak se rozliší název proměnné od typu (atp.)...

 
Odpovědět 21.10.2012 15:52
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

Jenže tady se slovník používá (nebo spíš zneužívá) jako obyčejný seznam tuples. Místo aby se slovo hledalo ve slovníku, tak se slovo ze slovníku hledá v textu a to je mnohem náročnější.

Proměnnou od typu rozliší syntaktickou analýzou. Ta se dělá pomocí stavového automatu, který si může budovat slovník proměnných a typů. V objektovém jazyku bude výhodnější využití rekurze, ta nám zajistí i jejich kvalitní likvidaci po opuštění bloku.

Syntaktickou analýzu teď neřešíme. V tuto chvíli se zabýváme jen lexikální, která je podstatně jednodušší.

Odpovědět 21.10.2012 16:07
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 6 zpráv z 6.