mirror of https://gitlab.com/basile.b/dexed.git
1203 lines
34 KiB
Plaintext
1203 lines
34 KiB
Plaintext
unit ce_messages;
|
|
|
|
{$I ce_defines.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, ComCtrls,
|
|
EditBtn, lcltype, ce_widget, ActnList, Menus, clipbrd, AnchorDocking, math,
|
|
TreeFilterEdit, Buttons, GraphType, fgl, strutils,
|
|
ce_ddemangle, ce_writableComponent, ce_common, ce_synmemo, ce_interfaces,
|
|
ce_observer, ce_sharedres, ce_stringrange, ce_dsgncontrols;
|
|
|
|
type
|
|
|
|
TCEEditorMessagePos = class(specialize TFPGMap<string,integer>);
|
|
|
|
(**
|
|
* the struct linked to a log message. allow to be filtered.
|
|
*)
|
|
PMessageData = ^TMessageData;
|
|
TMessageData = record
|
|
ctxt: TCEAppMessageCtxt;
|
|
data: Pointer;
|
|
end;
|
|
|
|
TCEMessagesOptions = class(TWritableLfmTextComponent)
|
|
private
|
|
fFastDisplay: boolean;
|
|
fMaxCount: Integer;
|
|
fAutoSelect: boolean;
|
|
fSingleClick: boolean;
|
|
fAutoDemangle: boolean;
|
|
fAlwaysFilter: boolean;
|
|
fFont: TFont;
|
|
fMsgColors: array[TCEAppMessageKind] of TColor;
|
|
procedure setFont(value: TFont);
|
|
published
|
|
property alwaysFilter: boolean read fAlwaysFilter write fAlwaysFilter;
|
|
property fastDisplay: boolean read fFastDisplay write fFastDisplay;
|
|
property maxMessageCount: integer read fMaxCount write fMaxCount;
|
|
property autoSelect: boolean read fAutoSelect write fAutoSelect;
|
|
property autoDemangle: boolean read fAutoDemangle write fAutoDemangle;
|
|
property singleMessageClick: boolean read fSingleClick write fSingleClick;
|
|
property font: TFont read fFont write setFont;
|
|
property colorBuble: TColor read fMsgColors[amkBub] write fMsgColors[amkBub];
|
|
property colorInfo: TColor read fMsgColors[amkInf] write fMsgColors[amkInf];
|
|
property colorHint: TColor read fMsgColors[amkHint] write fMsgColors[amkHint];
|
|
property colorWarning: TColor read fMsgColors[amkWarn] write fMsgColors[amkWarn];
|
|
property colorError: TColor read fMsgColors[amkErr] write fMsgColors[amkErr];
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor destroy; override;
|
|
procedure assign(source: TPersistent); override;
|
|
procedure AssignTo(target: TPersistent); override;
|
|
end;
|
|
|
|
// gives access to protected fields that should be actually public
|
|
// (scroll position needed for custom draw !)
|
|
TTreeHack = class(TTreeView)
|
|
end;
|
|
|
|
{ TCEMessagesWidget }
|
|
|
|
TCEMessagesWidget = class(TCEWidget, ICEEditableOptions, ICEDocumentObserver, ICEProjectObserver, ICEMessagesDisplay)
|
|
btnClearCat: TCEToolButton;
|
|
sepCat: TCEToolButton;
|
|
btnSelAll: TCEToolButton;
|
|
btnSelApp: TCEToolButton;
|
|
btnSelEdit: TCEToolButton;
|
|
btnSelMisc: TCEToolButton;
|
|
btnSelProj: TCEToolButton;
|
|
sep: TCEToolButton;
|
|
button2: TCEToolButton;
|
|
button4: TCEToolButton;
|
|
button6: TCEToolButton;
|
|
button8: TCEToolButton;
|
|
List: TTreeView;
|
|
TreeFilterEdit1: TTreeFilterEdit;
|
|
procedure ListCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
|
|
State: TCustomDrawState; var DefaultDraw: Boolean);
|
|
procedure ListKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure TreeFilterEdit1AfterFilter(Sender: TObject);
|
|
procedure TreeFilterEdit1ButtonClick(Sender: TObject);
|
|
private
|
|
fImages: TImageList;
|
|
fEditorMessagePos: TCEEditorMessagePos;
|
|
fMsgColors: array[TCEAppMessageKind] of TColor;
|
|
fProjCompile: boolean;
|
|
fActAutoSel: TAction;
|
|
fActClearAll: TAction;
|
|
fActClearCurCat: TAction;
|
|
fActSaveMsg: TAction;
|
|
fActCopyMsg: TAction;
|
|
fActSelAll: TAction;
|
|
fActDemangle: TAction;
|
|
fMaxMessCnt: Integer;
|
|
fAlwaysFilter: boolean;
|
|
fProj: ICECommonProject;
|
|
fDoc: TCESynMemo;
|
|
fCtxt: TCEAppMessageCtxt;
|
|
fAutoSelect: boolean;
|
|
fAutoDemangle: boolean;
|
|
fSingleClick: boolean;
|
|
fastDisplay: boolean;
|
|
fOptions: TCEMessagesOptions;
|
|
fOptionsBackup: TCEMessagesOptions;
|
|
fBtns: array[TCEAppMessageCtxt] of TToolButton;
|
|
fFiltering: boolean;
|
|
function itemShouldBeVisible(item: TTreeNode; aCtxt: TCEAppMessageCtxt): boolean;
|
|
procedure filterMessages(aCtxt: TCEAppMessageCtxt);
|
|
procedure clearOutOfRangeMessg;
|
|
procedure actDemangleExecute(Sender: TObject);
|
|
procedure actAutoSelExecute(Sender: TObject);
|
|
procedure actClearCurCatExecute(Sender: TObject);
|
|
procedure actClearAllExecute(Sender: TObject);
|
|
procedure actSaveMsgExecute(Sender: TObject);
|
|
procedure actCopyMsgExecute(Sender: TObject);
|
|
procedure actSelAllExecute(Sender: TObject);
|
|
procedure setMaxMessageCount(value: Integer);
|
|
procedure setAutoSelectCategory(value: boolean);
|
|
procedure setSingleMessageClick(value: boolean);
|
|
procedure listDeletion(Sender: TObject; Node: TTreeNode);
|
|
procedure selCtxtClick(Sender: TObject);
|
|
function iconIndex(aKind: TCEAppMessageKind): Integer;
|
|
procedure handleMessageClick(Sender: TObject);
|
|
//
|
|
procedure setColorError(value: TColor);
|
|
procedure setColorInfo(value: TColor);
|
|
procedure setColorHint(value: TColor);
|
|
procedure setColorBuble(value: TColor);
|
|
procedure setColorWarning(value: TColor);
|
|
//
|
|
procedure projNew(project: ICECommonProject);
|
|
procedure projClosing(project: ICECommonProject);
|
|
procedure projFocused(project: ICECommonProject);
|
|
procedure projChanged(project: ICECommonProject);
|
|
procedure projCompiling(project: ICECommonProject);
|
|
procedure projCompiled(project: ICECommonProject; success: boolean);
|
|
//
|
|
procedure docNew(document: TCESynMemo);
|
|
procedure docClosing(document: TCESynMemo);
|
|
procedure docFocused(document: TCESynMemo);
|
|
procedure docChanged(document: TCESynMemo);
|
|
//
|
|
function optionedWantCategory(): string;
|
|
function optionedWantEditorKind: TOptionEditorKind;
|
|
function optionedWantContainer: TPersistent;
|
|
procedure optionedEvent(event: TOptionEditorEvent);
|
|
function optionedOptionsModified: boolean;
|
|
//
|
|
function openFileFromDmdMessage(const aMessage: string): boolean;
|
|
function getLineFromMessage(const aMessage: string): TPoint;
|
|
function guessMessageKind(const aMessg: string): TCEAppMessageKind;
|
|
//
|
|
function singleServiceName: string;
|
|
procedure message(const value: string; aData: Pointer; aCtxt: TCEAppMessageCtxt; aKind: TCEAppMessageKind);
|
|
procedure clearbyContext(aCtxt: TCEAppMessageCtxt);
|
|
procedure clearbyData(data: Pointer);
|
|
procedure scrollToBack;
|
|
protected
|
|
procedure setToolBarFlat(value: boolean); override;
|
|
procedure updateLoop; override;
|
|
//
|
|
function contextName: string; override;
|
|
function contextActionCount: integer; override;
|
|
function contextAction(index: integer): TAction; override;
|
|
//
|
|
property maxMessageCount: Integer read fMaxMessCnt write setMaxMessageCount;
|
|
property autoSelectCategory: boolean read fAutoSelect write setAutoSelectCategory;
|
|
property autoDEmangle: boolean read fAutoDemangle write fAutoDemangle;
|
|
property singleMessageClick: boolean read fSingleClick write setSingleMessageClick;
|
|
//
|
|
property colorBuble: TColor read fMsgColors[amkBub] write setColorBuble;
|
|
property colorInfo: TColor read fMsgColors[amkInf] write setColorInfo;
|
|
property colorHint: TColor read fMsgColors[amkHint] write setColorHint;
|
|
property colorWarning: TColor read fMsgColors[amkWarn] write setColorWarning;
|
|
property colorError: TColor read fMsgColors[amkErr] write setColorError;
|
|
public
|
|
constructor create(aOwner: TComponent); override;
|
|
destructor destroy; override;
|
|
end;
|
|
|
|
// Maps an identifier to a message kind
|
|
type messageSemantic = record
|
|
private
|
|
|
|
{
|
|
rendered on 2017-Jan-19 21:11:15.6560057 by IsItThere.
|
|
- PRNG seed: 0
|
|
- map length: 64
|
|
- case sensitive: true
|
|
}
|
|
|
|
const fWords: array [0..63] of string =
|
|
('caution', '', '', '', 'Fatal', 'Critical', 'Error', 'Advice',
|
|
'Warn', '', '', 'advice', '', 'warning', '', 'information',
|
|
'', '', '', 'Exception', '', '', 'illegal', '',
|
|
'', 'Hint', 'errorlevel', 'Warning', 'critical', 'Deprecated', 'Invalid', 'fatal',
|
|
'', 'Deprecation', 'hint', '', '', 'error', '', '',
|
|
'', 'Caution', 'Tip', '', 'deprecated', '', '', 'Suggestion',
|
|
'deprecation', '', 'exception', 'ERROR', 'Information', '', '', '',
|
|
'suggestion', 'invalid', 'warn', 'Illegal', '', '', '', 'tip');
|
|
|
|
const fFilled: array [0..63] of boolean =
|
|
(true, false, false, false, true, true, true, true, true, false, false,
|
|
true, false, true, false, true, false, false, false, true, false, false,
|
|
true, false, false, true, true, true, true, true, true, true, false, true,
|
|
true, false, false, true, false, false, false, true, true, false, true,
|
|
false, false, true, true, false, true, true, true, false, false, false,
|
|
true, true, true, true, false, false, false, true);
|
|
|
|
const fMap: array [0..63] of TCEAppMessageKind =
|
|
( amkWarn, amkBub, amkBub, amkBub, amkErr, amkErr, amkErr, amkHint,
|
|
amkWarn, amkBub, amkBub, amkHint, amkBub, amkWarn, amkBub, amkInf,
|
|
amkBub, amkBub, amkBub, amkErr, amkBub, amkBub, amkErr, amkBub,
|
|
amkBub, amkHint, amkErr, amkWarn, amkErr, amkWarn, amkErr, amkErr,
|
|
amkBub, amkWarn, amkHint, amkBub, amkBub, amkErr, amkBub, amkBub,
|
|
amkBub, amkWarn, amkHint, amkBub, amkWarn, amkBub, amkBub, amkHint,
|
|
amkWarn, amkBub, amkErr, amkErr, amkInf, amkBub, amkBub, amkBub,
|
|
amkHint, amkErr, amkWarn, amkErr, amkBub, amkBub, amkBub, amkHint);
|
|
|
|
const fCoefficients: array [0..255] of Byte =
|
|
(151, 145, 214, 156, 15, 232, 156, 185, 180, 64, 178, 95, 6, 249, 69, 68,
|
|
240, 111, 93, 41, 229, 240, 146, 62, 148, 157, 106, 190, 120, 112, 104,
|
|
207, 85, 123, 228, 254, 43, 2, 236, 108, 39, 221, 41, 251, 144, 192, 247,
|
|
101, 210, 134, 105, 39, 208, 115, 116, 65, 209, 36, 237, 87, 195, 162,
|
|
142, 33, 203, 95, 12, 200, 124, 111, 9, 145, 187, 238, 173, 155, 214,
|
|
127, 229, 197, 232, 87, 213, 92, 39, 25, 218, 24, 193, 223, 45, 35, 157,
|
|
4, 34, 244, 154, 99, 21, 95, 203, 14, 100, 113, 68, 201, 199, 174, 249,
|
|
30, 153, 251, 122, 129, 244, 229, 188, 101, 103, 138, 164, 136, 188, 209,
|
|
164, 192, 76, 159, 40, 182, 137, 202, 107, 115, 9, 23, 14, 166, 47, 71,
|
|
243, 156, 148, 176, 187, 247, 143, 124, 180, 14, 250, 157, 212, 18, 151,
|
|
246, 174, 222, 41, 114, 148, 24, 34, 97, 116, 37, 173, 30, 177, 20, 55,
|
|
18, 15, 149, 94, 129, 87, 72, 25, 3, 82, 200, 198, 214, 49, 228, 10, 39,
|
|
191, 83, 128, 30, 117, 209, 216, 152, 89, 237, 253, 24, 173, 116, 65, 64,
|
|
55, 222, 210, 243, 140, 82, 219, 8, 35, 13, 123, 43, 15, 72, 174, 28, 10,
|
|
242, 74, 136, 18, 198, 247, 240, 196, 146, 49, 39, 175, 186, 38, 8, 110,
|
|
101, 179, 242, 152, 251, 227, 60, 25, 31, 123, 80, 149, 187, 67, 157, 120,
|
|
84, 83, 192);
|
|
|
|
class function hash(const w: string): Word; static;
|
|
public
|
|
class function getType(const w: string): TCEAppMessageKind; static;
|
|
end;
|
|
|
|
implementation
|
|
{$R *.lfm}
|
|
|
|
const
|
|
optname = 'messages.txt';
|
|
minColor = $232323;
|
|
|
|
{$REGION TCEMessagesOptions ----------------------------------------------------}
|
|
constructor TCEMessagesOptions.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
fFont := TFont.Create;
|
|
fFont.Style := [fsBold];
|
|
{$IFDEF WINDOWS}
|
|
fFont.name := 'Consolas';
|
|
{$ENDIF}
|
|
fFont.Size := ScaleY(11,96);
|
|
fAutoSelect :=true;
|
|
fMaxCount := 1000;
|
|
fMsgColors[amkBub] := $FCE7D2;
|
|
fMsgColors[amkWarn]:= $B3FFFF;
|
|
fMsgColors[amkErr] := $BDBDFF;
|
|
fMsgColors[amkInf] := $FFD0A8;
|
|
fMsgColors[amkHint]:= $C2FFC2;
|
|
end;
|
|
|
|
destructor TCEMessagesOptions.destroy;
|
|
begin
|
|
fFont.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCEMessagesOptions.setFont(value: TFont);
|
|
begin
|
|
fFont.Assign(value);
|
|
end;
|
|
|
|
procedure TCEMessagesOptions.assign(source: TPersistent);
|
|
var
|
|
widg : TCEMessagesWidget;
|
|
opts : TCEMessagesOptions;
|
|
begin
|
|
if source is TCEMessagesOptions then
|
|
begin
|
|
opts := TCEMessagesOptions(source);
|
|
fFont.BeginUpdate;
|
|
fFont.Assign(opts.font);
|
|
fMaxCount := opts.fMaxCount;
|
|
fAutoSelect := opts.fAutoSelect;
|
|
fAutoDemangle:= opts.fAutoDemangle;
|
|
fSingleClick := opts.fSingleClick;
|
|
fFastDisplay := opts.fFastDisplay;
|
|
fMsgColors := opts.fMsgColors;
|
|
fAlwaysFilter := opts.fAlwaysFilter;
|
|
fFont.EndUpdate;
|
|
end
|
|
else if source is TCEMessagesWidget then
|
|
begin
|
|
widg := TCEMessagesWidget(source);
|
|
fFont.Assign(widg.List.Font);
|
|
fMaxCount := widg.fMaxMessCnt;
|
|
fAutoSelect := widg.fAutoSelect;
|
|
fSingleClick := widg.fSingleClick;
|
|
fFastDisplay := widg.fastDisplay;
|
|
fMsgColors := widg.fMsgColors;
|
|
fAutoDemangle:= widg.fAutoDemangle;
|
|
fAlwaysFilter:=widg.fAlwaysFilter;
|
|
end
|
|
else inherited;
|
|
end;
|
|
|
|
procedure TCEMessagesOptions.AssignTo(target: TPersistent);
|
|
var
|
|
widg : TCEMessagesWidget;
|
|
begin
|
|
if target is TCEMessagesWidget then
|
|
begin
|
|
widg := TCEMessagesWidget(target);
|
|
widg.List.Font.Assign(fFont);
|
|
widg.maxMessageCount := fMaxCount;
|
|
widg.autoSelectCategory := fAutoSelect;
|
|
widg.singleMessageClick := fSingleClick;
|
|
widg.fastDisplay:= fFastDisplay;
|
|
widg.fMsgColors := fMsgColors;
|
|
widg.fAutoDemangle:=fAutoDemangle;
|
|
widg.fAlwaysFilter:=fAlwaysFilter;
|
|
if fFastDisplay then
|
|
widg.updaterByLoopInterval:= 70
|
|
else
|
|
widg.updaterByLoopInterval:= 0;
|
|
end
|
|
else inherited;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION Standard Comp/Obj------------------------------------------------------}
|
|
constructor TCEMessagesWidget.create(aOwner: TComponent);
|
|
var
|
|
fname: string;
|
|
begin
|
|
fMaxMessCnt := 500;
|
|
fAutoSelect := true;
|
|
fCtxt := amcAll;
|
|
|
|
fActAutoSel := TAction.Create(self);
|
|
fActAutoSel.Caption := 'Auto select message category';
|
|
fActAutoSel.AutoCheck := true;
|
|
fActAutoSel.OnExecute := @actAutoSelExecute;
|
|
fActClearAll := TAction.Create(self);
|
|
fActClearAll.OnExecute := @actClearAllExecute;
|
|
fActClearAll.caption := 'Clear all messages';
|
|
fActClearCurCat := TAction.Create(self);
|
|
fActClearCurCat.OnExecute := @actClearCurCatExecute;
|
|
fActClearCurCat.caption := 'Clear filtered messages';
|
|
fActCopyMsg := TAction.Create(self);
|
|
fActCopyMsg.OnExecute := @actCopyMsgExecute;
|
|
fActCopyMsg.Caption := 'Copy message(s)';
|
|
fActSelAll := TAction.Create(self);
|
|
fActSelAll.OnExecute := @actSelAllExecute;
|
|
fActSelAll.Caption := 'Select all';
|
|
fActSaveMsg := TAction.Create(self);
|
|
fActSaveMsg.OnExecute := @actSaveMsgExecute;
|
|
fActSaveMsg.caption := 'Save selected message(s) to...';
|
|
fActDemangle := TAction.Create(self);
|
|
fActDemangle.OnExecute := @actDemangleExecute;
|
|
fActDemangle.caption := 'Demangle selection';
|
|
|
|
inherited;
|
|
|
|
fImages:= TImageList.Create(self);
|
|
Case GetIconScaledSize of
|
|
iss16:
|
|
begin
|
|
fImages.Width:=16;
|
|
fImages.Height:=16;
|
|
AssignPng(TreeFilterEdit1.Glyph, 'FILTER_CLEAR');
|
|
fImages.AddResourceName(HINSTANCE, 'BALLOON');
|
|
fImages.AddResourceName(HINSTANCE, 'INFORMATION');
|
|
fImages.AddResourceName(HINSTANCE, 'LIGHTBULB_OFF');
|
|
fImages.AddResourceName(HINSTANCE, 'WARNING');
|
|
fImages.AddResourceName(HINSTANCE, 'EXCLAMATION');
|
|
end;
|
|
iss24:
|
|
begin
|
|
fImages.Width:=24;
|
|
fImages.Height:=24;
|
|
AssignPng(TreeFilterEdit1.Glyph, 'FILTER_CLEAR24');
|
|
fImages.AddResourceName(HINSTANCE, 'BALLOON24');
|
|
fImages.AddResourceName(HINSTANCE, 'INFORMATION24');
|
|
fImages.AddResourceName(HINSTANCE, 'LIGHTBULB_OFF24');
|
|
fImages.AddResourceName(HINSTANCE, 'WARNING24');
|
|
fImages.AddResourceName(HINSTANCE, 'EXCLAMATION24');
|
|
end;
|
|
iss32:
|
|
begin
|
|
fImages.Width:=32;
|
|
fImages.Height:=32;
|
|
AssignPng(TreeFilterEdit1.Glyph, 'FILTER_CLEAR32');
|
|
fImages.AddResourceName(HINSTANCE, 'BALLOON32');
|
|
fImages.AddResourceName(HINSTANCE, 'INFORMATION32');
|
|
fImages.AddResourceName(HINSTANCE, 'LIGHTBULB_OFF32');
|
|
fImages.AddResourceName(HINSTANCE, 'WARNING32');
|
|
fImages.AddResourceName(HINSTANCE, 'EXCLAMATION32');
|
|
end;
|
|
end;
|
|
List.Images := fImages;
|
|
List.DefaultItemHeight:= ScaleY(22,96);
|
|
|
|
fMsgColors[amkBub] := $FCE7D2;
|
|
fMsgColors[amkWarn] := $B3FFFF;
|
|
fMsgColors[amkErr] := $BDBDFF;
|
|
fMsgColors[amkInf] := $FFD0A8;
|
|
fMsgColors[amkHint] := $C2FFC2;
|
|
|
|
updaterByLoopInterval := 12;
|
|
fOptions := TCEMessagesOptions.Create(Self);
|
|
fOptions.assign(self);
|
|
fOptions.Name:= 'messageOptions';
|
|
fOptionsBackup := TCEMessagesOptions.Create(Self);
|
|
|
|
List.PopupMenu := contextMenu;
|
|
List.OnDeletion := @ListDeletion;
|
|
List.OnDblClick := @handleMessageClick;
|
|
|
|
btnSelProj.OnClick := @selCtxtClick;
|
|
btnSelMisc.OnClick := @selCtxtClick;
|
|
btnSelEdit.OnClick := @selCtxtClick;
|
|
btnSelApp.OnClick := @selCtxtClick;
|
|
btnSelAll.OnClick := @selCtxtClick;
|
|
fBtns[amcAll] := btnSelAll;
|
|
fBtns[amcApp] := btnSelApp;
|
|
fBtns[amcEdit]:= btnSelEdit;
|
|
fBtns[amcMisc]:= btnSelMisc;
|
|
fBtns[amcProj]:= btnSelProj;
|
|
|
|
btnClearCat.OnClick := @actClearCurCatExecute;
|
|
|
|
fEditorMessagePos := TCEEditorMessagePos.Create;
|
|
|
|
fname := getCoeditDocPath + optname;
|
|
if fname.fileExists then
|
|
begin
|
|
fOptions.loadFromFile(fname);
|
|
fOptions.AssignTo(self);
|
|
end;
|
|
|
|
EntitiesConnector.addObserver(self);
|
|
EntitiesConnector.addSingleService(self);
|
|
end;
|
|
|
|
destructor TCEMessagesWidget.destroy;
|
|
begin
|
|
fEditorMessagePos.Free;
|
|
fOptions.saveToFile(getCoeditDocPath + optname);
|
|
EntitiesConnector.removeObserver(self);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setToolBarFlat(value: boolean);
|
|
begin
|
|
inherited setToolBarFlat(value);
|
|
TreeFilterEdit1.Flat:=value;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.listDeletion(Sender: TObject; Node: TTreeNode);
|
|
begin
|
|
if node.data.isNotNil then
|
|
Dispose(PMessageData(Node.Data));
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.ListKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
case Key of
|
|
VK_BACK, VK_DELETE:
|
|
begin
|
|
if List.SelectionCount > 0 then
|
|
begin
|
|
for i := List.Items.Count-1 downto 0 do
|
|
if List.Items[i].MultiSelected then
|
|
List.Items.Delete(List.Items[i]);
|
|
end
|
|
else clearbyContext(amcAll);
|
|
end;
|
|
VK_UP, VK_DOWN:
|
|
if fOptions.singleMessageClick then handleMessageClick(nil);
|
|
VK_RETURN:
|
|
handleMessageClick(nil);
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.TreeFilterEdit1AfterFilter(Sender: TObject);
|
|
begin
|
|
fFiltering := TreeFilterEdit1.Filter.isNotEmpty;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.TreeFilterEdit1ButtonClick(Sender: TObject);
|
|
begin
|
|
fFiltering := false;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.selCtxtClick(Sender: TObject);
|
|
var
|
|
btn: TToolButton;
|
|
i: Integer;
|
|
begin
|
|
if sender.isNil then
|
|
exit;
|
|
//
|
|
fCtxt := amcAll;
|
|
btn := TToolButton(Sender);
|
|
for i := 0 to toolbar.ButtonCount-1 do
|
|
toolbar.Buttons[i].Down := toolbar.Buttons[i] = btn;
|
|
if btn = btnSelAll then
|
|
fCtxt := amcAll
|
|
else if btn = btnSelEdit then
|
|
fCtxt := amcEdit
|
|
else if btn = btnSelProj then
|
|
fCtxt := amcProj
|
|
else if btn = btnSelApp then
|
|
fCtxt := amcApp
|
|
else if btn = btnSelMisc then
|
|
fCtxt := amcMisc;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setMaxMessageCount(value: Integer);
|
|
begin
|
|
if value < 5 then
|
|
value := 5;
|
|
if fMaxMessCnt = value then
|
|
exit;
|
|
fMaxMessCnt := value;
|
|
clearOutOfRangeMessg;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setAutoSelectCategory(value: boolean);
|
|
begin
|
|
fAutoSelect := value;
|
|
fActAutoSel.Checked:= fAutoSelect;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setSingleMessageClick(value: boolean);
|
|
begin
|
|
fSingleClick := value;
|
|
if fSingleClick then
|
|
begin
|
|
List.OnClick := @handleMessageClick;
|
|
List.OnDblClick:= nil;
|
|
end else begin
|
|
List.OnClick := nil;
|
|
List.OnDblClick:= @handleMessageClick;
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setColorError(value: TColor);
|
|
begin
|
|
fMsgColors[amkErr] := max(value, minColor);
|
|
List.Invalidate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setColorInfo(value: TColor);
|
|
begin
|
|
fMsgColors[amkInf] := max(value, minColor);
|
|
List.Invalidate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setColorHint(value: TColor);
|
|
begin
|
|
fMsgColors[amkHint] := max(value, minColor);
|
|
List.Invalidate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setColorBuble(value: TColor);
|
|
begin
|
|
fMsgColors[amkBub] := max(value, minColor);
|
|
List.Invalidate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.setColorWarning(value: TColor);
|
|
begin
|
|
fMsgColors[amkWarn] := value;
|
|
List.Invalidate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.ListCustomDrawItem(Sender: TCustomTreeView;
|
|
Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
|
|
var
|
|
x: integer;
|
|
rc: TRect;
|
|
begin
|
|
rc := node.DisplayRect(false);
|
|
x := rc.Left + 2 - TTreeHack(list).ScrolledLeft;
|
|
// warning: the cast may become wrong if the enum is modified.
|
|
Sender.Canvas.Brush.Color := fMsgColors[TCEAppMessageKind(node.ImageIndex + 1)];
|
|
if node.Selected then
|
|
begin
|
|
Sender.Canvas.DrawFocusRect(rc);
|
|
Sender.Canvas.Brush.Color := Sender.Canvas.Brush.Color - minColor;
|
|
end;
|
|
Sender.Canvas.FillRect(rc);
|
|
list.Images.Draw(sender.Canvas, x, (rc.Top + rc.Bottom - list.Images.Height) div 2,
|
|
node.ImageIndex, Node.NodeEffect);
|
|
x += list.Images.Width + 5;
|
|
Sender.Canvas.TextOut(x, rc.Top, node.Text);
|
|
DefaultDraw := false;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION ICEEditableOptions ----------------------------------------------------}
|
|
function TCEMessagesWidget.optionedWantCategory(): string;
|
|
begin
|
|
exit('Messages');
|
|
end;
|
|
|
|
function TCEMessagesWidget.optionedWantEditorKind: TOptionEditorKind;
|
|
begin
|
|
exit(oekGeneric);
|
|
end;
|
|
|
|
function TCEMessagesWidget.optionedWantContainer: TPersistent;
|
|
begin
|
|
fOptions.assign(self);
|
|
fOptionsBackup.assign(self);
|
|
exit(fOptions);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.optionedEvent(event: TOptionEditorEvent);
|
|
begin
|
|
case event of
|
|
oeeAccept, oeeSelectCat:
|
|
fOptionsBackup.assign(fOptions);
|
|
oeeCancel:
|
|
fOptions.assign(fOptionsBackup);
|
|
end;
|
|
fOptions.AssignTo(self);
|
|
List.Invalidate;
|
|
end;
|
|
|
|
function TCEMessagesWidget.optionedOptionsModified: boolean;
|
|
begin
|
|
exit(false);
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION ICEContextualActions---------------------------------------------------}
|
|
function TCEMessagesWidget.contextName: string;
|
|
begin
|
|
result := 'Messages';
|
|
end;
|
|
|
|
function TCEMessagesWidget.contextActionCount: integer;
|
|
begin
|
|
result := 7;
|
|
end;
|
|
|
|
function TCEMessagesWidget.contextAction(index: integer): TAction;
|
|
begin
|
|
case index of
|
|
0: result := fActAutoSel;
|
|
1: result := fActClearAll;
|
|
2: result := fActClearCurCat;
|
|
3: result := fActCopyMsg;
|
|
4: result := fActSelAll;
|
|
5: result := fActSaveMsg;
|
|
6: result := fActDemangle;
|
|
else result := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actDemangleExecute(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:= 0 to List.SelectionCount-1 do
|
|
list.Selections[i].Text := demangle(list.Selections[i].Text);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actAutoSelExecute(Sender: TObject);
|
|
begin
|
|
fAutoSelect := fActAutoSel.Checked;
|
|
fOptions.autoSelect:=fAutoSelect;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actClearAllExecute(Sender: TObject);
|
|
begin
|
|
clearbyContext(amcAll);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actClearCurCatExecute(Sender: TObject);
|
|
begin
|
|
case fCtxt of
|
|
amcAll, amcApp, amcMisc :
|
|
clearbyContext(fCtxt);
|
|
amcEdit: if fDoc.isNotNil then
|
|
clearbyData(fDoc);
|
|
amcProj: if fProj <> nil then
|
|
clearbyData(fProj);
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actCopyMsgExecute(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
str: string = '';
|
|
begin
|
|
for i := 0 to List.Items.Count-1 do
|
|
if List.Items[i].MultiSelected then
|
|
str += List.Items[i].Text + LineEnding;
|
|
Clipboard.AsText := str;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actSelAllExecute(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
List.BeginUpdate;
|
|
for i := 0 to List.Items.Count-1 do
|
|
if List.Items[i].Visible then
|
|
List.Items[i].MultiSelected := true;
|
|
List.EndUpdate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.actSaveMsgExecute(Sender: TObject);
|
|
var
|
|
lst: TStringList;
|
|
itm: TtreeNode;
|
|
begin
|
|
with TSaveDialog.Create(nil) do
|
|
try
|
|
if execute then
|
|
begin
|
|
lst := TStringList.Create;
|
|
try
|
|
for itm in List.Items do
|
|
lst.Add(itm.Text);
|
|
lst.SaveToFile(filename.normalizePath);
|
|
finally
|
|
lst.Free;
|
|
end;
|
|
end;
|
|
finally
|
|
free;
|
|
end;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION ICEProjectObserver ----------------------------------------------------}
|
|
procedure TCEMessagesWidget.projNew(project: ICECommonProject);
|
|
begin
|
|
fProj := project;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.projClosing(project: ICECommonProject);
|
|
begin
|
|
if fProj <> project then
|
|
exit;
|
|
//
|
|
clearbyData(fProj);
|
|
fProj := nil;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.projFocused(project: ICECommonProject);
|
|
begin
|
|
if fProj = project then exit;
|
|
fProj := project;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.projChanged(project: ICECommonProject);
|
|
begin
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.projCompiling(project: ICECommonProject);
|
|
begin
|
|
fProjCompile := true;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.projCompiled(project: ICECommonProject; success: boolean);
|
|
begin
|
|
fProjCompile := false;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION ICEDocumentObserver ---------------------------------------------------}
|
|
procedure TCEMessagesWidget.docNew(document: TCESynMemo);
|
|
begin
|
|
|
|
if fDoc.isNotNil and fOptions.fAutoSelect and (fCtxt = amcEdit) then
|
|
begin
|
|
if list.Selected.isNotNil then
|
|
fEditorMessagePos[fDoc.fileName] := list.Selected.Index
|
|
else
|
|
fEditorMessagePos[fDoc.fileName] := -1;
|
|
end;
|
|
|
|
fDoc := document;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.docClosing(document: TCESynMemo);
|
|
begin
|
|
if document <> fDoc then exit;
|
|
clearbyData(fDoc);
|
|
fEditorMessagePos.Remove(fDoc.fileName);
|
|
fDoc := nil;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.docFocused(document: TCESynMemo);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if fDoc = document then exit;
|
|
|
|
if fDoc.isNotNil and fOptions.fAutoSelect and (fCtxt = amcEdit) then
|
|
begin
|
|
if list.Selected.isNotNil then
|
|
fEditorMessagePos[fDoc.fileName] := list.Selected.Index
|
|
else
|
|
fEditorMessagePos[fDoc.fileName] := -1;
|
|
end;
|
|
|
|
fDoc := document;
|
|
filterMessages(fCtxt);
|
|
|
|
if fOptions.fAutoSelect and (fCtxt = amcEdit) then
|
|
begin
|
|
i := fEditorMessagePos.IndexOf(fDoc.fileName);
|
|
if i <> -1 then
|
|
begin
|
|
i := fEditorMessagePos.Data[i];
|
|
if (i <> -1) and (i < list.Items.Count) then
|
|
begin
|
|
list.Selected := list.Items[i];
|
|
list.Selected.MakeVisible;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.docChanged(document: TCESynMemo);
|
|
begin
|
|
fDoc := document;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION ICEMessagesDisplay ----------------------------------------------------}
|
|
function TCEMessagesWidget.singleServiceName: string;
|
|
begin
|
|
exit('ICEMessagesDisplay');
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.message(const value: string; aData: Pointer;
|
|
aCtxt: TCEAppMessageCtxt; aKind: TCEAppMessageKind);
|
|
var
|
|
dt: PMessageData;
|
|
item: TTreeNode;
|
|
msg: string;
|
|
begin
|
|
showWidget;
|
|
if not fAlwaysFilter then
|
|
TreeFilterEdit1.Filter:='';
|
|
case fAutoDemangle of
|
|
false: msg := value;
|
|
true: msg := demangle(value);
|
|
end;
|
|
if aKind = amkAuto then
|
|
aKind := guessMessageKind(msg);
|
|
if aCtxt = amcAutoCompile then
|
|
begin
|
|
case fProjCompile of
|
|
false: aCtxt := amcAutoEdit;
|
|
true: aCtxt := amcAutoProj;
|
|
end;
|
|
end;
|
|
if aCtxt = amcAutoEdit then
|
|
begin
|
|
aData := fDoc;
|
|
aCtxt := amcEdit;
|
|
end
|
|
else if aCtxt = amcAutoProj then
|
|
begin
|
|
aData := fProj;
|
|
aCtxt := amcProj;
|
|
end;
|
|
dt := new(PMessageData);
|
|
dt^.data := aData;
|
|
dt^.ctxt := aCtxt;
|
|
if fAutoSelect then if fCtxt <> aCtxt then
|
|
fBtns[aCtxt].Click;
|
|
if fastDisplay then
|
|
IncLoopUpdate;
|
|
item := List.Items.AddObject(nil, msg, dt);
|
|
item.ImageIndex := iconIndex(aKind);
|
|
item.SelectedIndex := item.ImageIndex;
|
|
if not fastDisplay then
|
|
begin
|
|
clearOutOfRangeMessg;
|
|
scrollToBack;
|
|
TTreeHack(list).scrolledLeft := 0;
|
|
List.Update;
|
|
filterMessages(fCtxt);
|
|
end
|
|
else if fAlwaysFilter and fFiltering then
|
|
begin
|
|
filterMessages(fCtxt);
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.clearByContext(aCtxt: TCEAppMessageCtxt);
|
|
var
|
|
i: Integer;
|
|
msgdt: PMessageData;
|
|
begin
|
|
list.BeginUpdate;
|
|
TreeFilterEdit1.Filter := '';
|
|
if aCtxt = amcAll then
|
|
List.Items.Clear
|
|
else for i := List.Items.Count-1 downto 0 do
|
|
begin
|
|
msgdt := PMessageData(List.Items[i].Data);
|
|
if msgdt^.ctxt = aCtxt then
|
|
List.Items.Delete(List.Items[i]);
|
|
end;
|
|
list.EndUpdate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.clearByData(data: Pointer);
|
|
var
|
|
i: Integer;
|
|
msgdt: PMessageData;
|
|
begin
|
|
if data.isNil then
|
|
exit;
|
|
if (TObject(data) = fDoc) and (fDoc.isNotNil) then
|
|
fEditorMessagePos[fDoc.fileName] := -1;
|
|
list.BeginUpdate;
|
|
TreeFilterEdit1.Filter := '';
|
|
for i := List.Items.Count-1 downto 0 do
|
|
begin
|
|
msgdt := PMessageData(List.Items[i].Data);
|
|
if (msgdt^.data = data) then
|
|
List.Items.Delete(List.Items[i]);
|
|
end;
|
|
list.EndUpdate;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION Messages --------------------------------------------------------------}
|
|
procedure TCEMessagesWidget.updateLoop;
|
|
begin
|
|
if fastDisplay then
|
|
begin
|
|
clearOutOfRangeMessg;
|
|
scrollToBack;
|
|
List.Update;
|
|
filterMessages(fCtxt);
|
|
end;
|
|
end;
|
|
|
|
function TCEMessagesWidget.iconIndex(aKind: TCEAppMessageKind): Integer;
|
|
begin
|
|
case aKind of
|
|
amkBub: exit(0);
|
|
amkInf: exit(1);
|
|
amkHint: exit(2);
|
|
amkWarn: exit(3);
|
|
amkErr: exit(4);
|
|
else exit(0);
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.clearOutOfRangeMessg;
|
|
begin
|
|
list.BeginUpdate;
|
|
while List.Items.Count > fMaxMessCnt do
|
|
List.Items.Delete(List.Items.GetFirstNode);
|
|
list.EndUpdate;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.scrollToBack;
|
|
begin
|
|
if not Visible then
|
|
exit;
|
|
if List.BottomItem.isNotNil then
|
|
List.BottomItem.MakeVisible;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.handleMessageClick(Sender: TObject);
|
|
var
|
|
pos: TPoint;
|
|
msg: string;
|
|
dat: PMessageData;
|
|
old: TCESynMemo;
|
|
begin
|
|
if List.Selected.isNil then
|
|
exit;
|
|
if ssCtrl in GetKeyShiftState then
|
|
exit;
|
|
old := fDoc;
|
|
msg := List.Selected.Text;
|
|
dat := PMessageData(List.Selected.Data);
|
|
if not openFileFromDmdMessage(msg) then
|
|
exit;
|
|
|
|
// fixes strange bug : https://github.com/BBasile/Coedit/issues/320
|
|
if (fDoc <> old) and fOptions.singleMessageClick and
|
|
assigned(dat) and (dat^.ctxt = amcEdit) then
|
|
List.ClearSelection(false);
|
|
|
|
// from here, since a doc has the focus, List.Selected is nil
|
|
pos := getLineFromMessage(msg);
|
|
if fDoc.isNil then
|
|
exit;
|
|
fDoc.setFocus;
|
|
fDoc.CaretXY := pos;
|
|
fDoc.SelectLine;
|
|
end;
|
|
|
|
function TCEMessagesWidget.itemShouldBeVisible(item: TTreeNode;
|
|
aCtxt: TCEAppMessageCtxt): boolean;
|
|
var
|
|
msgDt: PMessageData;
|
|
begin
|
|
result := false;
|
|
msgDt := PMessageData(item.Data);
|
|
if (not assigned(msgDt)) then
|
|
exit;
|
|
if aCtxt = amcAll then
|
|
result := true
|
|
else case msgDt^.ctxt of
|
|
amcEdit: result := (fDoc = TCESynMemo(msgDt^.data)) and (aCtxt = amcEdit);
|
|
amcProj: result := (fProj = ICECommonProject(msgDt^.data)) and (aCtxt = amcProj);
|
|
amcApp: result := aCtxt = amcApp;
|
|
amcMisc: result := aCtxt = amcMisc;
|
|
end;
|
|
end;
|
|
|
|
procedure TCEMessagesWidget.filterMessages(aCtxt: TCEAppMessageCtxt);
|
|
var
|
|
itm: TTreeNode;
|
|
i: integer;
|
|
begin
|
|
if updating then
|
|
exit;
|
|
List.BeginUpdate;
|
|
for i := 0 to List.Items.Count-1 do
|
|
begin
|
|
itm := List.Items.Item[i];
|
|
if fFiltering then
|
|
itm.Visible := itemShouldBeVisible(itm, aCtxt) and
|
|
AnsiContainsText(itm.Text, TreeFilterEdit1.Filter)
|
|
else
|
|
itm.Visible:= itemShouldBeVisible(itm, aCtxt);
|
|
itm.Selected := false;
|
|
end;
|
|
list.EndUpdate;
|
|
end;
|
|
|
|
class function messageSemantic.hash(const w: string): Word;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 1 to length(w) do
|
|
Result += fCoefficients[Byte(w[i])];
|
|
Result := Result and $3F;
|
|
end;
|
|
|
|
class function messageSemantic.getType(const w: string): TCEAppMessageKind;
|
|
var
|
|
h: Word;
|
|
begin
|
|
result := amkBub;
|
|
h := hash(w);
|
|
if fFilled[h] and (fWords[h] = w) then
|
|
result := fMap[h];
|
|
end;
|
|
|
|
function TCEMessagesWidget.guessMessageKind(const aMessg: string): TCEAppMessageKind;
|
|
var
|
|
idt: string;
|
|
rng: TStringRange = (ptr:nil; pos:0; len: 0);
|
|
const
|
|
alp = ['a'..'z', 'A'..'Z', '_'];
|
|
begin
|
|
result := amkBub;
|
|
rng.init(aMessg);
|
|
while true do
|
|
begin
|
|
if rng.empty then
|
|
break;
|
|
idt := rng.popUntil(alp)^.takeWhile(alp).yield;
|
|
if idt = '' then
|
|
exit;
|
|
result := messageSemantic.getType(idt);
|
|
if result <> amkBub then
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
function TCEMessagesWidget.getLineFromMessage(const aMessage: string): TPoint;
|
|
var
|
|
rng: TStringRange = (ptr:nil; pos:0; len: 0);
|
|
lne: string;
|
|
col: string = '';
|
|
begin
|
|
Result := Point(-1,-1);
|
|
if aMessage.isEmpty then
|
|
exit;
|
|
rng.init(aMessage);
|
|
{$IFDEF WINDOWS}
|
|
if (aMessage.length > 3) and (aMessage[2..3] = ':\') then
|
|
rng.popFrontN(3);
|
|
{$ENDIF}
|
|
rng.popUntil(['(', ':'])^.popWhile(['(', ':']);
|
|
lne := rng.takeUntil([',', ':', ')', ' ']).yield;
|
|
if rng.front in [',', ':'] then
|
|
col := rng.popWhile([',', ':'])^.takeUntil(')').yield;
|
|
result.y := strToIntDef(lne, -1);
|
|
result.x := strToIntDef(col, -1);
|
|
end;
|
|
|
|
function TCEMessagesWidget.openFileFromDmdMessage(const aMessage: string): boolean;
|
|
var
|
|
i: integer = 0;
|
|
ident: string = '';
|
|
absName: string;
|
|
begin
|
|
result := false;
|
|
while (true) do
|
|
begin
|
|
inc(i);
|
|
if i > aMessage.length then
|
|
exit;
|
|
// '(': line will be indicated after fname
|
|
// -mixin: dmd, error in mixin(token string) '<fname>-mixinXX<index>('
|
|
if isEditable(ident.extractFileExt) and
|
|
((aMessage[i] = '(') or (aMessage[i] = ':') or
|
|
((aMessage[i] = '-') and (i < aMessage.length-5) and (aMessage[i..i+5] = '-mixin'))) then
|
|
begin
|
|
// relative fname if project file is the base path to a rel. fname
|
|
absName := ExpandFileName(ident);
|
|
if absName.fileExists then
|
|
begin
|
|
getMultiDocHandler.openDocument(absName);
|
|
exit(true);
|
|
end;
|
|
// absolute fname
|
|
if ident.fileExists then
|
|
begin
|
|
getMultiDocHandler.openDocument(ident);
|
|
exit(true);
|
|
end;
|
|
// if fname relative to project path
|
|
if fProj <> nil then
|
|
begin
|
|
absName := expandFilenameEx(fProj.filename.extractFileDir + DirectorySeparator, ident);
|
|
if absName.fileExists then
|
|
begin
|
|
getMultiDocHandler.openDocument(absName);
|
|
exit(true);
|
|
end;
|
|
end;
|
|
// finally try using pwd ...
|
|
absName := expandFilenameEx(GetCurrentDir, ident);
|
|
if absName.fileExists then
|
|
begin
|
|
getMultiDocHandler.openDocument(absName);
|
|
exit(true);
|
|
end;
|
|
// ... and $HOME
|
|
absName := expandFilenameEx(GetUserDir, ident);
|
|
if absName.fileExists then
|
|
begin
|
|
getMultiDocHandler.openDocument(absName);
|
|
exit(true);
|
|
end;
|
|
end
|
|
// <assertion failure messg>@<filename>
|
|
else if aMessage[i] = '@' then
|
|
ident := ''
|
|
else
|
|
ident += aMessage[i];
|
|
end;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
end.
|