mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-27 10:07:40 +00:00
[Developer] Rewrite web editor integration to use Monaco instead of ACE
This commit is contained in:
parent
532bcee7c5
commit
79d45eff40
6 changed files with 319 additions and 272 deletions
|
|
@ -57,20 +57,40 @@ unit UfrmDebug; // I3323 // I3306
|
|||
interface
|
||||
|
||||
uses
|
||||
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
||||
ExtCtrls, Grids, ComCtrls, CaptionPanel, Buttons,
|
||||
StdCtrls, debugging, debugkeyboard, UfrmMDIEditor, PaintPanel, Menus,
|
||||
HintLabel, debugdeadkeys, UserMessages,
|
||||
UframeTextEditor,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
System.SysUtils,
|
||||
Vcl.AppEvnts,
|
||||
Vcl.Buttons,
|
||||
Vcl.ComCtrls,
|
||||
Vcl.Controls,
|
||||
Vcl.Dialogs,
|
||||
Vcl.ExtCtrls,
|
||||
Vcl.Forms,
|
||||
Vcl.Graphics,
|
||||
Vcl.Grids,
|
||||
Vcl.Menus,
|
||||
Vcl.StdCtrls,
|
||||
Winapi.Messages,
|
||||
Winapi.Windows,
|
||||
|
||||
CaptionPanel,
|
||||
debugdeadkeys,
|
||||
debugging,
|
||||
debugkeyboard,
|
||||
DebugUtils,
|
||||
keymanapi_TLB, msctf, UfrmTike,
|
||||
KeymanDeveloperDebuggerMemo;
|
||||
HintLabel,
|
||||
PaintPanel,
|
||||
keymanapi_TLB,
|
||||
KeymanDeveloperDebuggerMemo,
|
||||
msctf,
|
||||
UframeTextEditor,
|
||||
UfrmMDIEditor,
|
||||
UfrmTike,
|
||||
UserMessages;
|
||||
|
||||
type
|
||||
TUpdateParColourEvent = procedure(Sender: TObject; ALine: Integer; ALineType: TParColourLineType) of object;
|
||||
|
||||
TBreakpointRange = 0..99;
|
||||
TDebugLineEvent = procedure(Sender: TObject; ALine: Integer) of object;
|
||||
|
||||
TDebugUIStatus = (duiInvalid, duiPaused, duiFocusedForInput, duiReadyForInput, duiReceivingEvents, duiDebugging,
|
||||
duiClosing, duiDebuggingOutput, duiTest);
|
||||
|
|
@ -87,6 +107,8 @@ type
|
|||
property TrueLineNumber: Integer read GetTrueLineNumber write SetTrueLineNumber;
|
||||
end;
|
||||
|
||||
TDebugBreakpoints = class(TObjectList<TDebugBreakpoint>);
|
||||
|
||||
TfrmDebug = class(TTikeForm)
|
||||
memo: TKeymanDeveloperDebuggerMemo;
|
||||
mnuPopup: TPopupMenu; // I4796
|
||||
|
|
@ -115,7 +137,7 @@ type
|
|||
private
|
||||
|
||||
FDebugVisible: Boolean;
|
||||
FBreakpoint: array[TBreakpointRange] of TDebugBreakpoint;
|
||||
FBreakpoints: TDebugBreakpoints;
|
||||
FRunning, FFoundBreakpoint, FForceKeyboard: Boolean;
|
||||
FFileName: string;
|
||||
//FEditor: TfrmTikeEditor;
|
||||
|
|
@ -163,8 +185,6 @@ type
|
|||
|
||||
procedure KeymanGetContext(var Message: TMessage);
|
||||
|
||||
procedure UpdateParColour(Line: Integer; LineType: TParColourLineType);
|
||||
|
||||
procedure AddDebug(s: WideString);
|
||||
|
||||
{ Debug panel functions }
|
||||
|
|
@ -174,10 +194,13 @@ type
|
|||
private
|
||||
FANSITest: Boolean;
|
||||
FEditorMemo: TframeTextEditor;
|
||||
FOnUpdateParColour: TUpdateParColourEvent;
|
||||
|
||||
FDebugFileName: WideString;
|
||||
FSingleStepMode: Boolean;
|
||||
FCanDebug: Boolean;
|
||||
FOnUpdateExecutionPoint: TDebugLineEvent;
|
||||
FOnClearBreakpoint: TDebugLineEvent;
|
||||
FOnSetBreakpoint: TDebugLineEvent;
|
||||
procedure SetANSITest(const Value: Boolean);
|
||||
procedure UpdateANSITest;
|
||||
procedure ClearDeadkeys;
|
||||
|
|
@ -216,13 +239,14 @@ type
|
|||
|
||||
procedure SetBreakpoint(ALine: Integer);
|
||||
procedure ClearBreakpoint(ALine: Integer);
|
||||
procedure ToggleBreakpoint(ALine: Integer);
|
||||
|
||||
function IsBreakPointLine(ALine: Integer): Boolean;
|
||||
function IsExecutionPointLine(ALine: Integer): Boolean;
|
||||
|
||||
function GetDebugKeyboard: TDebugKeyboard;
|
||||
|
||||
property CanDebug: Boolean read FCanDebug write FCanDebug;
|
||||
property CanDebug: Boolean read FCanDebug write FCanDebug;
|
||||
property UIStatus: TDebugUIStatus read FUIStatus write SetUIStatus;
|
||||
|
||||
property SingleStepMode: Boolean read FSingleStepMode write SetSingleStepMode;
|
||||
|
|
@ -250,7 +274,9 @@ type
|
|||
|
||||
property CurrentEvent: TDebugEvent read GetCurrentEvent;
|
||||
|
||||
property OnUpdateParColour: TUpdateParColourEvent read FOnUpdateParColour write FOnUpdateParColour;
|
||||
property OnSetBreakpoint: TDebugLineEvent read FOnSetBreakpoint write FOnSetBreakpoint;
|
||||
property OnClearBreakpoint: TDebugLineEvent read FOnClearBreakpoint write FOnClearBreakpoint;
|
||||
property OnUpdateExecutionPoint: TDebugLineEvent read FOnUpdateExecutionPoint write FOnUpdateExecutionPoint;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -317,6 +343,7 @@ begin
|
|||
// InitMSCTF; // I3655
|
||||
|
||||
TDebugUtils.GetActiveTSFProfile(FLastActiveProfile); // I4331
|
||||
FBreakpoints := TDebugBreakpoints.Create;
|
||||
|
||||
FExecutionPointLine := -1;
|
||||
//InitControlCaptions;
|
||||
|
|
@ -331,11 +358,9 @@ begin
|
|||
end;
|
||||
|
||||
procedure TfrmDebug.FormDestroy(Sender: TObject);
|
||||
var
|
||||
i: TBreakpointRange;
|
||||
begin
|
||||
ResetDebug;
|
||||
for i := Low(TBreakpointRange) to High(TBreakpointRange) do FBreakpoint[i].Free;
|
||||
FBreakpoints.Free;
|
||||
FEvents.Free;
|
||||
//UninitControlCaptions;
|
||||
//UninitSystemKeyboard;
|
||||
|
|
@ -722,7 +747,7 @@ end;
|
|||
procedure TfrmDebug.WMUSERUpdateForceKeyboard(var Message: TMessage); // I4767
|
||||
procedure FailTidyUp;
|
||||
begin
|
||||
Windows.SetFocus(0);
|
||||
Winapi.Windows.SetFocus(0);
|
||||
HideDebugForm;
|
||||
FForceKeyboard := False;
|
||||
end;
|
||||
|
|
@ -763,8 +788,8 @@ begin
|
|||
if FWasStarted then // I3283 // I3503
|
||||
begin
|
||||
// Give Keyman Engine a chance to correctly attach focus after it starts
|
||||
Windows.SetFocus(0);
|
||||
Windows.SetFocus(memo.Handle);
|
||||
Winapi.Windows.SetFocus(0);
|
||||
Winapi.Windows.SetFocus(memo.Handle);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
|
|
@ -784,7 +809,7 @@ begin
|
|||
{Keyman_Exit; I3283 // I3503
|
||||
if not Keyman_Initialise(Application.MainForm.Handle, True) or not Keyman_ForceKeyboard(FFileName) then
|
||||
begin}
|
||||
Windows.SetFocus(0);
|
||||
Winapi.Windows.SetFocus(0);
|
||||
HideDebugForm;
|
||||
ShowMessage('Unable to start debugger - please make sure that Keyman Developer is correctly installed (the error code was '+IntToHex(FLastError, 8)+').'); // I3173 // I3504
|
||||
//(Editor as TfrmEditor).HideDebugForm;
|
||||
|
|
@ -1017,59 +1042,49 @@ end;
|
|||
|
||||
procedure TfrmDebug.SetBreakpoint(ALine: Integer);
|
||||
var
|
||||
i: TBreakpointRange;
|
||||
j: Integer;
|
||||
b: TDebugBreakpoint;
|
||||
begin
|
||||
j := -1;
|
||||
for i := Low(TBreakpointRange) to High(TBreakpointRange) do
|
||||
begin
|
||||
if Assigned(FBreakpoint[i]) then
|
||||
begin
|
||||
if (FBreakpoint[i].TrueLineNumber = ALine) then Exit;
|
||||
end
|
||||
else if j = -1 then j := i;
|
||||
end;
|
||||
for b in FBreakpoints do
|
||||
if b.TrueLineNumber = ALine then
|
||||
Exit;
|
||||
|
||||
if j = -1 then
|
||||
begin
|
||||
ShowMessage('You can only have a maximum of '+
|
||||
IntToStr(High(TBreakpointRange)-Low(TBreakpointRange))+' breakpoints.');
|
||||
Exit;
|
||||
end;
|
||||
b := TDebugBreakpoint.Create(EditorMemo);
|
||||
b.TrueLineNumber := ALine;
|
||||
FBreakpoints.Add(b);
|
||||
|
||||
FBreakpoint[j] := TDebugBreakpoint.Create(EditorMemo);
|
||||
FBreakpoint[j].TrueLineNumber := ALine;
|
||||
UpdateParColour(ALine, pcltBreakpoint);
|
||||
if Assigned(FOnSetBreakpoint) then
|
||||
FOnSetBreakpoint(Self, ALine);
|
||||
end;
|
||||
|
||||
procedure TfrmDebug.ClearBreakpoint(ALine: Integer);
|
||||
var
|
||||
i: TBreakpointRange;
|
||||
b: TDebugBreakpoint;
|
||||
begin
|
||||
for i := Low(TBreakpointRange) to High(TBreakpointRange) do
|
||||
if Assigned(FBreakpoint[i]) and (FBreakpoint[i].TrueLineNumber = ALine) then
|
||||
for b in FBreakpoints do
|
||||
if b.TrueLineNumber = ALine then
|
||||
begin
|
||||
FBreakpoint[i].Free;
|
||||
FBreakpoint[i] := nil;
|
||||
if IsExecutionPointLine(ALine)
|
||||
then UpdateParColour(ALine, pcltExecutionPoint)
|
||||
else UpdateParColour(ALine, pcltNone);
|
||||
FBreakpoints.Remove(b);
|
||||
if Assigned(FOnClearBreakpoint) then
|
||||
FOnClearBreakpoint(Self, ALine);
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmDebug.ToggleBreakpoint(ALine: Integer);
|
||||
begin
|
||||
if IsBreakpointLine(ALine)
|
||||
then ClearBreakpoint(ALine)
|
||||
else SetBreakpoint(ALine)
|
||||
end;
|
||||
|
||||
function TfrmDebug.IsBreakPointLine(ALine: Integer): Boolean;
|
||||
var
|
||||
i: Integer;
|
||||
b: TDebugBreakpoint;
|
||||
begin
|
||||
Result := True;
|
||||
for i := Low(TBreakpointRange) to High(TBreakpointRange) do
|
||||
begin
|
||||
if FBreakpoint[i] <> nil then
|
||||
if FBreakpoint[i].TrueLineNumber = ALine then
|
||||
Exit;
|
||||
end;
|
||||
Result := False;
|
||||
for b in FBreakpoints do
|
||||
if b.TrueLineNumber = ALine then
|
||||
Exit(True);
|
||||
Exit(False);
|
||||
end;
|
||||
|
||||
{-------------------------------------------------------------------------------
|
||||
|
|
@ -1082,28 +1097,21 @@ begin
|
|||
end;
|
||||
|
||||
procedure TfrmDebug.SetExecutionPointLine(ALine: Integer);
|
||||
var
|
||||
oldline: Integer;
|
||||
begin
|
||||
oldline := FExecutionPointLine;
|
||||
FExecutionPointLine := ALine;
|
||||
if IsBreakPointLine(oldline)
|
||||
then UpdateParColour(oldline, pcltBreakpoint)
|
||||
else UpdateParColour(oldline, pcltNone);
|
||||
if FRunning then Exit;
|
||||
if FExecutionPointLine >= 0 then
|
||||
UpdateParColour(FExecutionPointLine, pcltExecutionPoint);
|
||||
if FRunning and (FExecutionPointLine >= 0) then Exit;
|
||||
if Assigned(FOnUpdateExecutionPoint) then
|
||||
FOnUpdateExecutionPoint(Self, ALine);
|
||||
end;
|
||||
|
||||
procedure TfrmDebug.ListBreakpoints;
|
||||
var
|
||||
i: Integer;
|
||||
b: TDebugBreakpoint;
|
||||
begin
|
||||
memo.Clear;
|
||||
//frmDebugStatus.DeadKeys.ClearDeadkeys; I1699
|
||||
for i := 0 to 99 do
|
||||
if Assigned(FBreakPoint[i]) and (FBreakpoint[i].TrueLineNumber >= 0) then
|
||||
UpdateParColour(FBreakpoint[i].TrueLineNumber, pcltBreakpoint);
|
||||
for b in FBreakpoints do
|
||||
if Assigned(FOnSetBreakpoint) then
|
||||
FOnSetBreakpoint(Self, b.TrueLineNumber);
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -1178,12 +1186,6 @@ begin
|
|||
(frmDebugStatus as TfrmDebugStatus).DisplayFont := FFont;
|
||||
end;
|
||||
|
||||
procedure TfrmDebug.UpdateParColour(Line: Integer; LineType: TParColourLineType);
|
||||
begin
|
||||
if Assigned(FOnUpdateParColour) then
|
||||
FOnUpdateParColour(Self, Line, LineType);
|
||||
end;
|
||||
|
||||
procedure TfrmDebug.Pause;
|
||||
begin
|
||||
if UIStatus = duiTest then Exit;
|
||||
|
|
|
|||
|
|
@ -437,6 +437,8 @@ type
|
|||
procedure TouchLayoutModified(Sender: TObject);
|
||||
procedure FocusTabTouchLayout;
|
||||
|
||||
procedure EditorBreakpointClicked(Sender: TObject; ALine: Integer);
|
||||
|
||||
procedure FillFeatureGrid;
|
||||
procedure CheckParserSourceMove(Changed: Boolean);
|
||||
procedure ToggleWinLanguagesRow(Y: Integer);
|
||||
|
|
@ -488,7 +490,9 @@ type
|
|||
procedure StopDebugging;
|
||||
function PrepareForBuild(var DebugReset: Boolean): Boolean; // I4504
|
||||
|
||||
procedure UpdateParColour(Sender: TObject; ALine: Integer; ALineType: TParColourLineType);
|
||||
procedure DebugSetBreakpoint(Sender: TObject; ALine: Integer);
|
||||
procedure DebugClearBreakpoint(Sender: TObject; ALine: Integer);
|
||||
procedure DebugUpdateExecutionPoint(Sender: TObject; ALine: Integer);
|
||||
|
||||
function HasSubfilename(const Filename: string): Boolean; override; // I4081
|
||||
|
||||
|
|
@ -626,6 +630,7 @@ begin
|
|||
frameSource.EditorFormat := efKMN;
|
||||
frameSource.Visible := True;
|
||||
frameSource.OnChanged := SourceChanged;
|
||||
frameSource.OnBreakpointClicked := EditorBreakpointClicked;
|
||||
frameSource.TextFileFormat := FTextFileFormat;
|
||||
|
||||
pages.ActivePage := pageDetails;
|
||||
|
|
@ -702,6 +707,13 @@ end;
|
|||
{ General Functions }
|
||||
{-----------------------------------------------------------------------------}
|
||||
|
||||
procedure TfrmKeymanWizard.EditorBreakpointClicked(Sender: TObject;
|
||||
ALine: Integer);
|
||||
begin
|
||||
if Assigned(FDebugForm) then
|
||||
FDebugForm.ToggleBreakpoint(ALine);
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.EnableControls;
|
||||
begin
|
||||
BitmapEnableControls;
|
||||
|
|
@ -1478,11 +1490,6 @@ begin
|
|||
tmrUpdateCharacterMap.Enabled := True;
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.UpdateParColour(Sender: TObject; ALine: Integer; ALineType: TParColourLineType);
|
||||
begin
|
||||
frameSource.UpdateParColour(ALine, ALineType);
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.SelectVKey(VKey: Integer);
|
||||
begin
|
||||
kbdLayout.SelectedKey := kbdLayout.Keys.ItemsByUSVK[VKey];
|
||||
|
|
@ -1942,6 +1949,22 @@ begin
|
|||
frmKeymanDeveloper.cbTextFileFormat.ItemIndex := Ord(TextFileFormat);
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.DebugClearBreakpoint(Sender: TObject;
|
||||
ALine: Integer);
|
||||
begin
|
||||
frameSource.DebugClearBreakpoint(ALine);
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.DebugSetBreakpoint(Sender: TObject; ALine: Integer);
|
||||
begin
|
||||
frameSource.DebugSetBreakpoint(ALine);
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.DebugUpdateExecutionPoint(Sender: TObject; ALine: Integer);
|
||||
begin
|
||||
frameSource.DebugUpdateExecutionPoint(ALine);
|
||||
end;
|
||||
|
||||
procedure TfrmKeymanWizard.DoFocus(control: TWinControl);
|
||||
begin
|
||||
if control.Enabled and control.Visible and control.Showing and control.CanFocus then
|
||||
|
|
@ -2835,7 +2858,9 @@ begin
|
|||
FDebugForm.BorderStyle := bsNone;
|
||||
FDebugForm.Parent := panDebugWindowHost;
|
||||
FDebugForm.Align := alClient;
|
||||
FDebugForm.OnUpdateParColour := UpdateParColour;
|
||||
FDebugForm.OnSetBreakpoint := DebugSetBreakpoint;
|
||||
FDebugForm.OnClearBreakpoint := DebugClearBreakpoint;
|
||||
FDebugForm.OnUpdateExecutionPoint := DebugUpdateExecutionPoint;
|
||||
FDebugForm.Visible := True;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ uses
|
|||
UserMessages;
|
||||
|
||||
type
|
||||
TParColourLineType = (pcltNone, pcltBreakpoint, pcltExecutionPoint, pcltError);
|
||||
TEditorBreakpointClickedEvent = procedure(Sender: TObject; ALine: Integer) of object;
|
||||
|
||||
TframeTextEditor = class(TTIKEForm, IKMDEditActions, IKMDSearchActions, IKMDTextEditorActions)
|
||||
lstImages: TMenuImgList;
|
||||
|
|
@ -59,6 +59,7 @@ type
|
|||
|
||||
cef: TframeCEFHost;
|
||||
FFilename: string;
|
||||
FOnBreakpointClicked: TEditorBreakpointClickedEvent;
|
||||
|
||||
procedure RefreshOptions;
|
||||
function GetText: WideString;
|
||||
|
|
@ -91,9 +92,11 @@ type
|
|||
procedure LoadFileInBrowser(const AData: string);
|
||||
procedure UpdateInsertState(const AMode: string);
|
||||
procedure ExecuteCommand(const command: string; const parameters: TJSONValue = nil);
|
||||
procedure ExecuteLineCommand(ALine: Integer; const command: string);
|
||||
procedure UpdateToken(command: string);
|
||||
procedure SetCursorPosition(AColumn, ARow: Integer);
|
||||
procedure cefLoadEnd(Sender: TObject);
|
||||
procedure DoBreakpointClicked(const line: string);
|
||||
|
||||
protected
|
||||
function GetHelpTopic: string; override;
|
||||
|
|
@ -136,7 +139,11 @@ type
|
|||
|
||||
public
|
||||
{ Public declarations }
|
||||
procedure UpdateParColour(par: Integer; LineType: TParColourLineType);
|
||||
procedure DebugSetBreakpoint(ALine: Integer);
|
||||
procedure DebugClearBreakpoint(ALine: Integer);
|
||||
procedure DebugUpdateExecutionPoint(ALine: Integer);
|
||||
property OnBreakpointClicked: TEditorBreakpointClickedEvent read FOnBreakpointClicked write FOnBreakpointClicked;
|
||||
|
||||
procedure SetFocus; override;
|
||||
|
||||
procedure FindError(ln: Integer);
|
||||
|
|
@ -170,6 +177,7 @@ implementation
|
|||
uses
|
||||
System.TypInfo,
|
||||
Vcl.Clipbrd,
|
||||
|
||||
Keyman.Developer.System.HelpTopics,
|
||||
|
||||
dmActionsMain,
|
||||
|
|
@ -785,6 +793,21 @@ begin
|
|||
cef.cef.ClipboardCut;
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.DebugClearBreakpoint(ALine: Integer);
|
||||
begin
|
||||
ExecuteLineCommand(ALine, 'clearBreakpoint');
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.DebugSetBreakpoint(ALine: Integer);
|
||||
begin
|
||||
ExecuteLineCommand(ALine, 'setBreakpoint');
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.DebugUpdateExecutionPoint(ALine: Integer);
|
||||
begin
|
||||
ExecuteLineCommand(ALine, 'updateExecutionPoint');
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.PasteFromClipboard;
|
||||
begin
|
||||
cef.cef.ClipboardPaste;
|
||||
|
|
@ -832,28 +855,32 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.FindError(ln: Integer);
|
||||
procedure TframeTextEditor.ExecuteLineCommand(ALine: Integer;
|
||||
const command: string);
|
||||
var
|
||||
v: TJSONNumber;
|
||||
begin
|
||||
v := TJSONNumber.Create(ALine);
|
||||
try
|
||||
ExecuteCommand(command, v);
|
||||
finally
|
||||
v.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.FindError(ln: Integer);
|
||||
begin
|
||||
ClearError;
|
||||
if (ln <= 0) then Exit;
|
||||
|
||||
v := TJSONNumber.Create(ln);
|
||||
try
|
||||
ExecuteCommand('highlightError', v);
|
||||
SetSelectedRow(ln);
|
||||
finally
|
||||
v.Free;
|
||||
end;
|
||||
ExecuteLineCommand(ln, 'highlightError');
|
||||
SetSelectedRow(ln);
|
||||
end;
|
||||
|
||||
function TframeTextEditor.OffsetToLine(Offset: Integer): Integer; // I4083
|
||||
var
|
||||
line: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
|
||||
with TStringList.Create do
|
||||
try
|
||||
Text := Self.GetText;
|
||||
|
|
@ -879,40 +906,49 @@ end;
|
|||
procedure TframeTextEditor.FireCommand(const commands: TStringList);
|
||||
var
|
||||
i: Integer;
|
||||
command: string;
|
||||
command0, command: string;
|
||||
commandParams: TArray<string>;
|
||||
begin
|
||||
i := 0;
|
||||
while i < commands.Count do
|
||||
begin
|
||||
command := commands[i];
|
||||
command0 := commands[i];
|
||||
commandParams := command0.Split([',']);
|
||||
command := commandParams[0];
|
||||
if command = 'modified' then Changed // I3948
|
||||
|
||||
else if command = 'undo-disable' then FCanUndo := False
|
||||
else if command = 'undo-enable' then FCanUndo := True
|
||||
else if command = 'redo-disable' then FCanRedo := False
|
||||
else if command = 'redo-enable' then FCanRedo := True
|
||||
else if command = 'has-selection' then FHasSelection := True
|
||||
else if command = 'no-selection' then FHasSelection := False
|
||||
else if command.StartsWith('insert-mode,') then
|
||||
else if command = 'breakpoint-clicked' then DoBreakpointClicked(commandParams[1])
|
||||
else if command0.StartsWith('insert-mode,') then
|
||||
begin
|
||||
UpdateInsertState(command.Substring('insert-mode,'.Length));
|
||||
UpdateInsertState(command0.Substring('insert-mode,'.Length));
|
||||
end
|
||||
else if command.StartsWith('location,') then
|
||||
else if command0.StartsWith('location,') then
|
||||
begin
|
||||
UpdateState(command.Substring('location,'.Length));
|
||||
UpdateState(command0.Substring('location,'.Length));
|
||||
end
|
||||
else if command.StartsWith('token,') then
|
||||
else if command0.StartsWith('token,') then
|
||||
begin
|
||||
UpdateToken(command.Substring('token,'.Length));
|
||||
UpdateToken(command0.Substring('token,'.Length));
|
||||
end
|
||||
else ShowMessage('keyman:'+commands.Text);
|
||||
Inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.DoBreakpointClicked(const line: string);
|
||||
begin
|
||||
if Assigned(FOnBreakpointClicked) then
|
||||
FOnBreakpointClicked(Self, StrToInt(line));
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.UpdateToken(command: string);
|
||||
var
|
||||
n, col: Integer;
|
||||
col: Integer;
|
||||
line: string;
|
||||
x, tx: Integer;
|
||||
token, prevtoken: WideString;
|
||||
|
|
@ -968,23 +1004,6 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TframeTextEditor.UpdateParColour(par: Integer; LineType: TParColourLineType);
|
||||
var
|
||||
j: TJSONObject;
|
||||
begin
|
||||
if par < 0 then Exit;
|
||||
j := TJSONObject.Create;
|
||||
try
|
||||
j.AddPair('row', TJSONNumber.Create(par));
|
||||
if LineType <> pcltNone then
|
||||
j.AddPair('style', TJSONString.Create(GetEnumName(TypeInfo(TParColourLineType), Ord(LineType))));
|
||||
ExecuteCommand('setRowColor', j);
|
||||
finally
|
||||
j.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TframeTextEditor.GetHelpTopic: string;
|
||||
begin
|
||||
if FEditorFormat <> efKMN then
|
||||
|
|
|
|||
|
|
@ -11,27 +11,14 @@ html, body {
|
|||
left: 0;
|
||||
}
|
||||
|
||||
.ace_marker-layer .km_error,
|
||||
.ace_marker-layer .km_pcltBreakpoint,
|
||||
.ace_marker-layer .km_pcltExecutionPoint,
|
||||
.ace_marker-layer .km_pcltError {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/*.ace-chrome*/ .ace_marker-layer .km_error {
|
||||
.km_error {
|
||||
background: rgb(255, 128, 128);
|
||||
}
|
||||
|
||||
/*.ace-chrome*/ .ace_marker-layer .km_pcltBreakpoint {
|
||||
background-color: forestgreen;
|
||||
.km_breakpoint {
|
||||
background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cdefs%3E%3Cstyle%3E.icon-canvas-transparent,.icon-vs-out{fill:%23f6f6f6}.icon-canvas-transparent{opacity:0}.icon-vs-red{fill:%23e51400}%3C/style%3E%3C/defs%3E%3Ctitle%3Ebreakpoint%3C/title%3E%3Cpath class='icon-canvas-transparent' d='M16 0v16H0V0z' id='canvas'/%3E%3Cpath class='icon-vs-red' d='M11.789 8A3.789 3.789 0 1 1 8 4.211 3.788 3.788 0 0 1 11.789 8z' id='iconBg'/%3E%3C/svg%3E") 50% no-repeat
|
||||
}
|
||||
|
||||
/*.ace-chrome*/ .ace_marker-layer .km_pcltExecutionPoint {
|
||||
.km_executionPoint {
|
||||
background-color: deepskyblue;
|
||||
}
|
||||
|
||||
/*.ace-chrome*/ .ace_marker-layer .km_pcltError {
|
||||
background: rgb(255, 128, 128);
|
||||
}
|
||||
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
/*
|
||||
* Editor using monaco
|
||||
*
|
||||
* Helpful references:
|
||||
* https://microsoft.github.io/monaco-editor/api/index.html
|
||||
* https://blog.expo.io/building-a-code-editor-with-monaco-f84b3a06deaf
|
||||
*/
|
||||
|
||||
window.editorGlobalContext = {
|
||||
loading: false
|
||||
};
|
||||
|
|
@ -5,7 +13,8 @@ window.editorGlobalContext = {
|
|||
(function(context) {
|
||||
var editor = null;
|
||||
var errorRange = null;
|
||||
var ranges = [];
|
||||
var executionPoint = [];
|
||||
var breakpoints = [];
|
||||
let params = (new URL(location)).searchParams;
|
||||
let filename = params.get('filename');
|
||||
let mode = params.get('mode');
|
||||
|
|
@ -13,103 +22,153 @@ window.editorGlobalContext = {
|
|||
if(!mode) {
|
||||
mode = 'keyman';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Initialize the editor
|
||||
*/
|
||||
|
||||
require.config({ paths: { 'vs': '../lib/monaco/min/vs' } });
|
||||
require(['vs/editor/editor.main'], function () {
|
||||
editor = monaco.editor.create(document.getElementById('editor'), {
|
||||
language: mode,
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
glyphMargin: true,
|
||||
disableMonospaceOptimizations: true
|
||||
});
|
||||
|
||||
$.get("/app/source/file",
|
||||
{
|
||||
Filename: filename
|
||||
},
|
||||
function (response) {
|
||||
context.loading = true;
|
||||
editor.setValue(response);
|
||||
context.loading = false;
|
||||
},
|
||||
"text"
|
||||
);
|
||||
|
||||
const model = editor.getModel();
|
||||
model.onDidChangeContent(() => {
|
||||
// Even when loading, we post back the data to the backend so we have an original version
|
||||
$.post("/app/source/file", {
|
||||
Filename: filename,
|
||||
Data: model.getValue()
|
||||
// delta.start, delta.end, delta.lines, delta.action
|
||||
});
|
||||
if (!context.loading) {
|
||||
context.highlightError(); // clear the selected error
|
||||
command('modified');
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
|
||||
editor.onDidChangeCursorPosition(updateState);
|
||||
editor.onDidChangeCursorSelection(updateState);
|
||||
editor.onMouseDown(e => {
|
||||
if (e.target.type !== monaco.editor.MouseTargetType.GUTTER_GLYPH_MARGIN) {
|
||||
return;
|
||||
}
|
||||
command('breakpoint-clicked,'+(e.target.position.lineNumber-1));
|
||||
});
|
||||
});
|
||||
|
||||
/* Search and replace interfaces */
|
||||
|
||||
context.searchFind = function() {
|
||||
editor.commands.byName.find.exec(editor);
|
||||
context.searchFind = function () {
|
||||
editor.trigger('', 'actions.find');
|
||||
};
|
||||
|
||||
context.searchFindNext = function() {
|
||||
editor.commands.byName.selectOrFindNext.exec(editor);
|
||||
editor.trigger('', 'editor.action.nextMatchFindAction');
|
||||
};
|
||||
|
||||
context.searchReplace = function() {
|
||||
editor.commands.byName.replace.exec(editor);
|
||||
editor.trigger('', 'editor.action.startFindReplaceAction');
|
||||
};
|
||||
|
||||
/* Edit command interfaces */
|
||||
|
||||
context.editUndo = function() {
|
||||
editor.undo();
|
||||
editor.model.undo();
|
||||
};
|
||||
|
||||
context.editRedo = function() {
|
||||
editor.redo();
|
||||
editor.model.redo();
|
||||
};
|
||||
|
||||
context.editSelectAll = function() {
|
||||
editor.selectAll();
|
||||
editor.setSelection(editor.model.getFullModelRange());
|
||||
};
|
||||
|
||||
/* Row selection */
|
||||
|
||||
context.moveCursor = function (o) {
|
||||
editor.moveCursorTo(o.row, o.column);
|
||||
editor.selection.clearSelection();
|
||||
editor.renderer.scrollCursorIntoView();
|
||||
editor.setPosition({ column: o.column + 1, lineNumber: o.row + 1 });
|
||||
editor.revealPositionInCenterIfOutsideViewport(editor.getPosition(), monaco.editor.ScrollType.Smooth);
|
||||
};
|
||||
|
||||
/* Debug interactions */
|
||||
|
||||
context.setBreakpoint = function (row) {
|
||||
if (!breakpoints[row]) {
|
||||
breakpoints[row] = editor.deltaDecorations(
|
||||
[],
|
||||
[{ range: new monaco.Range(row + 1, 1, row + 1, 1), options: { isWholeLine: true, glyphMarginClassName: 'km_breakpoint' } }]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
context.clearBreakpoint = function (row) {
|
||||
if (breakpoints[row]) {
|
||||
editor.deltaDecorations(breakpoints[row], []);
|
||||
breakpoints[row] = null;
|
||||
}
|
||||
};
|
||||
|
||||
context.updateExecutionPoint = function (row) {
|
||||
executionPoint = editor.deltaDecorations(
|
||||
executionPoint,
|
||||
row >= 0 ? [{ range: new monaco.Range(row + 1, 1, row + 1, 1), options: { isWholeLine: true, linesDecorationsClassName: 'km_executionPoint' } }] : []
|
||||
);
|
||||
context.moveCursor({ row: row, column: 0 });
|
||||
};
|
||||
|
||||
/* Error highlighting */
|
||||
|
||||
context.setRowColor = function(o) {
|
||||
if (o.style) {
|
||||
var r = new ace.Range(o.row, 0, o.row, Infinity);
|
||||
r.row = o.row;
|
||||
r.id = editor.session.addMarker(r, 'km_'+o.style, "fullLine", false);
|
||||
ranges.push(r);
|
||||
} else {
|
||||
ranges = ranges.filter(function (v) {
|
||||
if (v.row !== o.row) {
|
||||
return true;
|
||||
}
|
||||
editor.session.removeMarker(v.id);
|
||||
return false;
|
||||
});
|
||||
|
||||
context.highlightError = function (row) {
|
||||
if (errorRange) {
|
||||
editor.deltaDecorations(errorRange, []);
|
||||
errorRange = null;
|
||||
}
|
||||
editor.moveCursorTo(o.row, 0);
|
||||
editor.selection.clearSelection();
|
||||
editor.renderer.scrollCursorIntoView();
|
||||
};
|
||||
|
||||
context.highlightError = function(row) {
|
||||
if(errorRange) {
|
||||
editor.session.removeMarker(errorRange.id);
|
||||
}
|
||||
if(typeof row == 'number') {
|
||||
errorRange = new ace.Range(row, 0, row, Infinity);
|
||||
errorRange.id = editor.session.addMarker(errorRange, 'km_error', "fullLine", false);
|
||||
if (typeof row == 'number') {
|
||||
errorRange = editor.deltaDecorations([], [{ range: new monaco.Range(row + 1, 1, row + 1, 1), options: { isWholeLine: true, linesDecorationsClassName: 'km_error', className: 'km_error' } }]);
|
||||
}
|
||||
};
|
||||
|
||||
context.replaceSelection = function (o) {
|
||||
let originalRange = new ace.Range(o.top, o.left, o.bottom, o.right);
|
||||
let end = editor.session.doc.replace(originalRange, o.newText);
|
||||
|
||||
let newRange = new ace.Range(o.top, o.left, end.row, end.column);
|
||||
editor.selection.setSelectionRange(newRange, false);
|
||||
let r = new monaco.Range(o.top + 1, o.left + 1, o.bottom + 1, o.right + 1);
|
||||
editor.setSelection(r);
|
||||
editor.executeEdits("", [
|
||||
{ range: r, text: o.newText }
|
||||
]);
|
||||
};
|
||||
|
||||
context.setText = function (text) {
|
||||
let range = editor.session.selection.getRange();
|
||||
let range = editor.getSelection();
|
||||
context.loading = true;
|
||||
editor.session.setValue(text);
|
||||
editor.session.selection.setSelectionRange(range);
|
||||
context.loading = false;
|
||||
};
|
||||
|
||||
context.setText = function (text) {
|
||||
let range = editor.session.selection.getRange();
|
||||
context.loading = true;
|
||||
editor.session.setValue(text);
|
||||
editor.session.selection.setSelectionRange(range);
|
||||
editor.setValue(text);
|
||||
editor.setSelection(range);
|
||||
context.loading = false;
|
||||
};
|
||||
|
||||
/* Printing */
|
||||
|
||||
context.print = function () {
|
||||
require("ace/config").loadModule("ace/ext/static_highlight", function (m) {
|
||||
/****require("ace/config").loadModule("ace/ext/static_highlight", function (m) {
|
||||
var result = m.renderSync(
|
||||
editor.getValue(), editor.session.getMode(), editor.renderer.theme
|
||||
);
|
||||
|
|
@ -129,7 +188,7 @@ window.editorGlobalContext = {
|
|||
}, 10);
|
||||
};
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
});*/
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -162,84 +221,38 @@ window.editorGlobalContext = {
|
|||
|
||||
/**
|
||||
*/
|
||||
var updateState = function() {
|
||||
command(editor.getSelectedText() == '' ? 'no-selection' : 'has-selection');
|
||||
command(editor.session.getUndoManager().hasUndo() ? 'undo-enable' : 'undo-disable');
|
||||
command(editor.session.getUndoManager().hasRedo() ? 'redo-enable' : 'redo-disable');
|
||||
let r = editor.selection.getRange();
|
||||
var n = editor.session.doc.getTextRange(editor.selection.getRange()).length;
|
||||
if (!editor.selection.isBackwards()) n = -n;
|
||||
command('location,' + r.start.row + ',' + r.start.column + ',' + r.end.row + ',' + r.end.column + ',' + n);
|
||||
command('insert-mode,' + (editor.session.getOption('overwrite') ? 'Overwrite' : 'Insert'));
|
||||
// command(editor.session.getUndoManager().isClean() ? 'modified' : 'not-modified');
|
||||
var s = getTokenAtCursor();
|
||||
if(s) {
|
||||
command('token,'+s.column+','+encodeURIComponent(s.text));
|
||||
var updateState = function () {
|
||||
let s = editor.getSelection();
|
||||
command(s.isEmpty() ? 'no-selection' : 'has-selection');
|
||||
command(editor.model.canUndo() ? 'undo-enable' : 'undo-disable');
|
||||
command(editor.model.canRedo() ? 'redo-enable' : 'redo-disable');
|
||||
|
||||
var n = editor.model.getValueInRange(s).length;
|
||||
if (editor.getSelection().getDirection() == monaco.SelectionDirection.LTR) n = -n;
|
||||
command('location,' + (s.startLineNumber-1) + ',' + (s.startColumn-1) + ',' + (s.endLineNumber-1) + ',' + (s.endColumn-1) + ',' + n);
|
||||
//command('insert-mode,' + (editor.session.getOption('overwrite') ? 'Overwrite' : 'Insert'));
|
||||
var token = getTokenAtCursor();
|
||||
if (token) {
|
||||
command('token,' + token.column + ',' + encodeURIComponent(token.text));
|
||||
}
|
||||
};
|
||||
|
||||
var getTokenAtCursor = function() {
|
||||
var txt = editor.getSelectedText();
|
||||
if(txt != '') {
|
||||
|
||||
var getTokenAtCursor = function () {
|
||||
var txt = editor.model.getValueInRange(editor.getSelection());
|
||||
if (txt != '') {
|
||||
// We'll always return the first 100 characters of the selection and not
|
||||
// do any manipulation here.
|
||||
return {column:null,text:txt.substr(0, 99)};
|
||||
return { column: null, text: txt.substr(0, 99) };
|
||||
}
|
||||
|
||||
if(mode == 'keyman') {
|
||||
|
||||
if (mode == 'keyman') {
|
||||
// Get the token under the cursor
|
||||
var c = editor.session.selection.getCursor();
|
||||
var line = editor.session.getLine(c.row);
|
||||
return {column:c.column, text:line};
|
||||
var c = editor.getSelection();
|
||||
var line = editor.model.getLineContent(c.positionLineNumber);
|
||||
return { column: c.positionColumn-1, text: line };
|
||||
} else {
|
||||
// Get the character under the cursor
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Initialize the editor
|
||||
*/
|
||||
$(function initialize() {
|
||||
editor = ace.edit("editor");
|
||||
|
||||
// Remove Alt+ key bindings which may conflict with environment shortcuts, e.g. Alt+E, function keys
|
||||
|
||||
var reAltKeyBindings = /(^alt-[a-z0-9]|f[0-9]+)$/;
|
||||
for (var key in editor.keyBinding.$defaultHandler.commandKeyBinding) {
|
||||
if (key.match(reAltKeyBindings)) {
|
||||
delete editor.keyBinding.$defaultHandler.commandKeyBinding[key];
|
||||
}
|
||||
}
|
||||
|
||||
editor.setTheme("ace/theme/xcode");
|
||||
|
||||
editor.session.selection.on('changeCursor', updateState);
|
||||
editor.session.on('changeOverwrite', updateState);
|
||||
editor.session.selection.on('changeSelection', updateState);
|
||||
|
||||
editor.session.on('change', function (delta) {
|
||||
// Even when loading, we post back the data to the backend so we have an original version
|
||||
$.post("/app/source/file", {
|
||||
Filename: filename,
|
||||
Data: editor.session.getValue()
|
||||
// delta.start, delta.end, delta.lines, delta.action
|
||||
});
|
||||
if (!context.loading) {
|
||||
context.highlightError(); // clear the selected error
|
||||
command('modified');
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
// Start reading the source file
|
||||
$.get("/app/source/file", {
|
||||
Filename: filename
|
||||
}, function (response) {
|
||||
context.loading = true;
|
||||
editor.session.setValue(response);
|
||||
editor.session.setMode("ace/mode/"+mode);
|
||||
context.loading = false;
|
||||
},
|
||||
"text");
|
||||
});
|
||||
})(window.editorGlobalContext);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
|
|
@ -15,11 +15,12 @@
|
|||
|
||||
<link rel="stylesheet" type='text/css' href='editor.css' />
|
||||
|
||||
<script src="../lib/ace/ace.js" charset="utf-8"></script>
|
||||
<script src="../lib/jquery/jquery-1.10.2.js"></script>
|
||||
<script src="editor.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="editor"></div>
|
||||
|
||||
<script src="../lib/monaco/min/vs/loader.js"></script>
|
||||
<script src="editor.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue