Would Be Divided Up Into:
proceduretsKeyWord tsSpaceTForm1tsIdentifier.tsSymbolFormCreatetsIdentifier (tsSymbolSendertsIdentifier: tsSymbolTObjecttsIdentifier); tsSymbol tsSpace {Create Form} tsComment
How is it done?
The RichEdit control normally loads preformatted text from .RTF files by way of by of the RichEdit.Lines.LoadFromFile () function YourPasEdit uses the RichEdit.Lines.LoadFromStream () function to load the file from a TPasConversion -. A custom TMemoryStream descendant. This stream takes the plaint text Pascal source file, loads it into its internal memory buffe, and then converts it from plain text to a text impregnated with RTF codes. This way when it is loaded the RichEdit control via RichEdit.Lines.LoadFromStream into the Pascal Source File Appears in The Control Color-syntax highlight.
To The Main Editor, this process is transparent - The code Looks Something Like this:
begin NewRichEdit: = TRichEdit.Create; PasCon.Clear; // Prepare the TPasConversion PasCon.LoadFromFile (FName); // Load the File into the Memory Stream PasCon.ConvertReadStream; // Convert the stream to RTF format NewRichEdit.Lines.BeginUpdate ; NewRichEdit.Lines.LoadFromStream (PasCon); // Read from the TPasConversion NewRichEdit.Lines.EndUpdate NewRichEdit.Show; Result: = NewRichEdit; endEXAMPLE - snippet of code from the NewRichEditCreate (Fname) routine
As I Said, It is The TmemoryStream Derived TPasconversion Which Does All The Hard Work:
// prepare the Outbuf to a certain default size FOutBuffSize: = size 3; ReAllocMem (FOutBuff, FOutBuffSize); // Initialise the parser to its begining state FTokenState: = tsUnknown; FComment: = csNo; FBuffPos: = 0; FReadBuff: = Memory; // Write Leading RTF Header WriteTobuff ('{/ RTF1 / ANSI / DEFF0 / DEFTAB720 {/ FONTTBL {/ f0 / fswiss ms Sansserif;} {/ f1 / froman / fcharset2 symbol;} {/ f2 / fmodern Courier New }} ' # 13 # 10); WriteTobuffer (' {/ colorbl / red0 / green0 / blue0;} ' # 13 # 10); WriteTobuffer (' / deflang1033 / pard / plain / f2 / fs20 ') // Creadbuff) and tokenize it results: = read (FREADBUFF ^, size); FREADBUFF [Result]: = # 0; if Result> 0 THEN BEGIN RUN: = FREADBUFF; tokenptr: = Run; While Run ^ <> # 13: // deal with crlfs begin fcomment: = csno; handlecrlf; end; # 1 .. # 9, # 11, # 12, # 14 .. # 32: / / DEAL with VARIOUS Whitespaces, Control Codes Begin While Run ^ in [# 1 .. # 14, # 11, # 12, # 14 .. # 32] do inc (RUN); fTokenState: = TSSPACE; tokenlen: = Run - tokenptr; setString (TokenStr, Tokenptr , Tokenlen; StrTf; WriteTobuffer (prefix tokenstr postfix); tokenptr: = Run; end; ~~~~~~~~~~~~~~~~~~~ ~~~~ ~~~~~ much code removed ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~ End; Endexample - Snippet Showing The While Loop That Breaks Up The Instream Into Recognosed Tokens
MOST OF THE WORK IS DONE BY [CASE RUN ^ IN ... End;] section which "Breaks Off" a token from the instream (freadbuf) based on the logic in the copy statement. The copy statement is Organised in Such A way that it can quickly decipher the input stream into the various TokenTypes by examining each character in turn Having worked out which tokentype it is, the actual encoding part is relatively easy: FTokenState: = tsSpace; TokenLen:. = Run - TokenPtr; SetString ( TokenStr, Tokenptr, Tokenlen; Scanforrtf; SetRTF; WriteTobuff; EXAMPLE - Basic Steps in Encoding The Output Stream of The TPasconversion Object
What's happening here is the program:
sets FTokenState to what we believe it is (in this part of the code it is tsSpace which matches any series of Whitespaces) the length of the token is calculated by working out how far the current memory pointer (Run) has moved since we finished with the last token (TokenPtr). the token is then copied from the Input buffer from the starting position of it in the memory buffer (TokenPtr) for the length of the token, into the variable TokenStr. ScanForRtf just checks through the resultant TokenStr to ensure it does not have any funny characters that the RichEdit would confuse as RTF commands. If it finds any, it escapes them out. SetRTF looks at the FTokenState to populate two global variables Prefix and Postfix with the appropriate RTF codes to give the token the Right Color, Font, Boldness. Writetobuffer Than Simply Puts The TokenStr with the prefix and postfix around it intenotput buffer and the loop the loop.
Back to the topic: syntax highlighting (on-the-fly)
No source code is necessarily 100% applicable to your needs. I was fortunate in that most of the parser applied to my 4GL command syntax (eg Strings were strings, Numbers were numbers, similar Keywords). As well YourPasEditor had implemented most of the basic Accessory Tasks Such as Printing, Find, Find and Replace, Multi-File Editing. It Was Just A Matter of Addin The Extras I Was After.problem # 1 - No Colors Or Fonts
One task the Parser did not fully implement was Colors or Different Fonts, or even fonts sizes. The reason for this (after some trial and error) was that the SetRTF procedure new nothing about how to do this. It only used the information in regards [Bold], [Italics] and [Underline] stored in the Win95 Registry for the Delphi Editors Settings to determine how to highlight each token As for fonts -. well I had not realised that the Delphi Editor actually uses only one Font and FONTSIZE for All The Different Tokens - So That Wasn't Pas2rtf Fault. I Was Just Being Greedy.
Luckily The Comments in Pas2rtt.Pas Told Me What The Other Values In The Registry Coded for, especially Where The Important Foreground Color Was Stored. This Meant Some Changes TO:
1. Procedure setDelphirtf (s: string; atokenstate: tttokenstate);
Add after the THE;
Font.color: = start (ed_list [0]);
2. Procedure TPasConversion.setPreandPosfix
Add after fprefix [atokenstate] = '';
FPREFIXLIST [ATOKENSTATE]: = ColorTortRf (AFONT.COLOR);
The ColorToRtf codes is already present, but had not been used for some reasone If you try it out you'll understand why :-) You get absolutely no change except lots of.. ';' In the wrong place.Change the ' 'to' (space) 'in ColorTortortRTF (), and you get rid of the'; 'Appearing in the richedit control, but no colors anyway.my first Thought WAS That The value in Ed_List [0] Didn't Convert To A Proper Font.Color. The Easiest Way To Test this Was To Hard Code Font.Color: = CLGreen; and See What Happens. Again No Luck. The Format Was Consistent with The RTF Codes I Could See in The RTF Header. What of the THE $ #% # $% # was WRONG WITH IT?
It was about then that I realised I needed a crash course in RTF document structure. For this I rushed off to www.microsoft.com (please forgive me) and found a reference on RTF. After an hour of reading a Microsoft Technical Document I Was Even more confused. oh Well - this Meant It Was Time to get Dirty. Time TO GET DOWN TO REAL Program. Time to "Cheat".
What did I do I went into WordPad (which is just a glorified RichEdit version 2.0 on steroids) and saved various files into RTF format I then opened them in NotePad so I could see the RTF codes and compare what happened in each case?.: What Codes Were Produced Depending On What i DID, or Didn't do. a Similar Sort of Technique Was Used Back In The 1980s To Decipher The First Paradox Database Format :-) Sorry Borland.