📄 uicdocumentdoc.pas
字号:
//add the file with a prefix and it's number
Result := 'File_';
if TheFile.InternalNameIndex <> 0 then
Result := Result + IntToStr(TheFile.InternalNameIndex);
Result := Result + TheFile.InternalFileName;
if Assigned(Ident) then //identifier in file/record-like type ?
begin
if Assigned(Ident.MemberOf) then //if in record-like type
//add record-like type with prefix
Result := Result + '.I_' + Ident.MemberOf.Name;
Result := Result + '.I_'; //add prefix and index and its name
if (Ident.InternalNameIndex <> 0) and not (Ident is TRecordType) then
Result := Result + IntToStr(Ident.InternalNameIndex);
Result := Result + Ident.Name;
end;
end;
{Returns the help context of the position in the documentation or 0.
~param URI the position in the documentation to search the help context of
~result the help context of the position or 0 if none has been defined }
function TICDocumentDoc.GetHelpContextOfURI(const URI: String): THelpContext;
var Index :Integer; //the index in the list of help contexts
begin
Index := FHelpContextList.IndexOf(URI); //search the position
if Index <> -1 then //help context for position defined?
Result := THelpContext(FHelpContextList.Objects[Index]) //return help context
else
Result := 0; //none defined for the position
end;
{Returns the position in the documentation with the help context or ''.
~param HelpContext the help context to search the defined position for
~result the position for the help context or '' if none has been defined }
function TICDocumentDoc.GetURIOfHelpContext(HelpContext: THelpContext): String;
var Index :Integer; //the index in the list of help contexts
begin
Index := FHelpContextList.IndexOfObject(TObject(HelpContext));
if Index <> -1 then //help context for position defined?
Result := FHelpContextList[Index] //return the position
else
Result := ''; //no position defined
end;
{Defines the position to be shown when help is requested with the context.
~param URI the position in the documentation to define the help context
for
~param HelpContext the help context to be defined for the position }
procedure TICDocumentDoc.DefineHelpContext(const URI: String;
HelpContext: THelpContext);
begin
Assert(URI <> '');
Assert(HelpContext <> 0);
Assert(GetHelpContextOfURI(URI) = 0);
Assert(GetURIOfHelpContext(HelpContext) = '');
//define the context for the topic
FHelpContextList.AddObject(URI, TObject(HelpContext));
end;
{Resets the attributes to ready the generator for a new generation. }
procedure TICDocumentDoc.ResetForNewGeneration;
begin
inherited ResetForNewGeneration; //reset inherited attributes
FHelpContextList.Clear; //clear all help contexts
end;
{Will be called for all expressions, for instance like used as the index of an
array or the value of a constant. The text should be parsed and identifiers
should be underlaid with a link to their declaration if possible.
~param ExprStr the text of the expression
~param OfIdentifier the identifier for which to transform the expression
~param AddTo the node to add the transformed text to
~todo reimplement, I'm not really happy with it, but it does work in most
cases }
procedure TICDocumentDoc.AddExpression(const ExprStr: String;
OfIdentifier: TIdentifier;
AddTo: TICNCompound);
{Adds a link to the given identifier. The identifier can't be declared inside
a record-like type but must be top-level declared inside the file.
~param Ident the identifier to link to
~param WriteFile if the file (also as a link) should be written
~result a string containing a link to the identifier (and the file) }
procedure AddIdentifierLink(Ident: TIdentifier; AddTo: TICNCompound;
AddLinkToFile: Boolean = False);
begin
Assert(Assigned(Ident));
Assert(not Assigned(Ident.MemberOf));
Assert(not DoNotDocumentIdentifier(Ident));
if AddLinkToFile then //link to file should also be added?
begin
Assert(Assigned(Ident.InFile));
Assert(not DoNotDocumentIdentifier(nil, Ident.InFile));
//add link to file and separating dot
AddTo.AppendNode(TICNLinkIdentifier.CreateIdentifierLink(AddTo.Owner,
Ident.InFile.InternalFileName,
nil, Ident.InFile, nil));
AddTo.AppendNode(TICNText.CreateText(AddTo.Owner, '.'));
end;
//add link to identifier
AddTo.AppendNode(TICNLinkIdentifier.CreateIdentifierLink(AddTo.Owner,
Ident.Name,
Ident, nil, nil));
end;
var SourceRec :TRecordType; //current record-like type
State :( //general state in the expression
sNo, //after operator or similar character
sIdent, //after an identifier (or dot)
sBrace, //after an opening brace or bracket
sString); //after a string
Parser :TTokenParser; //parser of the expression
Token :String; //a token in the expression
Next :String; //the next token after an identifier
FileGiven :Boolean; //file of identifier was given
Position :TPosition; //position to start search
Ident :TIdentifier; //identifiers in the expression
dot :Integer; //index of a "." in the token
//file of record-like type to search identifiers in
RecIdent :TRecordType; //used record-like type
IdentName :String; //a used member of a record-like type
begin
Assert(Assigned(OfIdentifier));
Assert(Assigned(OfIdentifier.InFile));
if OfIdentifier is TRecordType then //get current record-like type
SourceRec := TRecordType(OfIdentifier) //is is one, use it
else
SourceRec := OfIdentifier.MemberOf; //use its record-like type
if Assigned(OfIdentifier) then //get position to search from
begin
if OfIdentifier is TRecordType then //if it is a record-like type
Position := OfIdentifier.Position //use its position
else
Position := OfIdentifier.ForwardDefPos; //use always the first declaration
end
else
begin
Position.Row := -1; //search from the beginning
Position.Column := 1;
end;
Parser := TTokenParser.Create; //create tokenizer
try
Parser.PascalDialect := OfIdentifier.InFile.PascalDialect;
Parser.ParseString(ExprStr); //parse expression text
State := sNo; //begin without a special state
while Parser.GetIdentWithPointsToken(Token) do //parse each token
begin //is an identifier?
if (Token <> '') and (Token[1] in StartIdentifierChars) then
begin
State := sIdent; //next token is after identifier
if LowerCase(Token) = 'nil' then //is nil?
AddReservedWord(Token, AddTo) //just add to the expression
else
begin
AddTo.AppendText(' '); //add a space before it
Parser.PushPosition;
Parser.GetToken(Next); //preview the following token
Parser.PopPosition;
//not initialization of a record, i.e. a field of the record?
if Next <> ':' then
begin
dot := pos('.', Token);
if Assigned(SourceRec) then //is in a record-like type?
begin
if dot = 0 then
dot := length(Token) + 1;
//search the identifier in it by this name
Ident := SourceRec.IdentList.GetIdentByName(copy(Token, 1,
dot - 1));
if Assigned(Ident) then
begin
AddIdentifierLink(Ident, AddTo); //add link to it
Delete(Token, 1, dot); //remove identifier
end
else
dot := pos('.', Token);
end
else
Ident := nil; //not found so far
if not Assigned(Ident) then
begin
//search the identifier by this name (globally)
Ident := FindIdentifier(Token, OfIdentifier.InFile, Position);
if Assigned(Ident) then //the identifier found?
begin
FileGiven := (dot <> 0) and //file name given?
(length(OfIdentifier.InFile.InternalFileName) =
dot - 1) and
(CompareText(OfIdentifier.InFile.InternalFileName,
copy(Token, 1, dot - 1)) = 0);
if dot = 0 then //get full length of identifier or file
dot := length(Token) + 1;
AddIdentifierLink(Ident, AddTo, FileGiven);
if FileGiven then //if file given
begin
Delete(Token, 1, dot); //delete it
dot := pos('.', Token);
if dot = 0 then
dot := length(Token);
end;
Delete(Token, 1, dot); //delete the identifier
end;
end;
if Assigned(Ident) then //something found?
begin
//while members follow
while (Token <> '') and (Ident is TRecordType) do
begin
dot := pos('.', Token);
if dot = 0 then //get next member
IdentName := Token
else
IdentName := copy(Token, 1, dot - 1);
RecIdent := TRecordType(Ident); //search the member
Ident := RecIdent.FindMember(IdentName, OfIdentifier.InFile,
False);
if Assigned(Ident) then //member found?
begin
if dot = 0 then //delete it
Token := ''
else
Delete(Token, 1, dot);
AddTo.AppendText('.');
AddIdentifierLink(Ident, AddTo); //append a link to it
end;
end; //while Token <> '' and Ident is TRecordType
if Token <> '' then //add any unknown members
begin
AddTo.AppendText('.');
AddIdentifierText(Token, AddTo);
end;
end //if assigned(Ident)
else
AddIdentifierText(Token, AddTo); //append text
end //if Next <> ':' //record-field initialization?
else
//link on field of record would be nice, but would have to know the
//record, hard if its an array of record or record of array etc.
AddIdentifierText(Token, AddTo);
end //if not 'nil'
end //if identifier or reserved word
else
begin
if (State <> sBrace) and //no space after opening brace
((length(Token) <> 1) or //not a single special character?
(not (Token[1] in [',', '.', '(', ')', ']']) and
((Token[1] <> '[') or (State <> sIdent)))) and
//no spaces between parts of strings
((State <> sString) or not (Token[1] in ['''', '#', '^'])) then
AddTo.AppendText(' '); //add a separating space
if Token[1] = '''' then //is a string?
AddString(Token, AddTo) //add formatted as string
else
AddTo.AppendText(Token); //add text
//get state of the expression after this last token
if Token[1] in ['(', '['] then
State := sBrace
else
if (Token[1] in ['''', '#']) or
((Token[1] = '^') and (State <> sIdent)) then
State := sString
else
if Token[1] in [')', ']', '.', '^'] then
State := sIdent
else
State := sNo;
//needs a second token?
if (State = sString) and (Token[1] in ['#', '^']) and
Parser.GetToken(Token) then //and it is available?
//add character number or the escaped control character
AddTo.AppendText(Token);
end; //else identifier or reserved word
end; //while Parser.GetIdentWithPointsToken
finally
Parser.Free; //free tokenizer
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -