IDE: Move function DoMakeResourceString to unit MakeResStrDlg. Improve the logic. Issue #28829.

This commit is contained in:
Juha 2024-03-07 04:42:51 +02:00
parent 79a6aff5c9
commit ca5ac00672
4 changed files with 175 additions and 172 deletions

View File

@ -9699,16 +9699,14 @@ end;
procedure TCustomSynEdit.CaretAtIdentOrString(XY: TPoint; out AtIdent, NearString: Boolean);
// This is optimized to check if cursor is on identifier or string.
var
PosX, PosY: integer;
PosX, PosY, Start: integer;
Line, Token: string;
Start: Integer;
Attri, PrevAttri: TSynHighlighterAttributes;
begin
PosY := XY.Y -1;
PrevAttri := nil;
AtIdent := False;
NearString := False;
//DebugLn('');
//DebugLn('TCustomSynEdit.CaretAtIdentOrString: Enter');
if Assigned(Highlighter) and (PosY >= 0) and (PosY < FTheLinesView.Count) then
begin
@ -9716,30 +9714,33 @@ begin
fHighlighter.CurrentLines := FTheLinesView;
Highlighter.StartAtLineIndex(PosY);
PosX := XY.X;
//DebugLn([' TCustomSynEdit.CaretAtIdentOrString: Line="', Line, '", PosX=', PosX, ', PosY=', PosY]);
if (PosX > 0) and (PosX <= Length(Line)) then
//DebugLn([' CaretAtIdentOrString: Line="',Line,'", PosX=',PosX,', PosY=', PosY]);
if (PosX > 0) and (PosX <= Length(Line)+1) then
begin
while not Highlighter.GetEol do
begin
Start := Highlighter.GetTokenPos + 1;
Token := Highlighter.GetToken;
//TokenType := Highlighter.GetTokenKind;
Attri := Highlighter.GetTokenAttribute;
//DebugLn([' TCustomSynEdit.CaretAtIdentOrString: Start=', Start, ', Token=', Token]);
if (PosX = Start) then
//DebugLn([' CaretAtIdentOrString: Start=', Start, ', Token=', Token]);
if PosX = Start then
begin
AtIdent := (Attri = Highlighter.IdentifierAttribute)
or (PrevAttri = Highlighter.IdentifierAttribute);
NearString := (Attri = Highlighter.StringAttribute)
or (PrevAttri = Highlighter.StringAttribute); // If cursor is on end-quote.
//DebugLn([' TCustomSynEdit.CaretAtIdentOrString: Success! Attri=', Attri,
// ', AtIdent=', AtIdent, ', AtString=', AtString]);
//DebugLn([' CaretAtIdentOrString: Success 1! Attri=', Attri,
// ', AtIdent=', AtIdent, ', NearString=', NearString]);
exit;
end;
if (PosX >= Start) and (PosX < Start + Length(Token)) then
begin
if (PosX >= Start) and (PosX <= Start + Length(Token))
and ( (Attri = Highlighter.IdentifierAttribute)
or (Attri = Highlighter.StringAttribute) )
then begin
AtIdent := Attri = Highlighter.IdentifierAttribute;
NearString := (Attri = Highlighter.StringAttribute);
NearString := Attri = Highlighter.StringAttribute;
//DebugLn([' CaretAtIdentOrString: Success 2! Attri=', Attri,
// ', AtIdent=', AtIdent, ', NearString=', NearString]);
exit;
end;
PrevAttri := Attri;

View File

@ -923,16 +923,6 @@ resourcestring
+'looses characters at line %s, column %s.';
lisNOTECouldNotCreateDefineTemplateForLazarusSources = 'NOTE: Could not '
+'create Define Template for Lazarus Sources';
lisInvalidExpressionHintTheMakeResourcestringFunction = 'Invalid expression.%s'
+'Hint: The "Make Resourcestring" function expects a string constant in a '
+'single file. Please select the expression and try again.';
lisSelectionExceedsStringConstant = 'Selection exceeds string constant';
lisHintTheMakeResourcestringFunctionExpectsAStringCon = 'Hint: The "Make '
+'Resourcestring" function expects a string constant.%sPlease select the '
+'expression and try again.';
lisNoResourceStringSectionFound = 'No ResourceString Section found';
lisUnableToFindAResourceStringSectionInThisOrAnyOfThe = 'Unable to find a '
+'ResourceString section in this or any of the used units.';
lisOwnerIsAlreadyUsedByTReaderTWriterPleaseChooseAnot = '''Owner'' is '
+'already used by TReader/TWriter. Please choose another name.';
lisDuplicateNameAComponentNamedAlreadyExistsInTheInhe = 'Duplicate name: A '
@ -3827,7 +3817,7 @@ resourcestring
lisTheResourceClassDescendsFromProbablyThisIsATypoFor = 'The resource '
+'class "%s" descends from "%s". Probably this is a typo for TForm.';
// make resource string dialog
// make resourcestring
lisMakeResourceString = 'Make ResourceString';
lisMakeResStrInvalidResourcestringSect = 'Invalid Resourcestring section';
lisMakeResStrPleaseChooseAResourcestring = 'Please choose a resourcestring '
@ -3849,6 +3839,17 @@ resourcestring
lisMakeResStrInsertContexttSensitive = 'Insert context sensitive';
lisMakeResStrSourcePreview = 'Source preview';
lisNoStringConstantFound = 'No string constant found';
lisSelectionExceedsStringConstant = 'Selection exceeds string constant';
lisInvalidExpressionHintTheMakeResourcestringFunction = 'Invalid expression.'
+'%sHint: The "Make Resourcestring" function expects a string constant in a '
+'single file. Please select the expression and try again.';
lisHintTheMakeResourcestringFunctionExpectsAStringCon =
'Hint: The "Make Resourcestring" function expects a string constant.'
+'%sPlease select the expression and try again.';
lisNoResourceStringSectionFound = 'No ResourceString Section found';
lisUnableToFindAResourceStringSectionInThisOrAnyOfThe = 'Unable to find a '
+'ResourceString section in this or any of the used units.';
lisFailedToResolveMacros = 'failed to resolve macros';
lisToolHasNoExecutable = 'tool "%s" has no executable';
lisCanNotFindExecutable = 'cannot find executable "%s"';

View File

@ -946,7 +946,6 @@ type
procedure DoGotoIncludeDirective;
// tools
function DoMakeResourceString: TModalResult;
function DoDiff: TModalResult;
function DoFindInFiles: TModalResult;
@ -3996,8 +3995,8 @@ begin
GetCurrentUnit(ASrcEdit, AnUnitInfo);
ActiveDesigner := GetActiveDesignerSkipMainBar;
if (ActiveDesigner is TDesigner) and
not UpdateEditorCommandsStamp.Changed(ASrcEdit, ActiveDesigner as TDesigner, DisplayState) then
Exit;
not UpdateEditorCommandsStamp.Changed(ASrcEdit,TDesigner(ActiveDesigner),DisplayState)
then Exit;
Editable := Assigned(ASrcEdit) and not ASrcEdit.ReadOnly;
SelAvail := Assigned(ASrcEdit) and ASrcEdit.SelectionAvailable;
@ -4009,7 +4008,8 @@ begin
begin
CurWordAtCursor := ASrcEdit.GetWordAtCurrentCaret;
//it is faster to get information from SynEdit than from CodeTools
ASrcEdit.EditorComponent.CaretAtIdentOrString(ASrcEdit.EditorComponent.CaretXY, IdentFound, StringFound);
ASrcEdit.EditorComponent.CaretAtIdentOrString(ASrcEdit.EditorComponent.CaretXY,
IdentFound, StringFound);
end
else begin
CurWordAtCursor := '';
@ -4019,18 +4019,21 @@ begin
if Assigned(ActiveDesigner) then
begin
IDECommandList.FindIDECommand(ecUndo).Enabled := DsgEditorActive and ActiveDesigner.CanUndo; {and not ActiveDesigner.ReadOnly}
IDECommandList.FindIDECommand(ecRedo).Enabled := DsgEditorActive and ActiveDesigner.CanRedo; {and not ActiveDesigner.ReadOnly}
IDECommandList.FindIDECommand(ecUndo).Enabled := DsgEditorActive and ActiveDesigner.CanUndo;
IDECommandList.FindIDECommand(ecRedo).Enabled := DsgEditorActive and ActiveDesigner.CanRedo;
DesignerCanCopy := ActiveDesigner.CanCopy;
IDECommandList.FindIDECommand(ecCut).Enabled := DesignerCanCopy;
IDECommandList.FindIDECommand(ecCopy).Enabled := DesignerCanCopy;
IDECommandList.FindIDECommand(ecPaste).Enabled := ActiveDesigner.CanPaste;
IDECommandList.FindIDECommand(ecSelectAll).Enabled := Assigned(ActiveDesigner.Form) and (ActiveDesigner.Form.ComponentCount>0);
IDECommandList.FindIDECommand(ecSelectAll).Enabled :=
Assigned(ActiveDesigner.Form) and (ActiveDesigner.Form.ComponentCount>0);
end
else
begin
IDECommandList.FindIDECommand(ecUndo).Enabled := Editable and SrcEditorActive and Assigned(ASrcEdit) and ASrcEdit.EditorComponent.CanUndo;
IDECommandList.FindIDECommand(ecRedo).Enabled := Editable and SrcEditorActive and Assigned(ASrcEdit) and ASrcEdit.EditorComponent.CanRedo;
IDECommandList.FindIDECommand(ecUndo).Enabled := Editable and SrcEditorActive
and Assigned(ASrcEdit) and ASrcEdit.EditorComponent.CanUndo;
IDECommandList.FindIDECommand(ecRedo).Enabled := Editable and SrcEditorActive
and Assigned(ASrcEdit) and ASrcEdit.EditorComponent.CanRedo;
IDECommandList.FindIDECommand(ecCut).Enabled := SelEditable;
IDECommandList.FindIDECommand(ecCopy).Enabled := SelAvail;
IDECommandList.FindIDECommand(ecPaste).Enabled := Editable;
@ -10963,142 +10966,6 @@ begin
DoJumpToCodeToolBossError;
end;
function TMainIDE.DoMakeResourceString: TModalResult;
var
ActiveSrcEdit: TSourceEditor;
ActiveUnitInfo: TUnitInfo;
StartPos, EndPos: TPoint;
StartCode, EndCode: TCodeBuffer;
NewIdentifier, NewIdentValue: string;
NewSourceLines: string;
InsertPolicy: TResourcestringInsertPolicy;
SectionCode: TCodeBuffer;
SectionCaretXY: TPoint;
DummyResult: Boolean;
SelectedStartPos: TPoint;
SelectedEndPos: TPoint;
CursorCode: TCodeBuffer;
CursorXY: TPoint;
OldChange: Boolean;
begin
OldChange:=OpenEditorsOnCodeToolChange;
OpenEditorsOnCodeToolChange:=true;
try
Result:=mrCancel;
ActiveSrcEdit:=nil;
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
{$IFDEF IDE_DEBUG}
debugln('');
debugln('[TMainIDE.DoMakeResourceString] ************');
{$ENDIF}
// calculate start and end of expression in source
CursorCode:=ActiveUnitInfo.Source;
if ActiveSrcEdit.EditorComponent.SelAvail then
CursorXY:=ActiveSrcEdit.EditorComponent.BlockBegin
else
CursorXY:=ActiveSrcEdit.EditorComponent.LogicalCaretXY;
if not CodeToolBoss.GetStringConstBounds(
CursorCode,CursorXY.X,CursorXY.Y,
StartCode,StartPos.X,StartPos.Y,
EndCode,EndPos.X,EndPos.Y,true) then
begin
DoJumpToCodeToolBossError;
exit;
end;
// the codetools have calculated the maximum bounds
if (StartCode=EndCode) and (CompareCaret(StartPos,EndPos)=0) then begin
IDEMessageDialog(lisNoStringConstantFound,
Format(lisHintTheMakeResourcestringFunctionExpectsAStringCon, [LineEnding]),
mtError,[mbCancel]);
exit;
end;
// the user can shorten this range by selecting text
if (ActiveSrcEdit.EditorComponent.SelText='') then begin
// the user has not selected text
// -> check if the string constant is in single file
// (replacing code that contains an $include directive is ambiguous)
//debugln('TMainIDE.DoMakeResourceString user has not selected text');
if (StartCode<>ActiveUnitInfo.Source)
or (EndCode<>ActiveUnitInfo.Source)
then begin
IDEMessageDialog(lisNoStringConstantFound, Format(
lisInvalidExpressionHintTheMakeResourcestringFunction, [LineEnding]),
mtError,[mbCancel]);
exit;
end;
end else begin
// the user has selected text
// -> check if the selection is only part of the maximum bounds
SelectedStartPos:=ActiveSrcEdit.EditorComponent.BlockBegin;
SelectedEndPos:=ActiveSrcEdit.EditorComponent.BlockEnd;
CodeToolBoss.ImproveStringConstantStart(
ActiveSrcEdit.EditorComponent.Lines[SelectedStartPos.Y-1],
SelectedStartPos.X);
CodeToolBoss.ImproveStringConstantEnd(
ActiveSrcEdit.EditorComponent.Lines[SelectedEndPos.Y-1],
SelectedEndPos.X);
//debugln('TMainIDE.DoMakeResourceString user has selected text: Selected=',dbgs(SelectedStartPos),'-',dbgs(SelectedEndPos),' Maximum=',dbgs(StartPos),'-',dbgs(EndPos));
if (CompareCaret(SelectedStartPos,StartPos)>0)
or (CompareCaret(SelectedEndPos,EndPos)<0)
then begin
IDEMessageDialog(lisSelectionExceedsStringConstant,
Format(lisHintTheMakeResourcestringFunctionExpectsAStringCon, [LineEnding]),
mtError,[mbCancel]);
exit;
end;
StartPos:=SelectedStartPos;
EndPos:=SelectedEndPos;
end;
// gather all reachable resourcestring sections
//debugln('TMainIDE.DoMakeResourceString gather all reachable resourcestring sections ...');
if not CodeToolBoss.GatherResourceStringSections(
CursorCode,CursorXY.X,CursorXY.Y,nil)
then begin
DoJumpToCodeToolBossError;
exit;
end;
if CodeToolBoss.Positions.Count=0 then begin
IDEMessageDialog(lisNoResourceStringSectionFound,
lisUnableToFindAResourceStringSectionInThisOrAnyOfThe,
mtError,[mbCancel]);
exit;
end;
// show make resourcestring dialog
Result:=ShowMakeResStrDialog(StartPos,EndPos,StartCode,
NewIdentifier,NewIdentValue,NewSourceLines,
SectionCode,SectionCaretXY,InsertPolicy);
if (Result<>mrOk) then exit;
// replace source
ActiveSrcEdit.ReplaceLines(StartPos.Y,EndPos.Y,NewSourceLines);
// add new resourcestring to resourcestring section
if (InsertPolicy<>rsipNone) then
DummyResult:=CodeToolBoss.AddResourcestring(
CursorCode,CursorXY.X,CursorXY.Y,
SectionCode,SectionCaretXY.X,SectionCaretXY.Y,
NewIdentifier,''''+NewIdentValue+'''',InsertPolicy)
else
DummyResult:=true;
ApplyCodeToolChanges;
if not DummyResult then begin
DoJumpToCodeToolBossError;
exit;
end;
// switch back to source
ActiveSrcEdit.Activate;
ActiveSrcEdit.EditorComponent.SetFocus;
Result:=mrOk;
finally
OpenEditorsOnCodeToolChange:=OldChange;
end;
end;
function TMainIDE.DoDiff: TModalResult;
var
ActiveSrcEdit: TSourceEditor;

View File

@ -41,7 +41,7 @@ interface
uses
Classes, SysUtils,
// LCL
Forms, Controls, StdCtrls, Dialogs, ExtCtrls, ButtonPanel,
Forms, Controls, StdCtrls, Dialogs, ExtCtrls, ButtonPanel, LCLProc,
// SynEdit
SynHighlighterPas, SynEdit,
// CodeTools
@ -51,7 +51,8 @@ uses
// IdeConfig
RecentListProcs,
// IDE
LazarusIDEStrConsts, EditorOptions, MiscOptions;
LazarusIDEStrConsts, EditorOptions, MiscOptions, MainBase, SourceEditor,
Project;
type
@ -90,7 +91,6 @@ type
// highlighter
SynPasSyn: TSynPasSyn;
procedure CustomIdentifierCheckBoxClick(Sender: TObject);
procedure HelpButtonClick(Sender: TObject);
procedure IdentLengthComboBoxChange(Sender: TObject);
@ -137,6 +137,9 @@ function ShowMakeResStrDialog(
out ResStrSectionXY: TPoint;
out InsertPolicy: TResourcestringInsertPolicy): TModalResult;
function DoMakeResourceString: TModalResult;
implementation
{$R *.lfm}
@ -194,6 +197,137 @@ begin
MakeResStrDialog.Free;
end;
function DoMakeResourceString: TModalResult;
var
ActiveSrcEdit: TSourceEditor;
ActiveUnitInfo: TUnitInfo;
SelectedStartPos, SelectedEndPos: TPoint;
StartPos, EndPos, SectionCaretXY, CursorXY: TPoint;
StartCode, EndCode, SectionCode, CursorCode: TCodeBuffer;
NewIdentifier, NewIdentValue, NewSourceLines: string;
InsertPolicy: TResourcestringInsertPolicy;
DummyResult, OldChange: Boolean;
begin
OldChange:=MainIDE.OpenEditorsOnCodeToolChange;
MainIDE.OpenEditorsOnCodeToolChange:=true;
try
Result:=mrCancel;
ActiveSrcEdit:=nil;
if not MainIDE.BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
// calculate start and end of expression in source
CursorCode:=ActiveUnitInfo.Source;
if ActiveSrcEdit.EditorComponent.SelAvail then
CursorXY:=ActiveSrcEdit.EditorComponent.BlockBegin
else
CursorXY:=ActiveSrcEdit.EditorComponent.LogicalCaretXY;
DummyResult:=CodeToolBoss.GetStringConstBounds(
CursorCode,CursorXY.X,CursorXY.Y,
StartCode,StartPos.X,StartPos.Y,EndCode,EndPos.X,EndPos.Y,true);
// codetools have calculated the maximum bounds
if DummyResult and (StartCode=EndCode) and (StartPos=EndPos) then begin
// cursor is behind the closing quote, try again inside quotes.
DummyResult:=CodeToolBoss.GetStringConstBounds(
CursorCode,CursorXY.X-1,CursorXY.Y,
StartCode,StartPos.X,StartPos.Y,EndCode,EndPos.X,EndPos.Y,true);
end;
if not DummyResult then begin
MainIDE.DoJumpToCodeToolBossError;
exit;
end;
//DebugLn(['DoMakeResourceString: CursorXY=', CursorXY.X,',',CursorXY.Y,
// ', StartPos=', StartPos.X,',',StartPos.Y,
// ', EndPos=', EndPos.X,',',EndPos.Y]);
if (StartCode=EndCode) and (StartPos=EndPos) then begin
IDEMessageDialog(lisNoStringConstantFound,
Format(lisHintTheMakeResourcestringFunctionExpectsAStringCon,[LineEnding]),
mtError,[mbCancel]);
exit;
end;
// the user can shorten this range by selecting text
if (ActiveSrcEdit.EditorComponent.SelText='') then begin
// the user has not selected text
// -> check if the string constant is in single file
// (replacing code that contains an $include directive is ambiguous)
//debugln('DoMakeResourceString user has not selected text');
if (StartCode<>ActiveUnitInfo.Source) or (EndCode<>ActiveUnitInfo.Source)
then begin
IDEMessageDialog(lisNoStringConstantFound,
Format(lisInvalidExpressionHintTheMakeResourcestringFunction,[LineEnding]),
mtError,[mbCancel]);
exit;
end;
end else begin
// the user has selected text
// -> check if the selection is only part of the maximum bounds
SelectedStartPos:=ActiveSrcEdit.EditorComponent.BlockBegin;
SelectedEndPos:=ActiveSrcEdit.EditorComponent.BlockEnd;
CodeToolBoss.ImproveStringConstantStart(
ActiveSrcEdit.EditorComponent.Lines[SelectedStartPos.Y-1],
SelectedStartPos.X);
CodeToolBoss.ImproveStringConstantEnd(
ActiveSrcEdit.EditorComponent.Lines[SelectedEndPos.Y-1],
SelectedEndPos.X);
//debugln('DoMakeResourceString user has selected text: Selected=',dbgs(SelectedStartPos),'-',dbgs(SelectedEndPos),' Maximum=',dbgs(StartPos),'-',dbgs(EndPos));
if (CompareCaret(SelectedStartPos,StartPos)>0)
or (CompareCaret(SelectedEndPos,EndPos)<0)
then begin
IDEMessageDialog(lisSelectionExceedsStringConstant,
Format(lisHintTheMakeResourcestringFunctionExpectsAStringCon,[LineEnding]),
mtError,[mbCancel]);
exit;
end;
StartPos:=SelectedStartPos;
EndPos:=SelectedEndPos;
end;
// gather all reachable resourcestring sections
//debugln('DoMakeResourceString gather all reachable resourcestring sections ...');
if not CodeToolBoss.GatherResourceStringSections(
CursorCode,CursorXY.X,CursorXY.Y,nil)
then begin
MainIDE.DoJumpToCodeToolBossError;
exit;
end;
if CodeToolBoss.Positions.Count=0 then begin
IDEMessageDialog(lisNoResourceStringSectionFound,
lisUnableToFindAResourceStringSectionInThisOrAnyOfThe,
mtError,[mbCancel]);
exit;
end;
// show make resourcestring dialog
Result:=ShowMakeResStrDialog(StartPos,EndPos,StartCode,
NewIdentifier,NewIdentValue,NewSourceLines,
SectionCode,SectionCaretXY,InsertPolicy);
if (Result<>mrOk) then exit;
// replace source
ActiveSrcEdit.ReplaceLines(StartPos.Y,EndPos.Y,NewSourceLines);
// add new resourcestring to resourcestring section
if (InsertPolicy<>rsipNone) then
DummyResult:=CodeToolBoss.AddResourcestring(
CursorCode,CursorXY.X,CursorXY.Y,
SectionCode,SectionCaretXY.X,SectionCaretXY.Y,
NewIdentifier,''''+NewIdentValue+'''',InsertPolicy)
else
DummyResult:=true;
CodeToolBoss.SourceCache.ClearAllSourceLogEntries;
if not DummyResult then begin
MainIDE.DoJumpToCodeToolBossError;
exit;
end;
// switch back to source
ActiveSrcEdit.Activate;
ActiveSrcEdit.EditorComponent.SetFocus;
Result:=mrOk;
finally
MainIDE.OpenEditorsOnCodeToolChange:=OldChange;
end;
end;
{ TMakeResStrDialog }
procedure TMakeResStrDialog.CustomIdentifierCheckBoxClick(Sender: TObject);