Merge branch 'master' into feat/developer/debugger-qrcode

This commit is contained in:
Marc Durdin 2019-12-09 09:13:29 +00:00 committed by GitHub
commit 1be5df9d19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 3230 additions and 379 deletions

View file

@ -283,12 +283,17 @@ uses
Keyman.Developer.System.ProjectTemplate in '..\kmconvert\Keyman.Developer.System.ProjectTemplate.pas',
Keyman.Developer.UI.Project.UfrmNewModelProjectParameters in 'project\Keyman.Developer.UI.Project.UfrmNewModelProjectParameters.pas' {frmNewModelProjectParameters},
Keyman.Developer.System.Project.wordlistTsvProjectFile in 'project\Keyman.Developer.System.Project.wordlistTsvProjectFile.pas',
Keyman.Developer.UI.UfrmWordlistEditor in 'child\Keyman.Developer.UI.UfrmWordlistEditor.pas' {frmWordlistEditor},
Keyman.Developer.UI.UframeWordlistEditor in 'child\Keyman.Developer.UI.UframeWordlistEditor.pas' {frameWordlistEditor},
Keyman.System.WordlistTsvFile in '..\..\global\delphi\lexicalmodels\Keyman.System.WordlistTsvFile.pas',
Keyman.Developer.UI.Project.wordlistTsvProjectFileUI in 'project\Keyman.Developer.UI.Project.wordlistTsvProjectFileUI.pas',
Keyman.Developer.System.Project.WelcomeRenderer in 'project\Keyman.Developer.System.Project.WelcomeRenderer.pas',
DelphiZXIngQRCode in '..\..\ext\zxingqrcode\Source\DelphiZXIngQRCode.pas',
Keyman.System.QRCode in '..\..\global\delphi\general\Keyman.System.QRCode.pas';
Keyman.System.QRCode in '..\..\global\delphi\general\Keyman.System.QRCode.pas',
Keyman.Developer.UI.UfrmModelEditor in 'child\Keyman.Developer.UI.UfrmModelEditor.pas' {frmModelEditor},
Keyman.Developer.System.LexicalModelParser in 'main\Keyman.Developer.System.LexicalModelParser.pas',
Keyman.Developer.System.LexicalModelParserTypes in 'main\Keyman.Developer.System.LexicalModelParserTypes.pas',
Keyman.Developer.UI.UfrmWordlistEditor in 'child\Keyman.Developer.UI.UfrmWordlistEditor.pas' {frmWordlistEditor},
Keyman.Developer.UI.dmActionsModelEditor in 'actions\Keyman.Developer.UI.dmActionsModelEditor.pas' {modActionsModelEditor: TDataModule};
{$R *.RES}
{$R ICONS.RES}
@ -316,8 +321,8 @@ begin
if TikeActive then Exit;
InitClasses;
Application.CreateForm(TmodWebHttpServer, modWebHttpServer);
Application.CreateForm(TfrmKeymanDeveloper, frmKeymanDeveloper);
Application.Run;
Application.CreateForm(TfrmKeymanDeveloper, frmKeymanDeveloper);
Application.Run;
end;
finally
FInitializeCEF.Free;

View file

@ -529,8 +529,8 @@
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="project\Keyman.Developer.System.Project.wordlistTsvProjectFile.pas"/>
<DCCReference Include="child\Keyman.Developer.UI.UfrmWordlistEditor.pas">
<Form>frmWordlistEditor</Form>
<DCCReference Include="child\Keyman.Developer.UI.UframeWordlistEditor.pas">
<Form>frameWordlistEditor</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="..\..\global\delphi\lexicalmodels\Keyman.System.WordlistTsvFile.pas"/>
@ -538,6 +538,21 @@
<DCCReference Include="project\Keyman.Developer.System.Project.WelcomeRenderer.pas"/>
<DCCReference Include="..\..\ext\zxingqrcode\Source\DelphiZXIngQRCode.pas"/>
<DCCReference Include="..\..\global\delphi\general\Keyman.System.QRCode.pas"/>
<DCCReference Include="child\Keyman.Developer.UI.UfrmModelEditor.pas">
<Form>frmModelEditor</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="main\Keyman.Developer.System.LexicalModelParser.pas"/>
<DCCReference Include="main\Keyman.Developer.System.LexicalModelParserTypes.pas"/>
<DCCReference Include="child\Keyman.Developer.UI.UfrmWordlistEditor.pas">
<Form>frmWordlistEditor</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="actions\Keyman.Developer.UI.dmActionsModelEditor.pas">
<Form>modActionsModelEditor</Form>
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<None Include="Profiling\AQtimeModule1.aqt"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>

View file

@ -0,0 +1,29 @@
object modActionsModelEditor: TmodActionsModelEditor
OldCreateOrder = False
Height = 150
Width = 215
object actionsModelEditor: TActionList
Images = frmKeymanDeveloper.lstImages
Left = 60
Top = 24
object actModelCompile: TAction
Category = 'Lexical Model'
Caption = '&Compile Model'
ImageIndex = 37
ShortCut = 118
OnExecute = actModelCompileExecute
OnUpdate = actModelCompileUpdate
end
object actModelIncludeDebugInformation: TAction
Category = 'Lexical Model'
Caption = 'Include &Debug Information'
OnExecute = actModelIncludeDebugInformationExecute
end
object actModelTest: TAction
Category = 'Lexical Model'
Caption = 'Test &Lexical Model'
OnExecute = actModelTestExecute
OnUpdate = actModelTestUpdate
end
end
end

View file

@ -0,0 +1,86 @@
unit Keyman.Developer.UI.dmActionsModelEditor;
interface
uses
System.SysUtils, System.Classes, System.Actions, Vcl.ActnList;
type
TmodActionsModelEditor = class(TDataModule)
actionsModelEditor: TActionList;
actModelCompile: TAction;
actModelTest: TAction;
actModelIncludeDebugInformation: TAction;
procedure actModelCompileExecute(Sender: TObject);
procedure actModelIncludeDebugInformationExecute(Sender: TObject);
procedure actModelTestExecute(Sender: TObject);
procedure actModelCompileUpdate(Sender: TObject);
procedure actModelTestUpdate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
modActionsModelEditor: TmodActionsModelEditor;
implementation
{%CLASSGROUP 'Vcl.Controls.TControl'}
uses
UfrmMain,
UfrmMessages,
Keyman.Developer.System.Project.ProjectFile,
Keyman.Developer.UI.Project.ProjectFileUI,
Keyman.Developer.System.Project.modelTsProjectFile,
Keyman.Developer.UI.UfrmModelEditor;
{$R *.dfm}
function ActiveModelEditor: TfrmModelEditor;
begin
if Assigned(frmKeymanDeveloper.ActiveChild) and (frmKeymanDeveloper.ActiveChild is TfrmModelEditor)
then Result := frmKeymanDeveloper.ActiveChild as TfrmModelEditor
else Result := nil;
end;
function ActiveModelProjectFile: TmodelTsProjectFile;
begin
Result := ActiveModelEditor.ProjectFile as TmodelTsProjectFile;
end;
procedure TmodActionsModelEditor.actModelCompileExecute(Sender: TObject);
begin
frmMessages.Clear; // I4686
if ActiveModelEditor <> nil then
begin
(ActiveModelProjectFile.UI as TProjectFileUI).DoAction(pfaCompile, False);
end;
end;
procedure TmodActionsModelEditor.actModelCompileUpdate(Sender: TObject);
begin
actModelCompile.Enabled := ActiveModelEditor <> nil;
frmKeymanDeveloper.mnuModel.Visible := actModelCompile.Enabled;
end;
procedure TmodActionsModelEditor.actModelIncludeDebugInformationExecute(
Sender: TObject);
begin
// TODO: (ActiveModelProjectFile.UI as TmodeltsProjectFileUI).Debug := not (ActiveModelProjectFile.UI as TmodeltsProjectFileUI).Debug; // I4687
end;
procedure TmodActionsModelEditor.actModelTestExecute(Sender: TObject);
begin
(ActiveModelProjectFile.UI as TProjectFileUI).DoAction(pfaTestKeymanWeb, False); // I4687
end;
procedure TmodActionsModelEditor.actModelTestUpdate(Sender: TObject);
begin
actModelTest.Enabled := ActiveModelEditor <> nil;
end;
end.

View file

@ -23,7 +23,7 @@ object modActionsKeyboardEditor: TmodActionsKeyboardEditor
end
object actKeyboardCreatePackage: TAction
Category = 'Keyboard'
Caption = '&Package for Distribution...'
Caption = 'Package for Distribution...'
ImageIndex = 40
OnExecute = actKeyboardCreatePackageExecute
end

View file

@ -446,7 +446,10 @@ end;
procedure TmodActionsKeyboardEditor.actKeyboardCompileUpdate(Sender: TObject);
begin
// TODO: Split Keyboard menu and package editor functions
actKeyboardCompile.Enabled := (ActiveEditor <> nil) or (ActivePackageEditor <> nil);
frmKeymanDeveloper.mnuKeyboard.Visible := actKeyboardCompile.Enabled;
frmKeymanDeveloper.mnuDebug.Visible := ActiveEditor <> nil;
end;
procedure TmodActionsKeyboardEditor.actKeyboardCreatePackageExecute(Sender: TObject);

View file

@ -0,0 +1,87 @@
inherited frameWordlistEditor: TframeWordlistEditor
BorderIcons = []
BorderStyle = bsNone
Caption = 'frameWordlistEditor'
ClientHeight = 338
ClientWidth = 651
OnResize = FormResize
ExplicitWidth = 651
ExplicitHeight = 338
PixelsPerInch = 96
TextHeight = 13
object pages: TPageControl
Left = 0
Top = 0
Width = 651
Height = 338
ActivePage = pageDesign
Align = alClient
TabOrder = 0
TabPosition = tpBottom
OnChanging = pagesChanging
ExplicitWidth = 635
ExplicitHeight = 299
object pageDesign: TTabSheet
Caption = 'Design'
ImageIndex = -1
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 627
ExplicitHeight = 273
object gridWordlist: TStringGridEditControlled
Left = 0
Top = 0
Width = 643
Height = 271
Align = alClient
ColCount = 3
DefaultRowHeight = 16
DefaultDrawing = False
FixedCols = 0
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goEditing, goTabs, goAlwaysShowEditor]
TabOrder = 0
OnClick = gridWordlistClick
OnDrawCell = gridWordlistDrawCell
OnSetEditText = gridWordlistSetEditText
ExplicitWidth = 627
ExplicitHeight = 232
end
object panGridControls: TPanel
Left = 0
Top = 271
Width = 643
Height = 41
Align = alBottom
TabOrder = 1
ExplicitTop = 232
ExplicitWidth = 627
object cmdDeleteRow: TButton
Left = 0
Top = 6
Width = 75
Height = 25
Caption = '&Delete row'
TabOrder = 0
OnClick = cmdDeleteRowClick
end
object cmdSortByFrequency: TButton
Left = 81
Top = 6
Width = 104
Height = 25
Caption = '&Sort by frequency'
TabOrder = 1
OnClick = cmdSortByFrequencyClick
end
end
end
object pageCode: TTabSheet
Caption = 'Code'
ImageIndex = -1
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
end
end
end

View file

@ -0,0 +1,340 @@
unit Keyman.Developer.UI.UframeWordlistEditor;
interface
uses
System.Classes,
System.SysUtils,
System.Variants,
Winapi.Messages,
Winapi.Windows,
Vcl.ComCtrls,
Vcl.Controls,
Vcl.Dialogs,
Vcl.Forms,
Vcl.Graphics,
Vcl.Grids,
StringGridEditControlled,
Keyman.System.WordlistTsvFile,
UframeTextEditor,
UfrmMDIEditor, Vcl.StdCtrls, Vcl.ExtCtrls, UfrmTike;
type
TframeWordlistEditor = class(TTIKEForm)
pages: TPageControl;
pageDesign: TTabSheet;
pageCode: TTabSheet;
gridWordlist: TStringGridEditControlled;
panGridControls: TPanel;
cmdDeleteRow: TButton;
cmdSortByFrequency: TButton;
procedure pagesChanging(Sender: TObject; var AllowChange: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure gridWordlistSetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: string);
procedure gridWordlistDrawCell(Sender: TObject; ACol, ARow: Integer;
ARect: TRect; State: TGridDrawState);
procedure cmdDeleteRowClick(Sender: TObject);
procedure gridWordlistClick(Sender: TObject);
procedure cmdSortByFrequencyClick(Sender: TObject);
private
FWordlist: TWordlistTsvFile;
frameSource: TframeTextEditor;
FSetup: Integer;
FModified: Boolean;
FOnModifiedChanged: TNotifyEvent;
FFilename: string;
procedure UpdateData;
function MoveCodeToWordlist: Boolean;
procedure FillCode;
procedure FillGrid;
function MoveDesignToWordlist: Boolean;
procedure SourceChanged(Sender: TObject);
procedure FillGridNewRow;
procedure EnableControls;
procedure SetModified(const Value: Boolean);
protected
function GetHelpTopic: string; override;
function DoOpenFile: Boolean;
function DoSaveFile: Boolean;
public
procedure FindError(const Filename: string; s: string; line: Integer); // I4081
function LoadFromFile(const Filename: string): Boolean;
function SaveToFile(const Filename: string): Boolean;
property Filename: string read FFilename;
property Modified: Boolean read FModified write SetModified;
property OnModifiedChanged: TNotifyEvent read FOnModifiedChanged write FOnModifiedChanged;
end;
implementation
{$R *.dfm}
uses
Keyman.Developer.System.HelpTopics,
TextFileFormat,
UfrmMain,
UfrmMessages;
const
ColWidth_Word = 120;
ColWidth_Frequency = 64;
S_AddRowText = 'Add word...';
{ TfrmWordlistEditor }
procedure TframeWordlistEditor.FormCreate(Sender: TObject);
begin
inherited;
Inc(FSetup);
try
FWordlist := TWordlistTsvFile.Create;
frameSource := TframeTextEditor.Create(Self);
frameSource.Parent := pageCode;
frameSource.Align := alClient;
frameSource.EditorFormat := efWordlistTsv;
frameSource.Visible := True;
frameSource.OnChanged := SourceChanged;
frameSource.TextFileFormat := tffUTF8;
//TODO: frameSource.UseTabs := True;
pages.ActivePage := pageDesign;
gridWordlist.Cells[0, 0] := 'Word Form';
gridWordlist.Cells[1, 0] := 'Count';
gridWordlist.Cells[2, 0] := 'Comment';
gridWordlist.ColWidths[0] := ColWidth_Word;
gridWordlist.ColWidths[1] := ColWidth_Frequency;
gridWordlist.ColWidths[2] := gridWordlist.ClientWidth - ColWidth_Word - ColWidth_Frequency - 2;
finally
Dec(FSetup);
end;
end;
procedure TframeWordlistEditor.FormDestroy(Sender: TObject);
begin
inherited;
FWordlist.Free;
end;
procedure TframeWordlistEditor.FormResize(Sender: TObject);
begin
inherited;
gridWordlist.ColWidths[2] := gridWordlist.ClientWidth - ColWidth_Word - ColWidth_Frequency - 2;
end;
procedure TframeWordlistEditor.cmdDeleteRowClick(Sender: TObject);
begin
FWordlist.RemoveWord(gridWordlist.Row-1);
FillGrid;
EnableControls;
Modified := True;
end;
procedure TframeWordlistEditor.cmdSortByFrequencyClick(Sender: TObject);
begin
FWordlist.SortByFrequency;
FillGrid;
Modified := True;
end;
function TframeWordlistEditor.DoOpenFile: Boolean;
begin
if FileExists(FileName) then
begin
FWordlist.LoadFromFile(FileName);
end;
UpdateData;
Result := True;
end;
function TframeWordlistEditor.DoSaveFile: Boolean;
begin
MoveCodeToWordlist; // Does nothing if not in code page
FWordlist.SaveToFile(FileName);
Result := True;
end;
procedure TframeWordlistEditor.EnableControls;
var
e: Boolean;
begin
e := gridWordlist.Row < gridWordlist.RowCount - 1;
cmdDeleteRow.Enabled := e;
cmdSortByFrequency.Enabled := e;
end;
procedure TframeWordlistEditor.FindError(const Filename: string; s: string; line: Integer);
begin
//
end;
function TframeWordlistEditor.GetHelpTopic: string;
begin
Result := SHelpTopic_Context_WordlistEditor;
end;
procedure TframeWordlistEditor.gridWordlistClick(Sender: TObject);
begin
EnableControls;
end;
procedure TframeWordlistEditor.gridWordlistDrawCell(Sender: TObject; ACol,
ARow: Integer; ARect: TRect; State: TGridDrawState);
var
LText: string;
begin
inherited;
if ARow = gridWordlist.RowCount - 1 then
begin
// Drawing last row
gridWordlist.Canvas.Font.Style := [fsItalic];
end
else if gridWordlist.Cells[0, ARow] = '#' then
begin
// Drawing a comment cell
gridWordlist.Canvas.Font.Style := [fsBold];
end
else
gridWordlist.Canvas.Font.Style := [];
LText := gridWordlist.Cells[ACol, ARow];
gridWordlist.Canvas.TextRect(ARect, ARect.Left+2,
ARect.Top+((ARect.Height - gridWordlist.Canvas.TextHeight(LText)) div 2), LText);
end;
procedure TframeWordlistEditor.gridWordlistSetEditText(Sender: TObject; ACol,
ARow: Integer; const Value: string);
var
w: TWordlistWord;
begin
if FSetup > 0 then Exit;
Inc(FSetup);
try
Modified := True;
if ARow = gridWordlist.RowCount - 1 then
begin
if (Value = '') or (Value = S_AddRowText) then
Exit;
w.Word := Value;
w.Frequency := 0;
w.Comment := '';
FWordlist.AddWord(w);
gridWordlist.RowCount := gridWordlist.RowCount + 1;
FillGridNewRow;
end
else
begin
w := FWordlist.Word[ARow-1];
case ACol of
0: w.Word := Value;
1: w.Frequency := StrToIntDef(Value, 0);
2: w.Comment := Value;
end;
FWordlist.Word[ARow-1] := w;
end;
finally
Dec(FSetup);
end;
end;
procedure TframeWordlistEditor.pagesChanging(Sender: TObject;
var AllowChange: Boolean);
begin
if FSetup > 0 then Exit;
if pages.ActivePage = pageCode then
AllowChange := MoveCodeToWordlist
else
AllowChange := MoveDesignToWordlist
end;
function TframeWordlistEditor.MoveCodeToWordlist: Boolean;
begin
if pages.ActivePage <> pageCode then
Exit(False);
FWordlist.Text := frameSource.EditorText;
FillGrid;
Result := True;
end;
function TframeWordlistEditor.MoveDesignToWordlist: Boolean;
begin
FillCode;
Result := True;
end;
function TframeWordlistEditor.LoadFromFile(const Filename: string): Boolean;
begin
FFilename := Filename;
Result := DoOpenFile;
end;
procedure TframeWordlistEditor.UpdateData;
begin
if pages.ActivePage = pageCode
then FillCode
else FillGrid;
end;
function TframeWordlistEditor.SaveToFile(const Filename: string): Boolean;
begin
FFilename := Filename;
Result := DoSaveFile;
end;
procedure TframeWordlistEditor.SetModified(const Value: Boolean);
begin
if FModified <> Value then
begin
FModified := Value;
if Assigned(FOnModifiedChanged) then
FOnModifiedChanged(Self);
end;
end;
procedure TframeWordlistEditor.SourceChanged(Sender: TObject);
begin
if FSetup = 0 then
Modified := True;
end;
procedure TframeWordlistEditor.FillCode;
begin
frameSource.EditorText := FWordlist.Text;
end;
procedure TframeWordlistEditor.FillGrid;
var
i: Integer;
w: TWordlistWord;
begin
gridWordlist.RowCount := FWordlist.Count + 2;
for i := 0 to FWordlist.Count - 1 do
begin
w := FWordlist.Word[i];
gridWordlist.Cells[0, i+1] := w.Word;
if w.Frequency = 0
then gridWordlist.Cells[1, i+1] := ''
else gridWordlist.Cells[1, i+1] := IntToStr(w.Frequency);
gridWordlist.Cells[2, i+1] := w.Comment;
end;
FillGridNewRow;
gridWordlist.FixedRows := 1;
end;
procedure TframeWordlistEditor.FillGridNewRow;
begin
gridWordlist.Cells[0, gridWordlist.RowCount - 1] := S_AddRowText;
gridWordlist.Cells[1, gridWordlist.RowCount - 1] := '';
gridWordlist.Cells[2, gridWordlist.RowCount - 1] := '';
EnableControls;
end;
end.

View file

@ -0,0 +1,410 @@
inherited frmModelEditor: TfrmModelEditor
Left = 0
Top = 0
Caption = 'frmModelEditor'
ClientHeight = 708
ClientWidth = 712
Font.Name = 'Tahoma'
ExplicitWidth = 712
ExplicitHeight = 708
PixelsPerInch = 96
TextHeight = 13
object pages: TLeftTabbedPageControl
Left = 0
Top = 0
Width = 712
Height = 708
ActivePage = pageCompile
Align = alClient
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Segoe UI'
Font.Style = []
Images = modActionsMain.ilEditorPages
MultiLine = True
OwnerDraw = True
ParentFont = False
TabHeight = 90
TabOrder = 0
TabPosition = tpLeft
TabWidth = 60
OnChanging = pagesChanging
object pageDetails: TTabSheet
Caption = 'Details'
ImageIndex = 2
object sbDetails: TScrollBox
Left = 0
Top = 0
Width = 619
Height = 708
Align = alClient
BevelInner = bvNone
BevelOuter = bvNone
BorderStyle = bsNone
Color = 14211288
ParentColor = False
TabOrder = 0
object panWordlists: TPanel
AlignWithMargins = True
Left = 4
Top = 181
Width = 611
Height = 232
Margins.Left = 4
Margins.Top = 4
Margins.Right = 4
Margins.Bottom = 4
Align = alTop
BevelOuter = bvNone
TabOrder = 1
DesignSize = (
611
232)
object lblWordlists: TLabel
AlignWithMargins = True
Left = 12
Top = 4
Width = 64
Height = 17
Caption = 'Wordlists'
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -14
Font.Name = 'Tahoma'
Font.Style = [fsBold]
ParentFont = False
end
object lblReadOnly: TLabel
Left = 15
Top = 200
Width = 415
Height = 13
Caption =
'The editor was unable to parse the source file. Details shown he' +
're are read-only.'
end
object gridWordlists: TStringGrid
Left = 12
Top = 27
Width = 485
Height = 160
Anchors = [akLeft, akTop, akRight]
ColCount = 1
FixedCols = 0
FixedRows = 0
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRowSelect]
TabOrder = 0
OnDblClick = gridWordlistsDblClick
ColWidths = (
271)
RowHeights = (
24
24
24
24
24)
end
object cmdAddWordlist: TButton
Left = 503
Top = 27
Width = 101
Height = 25
Anchors = [akTop, akRight]
Caption = '&Add...'
TabOrder = 1
OnClick = cmdAddWordlistClick
end
object cmdRemoveWordlist: TButton
Left = 503
Top = 58
Width = 100
Height = 25
Anchors = [akTop, akRight]
Caption = 'Remove'
TabOrder = 2
OnClick = cmdRemoveWordlistClick
end
end
object panBasicInformation: TPanel
AlignWithMargins = True
Left = 4
Top = 6
Width = 611
Height = 167
Margins.Left = 4
Margins.Top = 6
Margins.Right = 4
Margins.Bottom = 4
Align = alTop
AutoSize = True
BevelOuter = bvNone
ParentColor = True
TabOrder = 0
DesignSize = (
611
167)
object lblFormat: TLabel
Left = 12
Top = 30
Width = 36
Height = 13
Caption = '&Format'
end
object lblBasicInformation: TLabel
AlignWithMargins = True
Left = 12
Top = 3
Width = 123
Height = 17
Caption = 'Basic Information'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -14
Font.Name = 'Tahoma'
Font.Style = [fsBold]
ParentFont = False
end
object lblWordBreaker: TLabel
Left = 12
Top = 56
Width = 71
Height = 13
Caption = '&Word breaker'
end
object lblComments: TLabel
Left = 12
Top = 83
Width = 50
Height = 13
Caption = 'Comme&nts'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object cbFormat: TComboBox
Left = 98
Top = 26
Width = 145
Height = 21
Style = csDropDownList
TabOrder = 0
OnClick = cbFormatClick
Items.Strings = (
'Wordlist (trie-1.0)'
'Custom (custom-1.0)')
end
object cbWordBreaker: TComboBox
Left = 98
Top = 53
Width = 145
Height = 21
Style = csDropDownList
TabOrder = 1
OnClick = cbWordBreakerClick
Items.Strings = (
'default'
'ascii'
'custom')
end
object memoComments: TMemo
Left = 98
Top = 80
Width = 506
Height = 87
Anchors = [akLeft, akTop, akRight]
BevelOuter = bvNone
TabOrder = 2
OnChange = memoCommentsChange
end
end
end
end
object pageSource: TTabSheet
Caption = 'Source'
ImageIndex = 9
end
object pageCompile: TTabSheet
Caption = 'Build'
ImageIndex = 1
object Panel1: TPanel
Left = 0
Top = 0
Width = 619
Height = 708
Align = alClient
BevelOuter = bvNone
Color = 14211288
ParentBackground = False
TabOrder = 0
object lblCongrats: TLabel
Left = 10
Top = 13
Width = 333
Height = 13
Caption =
'The keyboard must be compiled in order to distribute or install ' +
'it'
end
object Label5: TLabel
Left = 10
Top = 79
Width = 82
Height = 13
Caption = 'Target filename:'
end
object cmdCompile: TButton
Left = 10
Top = 40
Width = 137
Height = 25
Action = modActionsModelEditor.actModelCompile
TabOrder = 0
end
object cmdAddToProject: TButton
Left = 297
Top = 40
Width = 137
Height = 25
Action = modActionsMain.actProjectAddCurrentEditorFile
TabOrder = 1
end
object cmdOpenContainingFolder2: TButton
Left = 153
Top = 40
Width = 138
Height = 25
Caption = '&Open Containing Folder'
TabOrder = 2
OnClick = cmdOpenContainingFolder2Click
end
object panBuildLexicalModel: TPanel
Left = 10
Top = 112
Width = 424
Height = 353
BevelOuter = bvNone
Color = 15921906
ParentBackground = False
TabOrder = 3
object lblDebugHostCaption: TLabel
Left = 12
Top = 158
Width = 252
Height = 13
Caption = 'Debug host is active at following web addresses:'
end
object lblCrossPlatform: TLabel
Left = 12
Top = 14
Width = 237
Height = 17
Caption = 'Test Lexical Model in Web Browser'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -14
Font.Name = 'Tahoma'
Font.Style = [fsBold]
ParentFont = False
end
object Label1: TLabel
Left = 12
Top = 48
Width = 105
Height = 13
Caption = 'Keyboard for testing'
end
object Label2: TLabel
Left = 12
Top = 72
Width = 389
Height = 26
Caption =
'Optionally, select a compiled keyboard with which to test this l' +
'exical model. Any keyboards already loaded in the web debugger w' +
'ill also be available.'
WordWrap = True
end
object cmdTestLexicalModel: TButton
Left = 12
Top = 122
Width = 150
Height = 25
Action = modActionsModelEditor.actModelTest
TabOrder = 2
end
object cmdOpenDebugHost: TButton
Left = 12
Top = 286
Width = 189
Height = 25
Caption = 'Open &debugger in local browser'
TabOrder = 3
OnClick = cmdOpenDebugHostClick
end
object lbDebugHosts: TListBox
Left = 12
Top = 183
Width = 289
Height = 97
ItemHeight = 13
TabOrder = 4
end
object cmdSendURLsToEmail: TButton
Left = 12
Top = 317
Width = 189
Height = 25
Caption = 'Send addresses to &email...'
TabOrder = 5
OnClick = cmdSendURLsToEmailClick
end
object editTestKeyboard: TEdit
Left = 123
Top = 45
Width = 158
Height = 21
TabOrder = 0
OnChange = editTestKeyboardChange
end
object cmdBrowseTestKeyboard: TButton
Left = 287
Top = 43
Width = 75
Height = 25
Caption = '&Browse...'
TabOrder = 1
OnClick = cmdBrowseTestKeyboardClick
end
end
object editOutPath: TEdit
Left = 98
Top = 76
Width = 383
Height = 21
TabStop = False
ParentColor = True
ReadOnly = True
TabOrder = 4
end
end
end
end
object dlgAddWordlist: TOpenDialog
Options = [ofHideReadOnly, ofPathMustExist, ofEnableSizing]
Title = 'Create or Add Wordlist'
Left = 344
Top = 344
end
object dlgBrowseTestKeyboard: TOpenDialog
DefaultExt = 'js'
Filter = 'Compiled keyboard files (*.js)|*.js|All files (*.*)|*.*'
Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing]
Title = 'Select compiled keyboard to test with'
Left = 488
Top = 120
end
end

View file

@ -0,0 +1,569 @@
//TODO: CEF destruction is incorrect in this unit
unit Keyman.Developer.UI.UfrmModelEditor;
interface
uses
System.Classes,
System.Generics.Collections,
System.SysUtils,
System.Variants,
Vcl.ComCtrls,
Vcl.Controls,
Vcl.Dialogs,
Vcl.ExtCtrls,
Vcl.Forms,
Vcl.Graphics,
Vcl.Grids,
Vcl.StdCtrls,
Winapi.Messages,
Winapi.Windows,
Keyman.Developer.UI.dmActionsModelEditor,
dmActionsMain,
LeftTabbedPageControl,
UfrmMDIEditor,
UframeTextEditor,
Keyman.Developer.System.Project.ProjectFile,
Keyman.Developer.System.Project.modeltsProjectFile,
Keyman.Developer.UI.Project.modeltsProjectFileUI,
Keyman.Developer.UI.UframeWordlistEditor,
Keyman.Developer.System.LexicalModelParser,
Keyman.Developer.System.LexicalModelParserTypes;
type
TfrmModelEditor = class(TfrmTikeEditor)
pages: TLeftTabbedPageControl;
pageDetails: TTabSheet;
sbDetails: TScrollBox;
panWordlists: TPanel;
lblWordlists: TLabel;
gridWordlists: TStringGrid;
cmdAddWordlist: TButton;
cmdRemoveWordlist: TButton;
panBasicInformation: TPanel;
lblFormat: TLabel;
lblBasicInformation: TLabel;
pageSource: TTabSheet;
pageCompile: TTabSheet;
Panel1: TPanel;
lblCongrats: TLabel;
cmdCompile: TButton;
cmdAddToProject: TButton;
cmdOpenContainingFolder2: TButton;
panBuildLexicalModel: TPanel;
cbFormat: TComboBox;
cbWordBreaker: TComboBox;
lblWordBreaker: TLabel;
memoComments: TMemo;
lblComments: TLabel;
lblDebugHostCaption: TLabel;
lblCrossPlatform: TLabel;
cmdTestLexicalModel: TButton;
cmdOpenDebugHost: TButton;
lbDebugHosts: TListBox;
cmdSendURLsToEmail: TButton;
Label1: TLabel;
editTestKeyboard: TEdit;
cmdBrowseTestKeyboard: TButton;
Label2: TLabel;
lblReadOnly: TLabel;
dlgAddWordlist: TOpenDialog;
dlgBrowseTestKeyboard: TOpenDialog;
Label5: TLabel;
editOutPath: TEdit;
procedure FormDestroy(Sender: TObject);
procedure cmdAddWordlistClick(Sender: TObject);
procedure cmdRemoveWordlistClick(Sender: TObject);
procedure gridWordlistsDblClick(Sender: TObject);
procedure pagesChanging(Sender: TObject; var AllowChange: Boolean);
procedure FormCreate(Sender: TObject);
procedure cbFormatClick(Sender: TObject);
procedure cbWordBreakerClick(Sender: TObject);
procedure memoCommentsChange(Sender: TObject);
procedure cmdOpenContainingFolder2Click(Sender: TObject);
procedure cmdOpenDebugHostClick(Sender: TObject);
procedure cmdSendURLsToEmailClick(Sender: TObject);
procedure cmdBrowseTestKeyboardClick(Sender: TObject);
procedure editTestKeyboardChange(Sender: TObject);
private
type
TWordlist = class
Frame: TframeWordlistEditor;
Tab: TTabSheet;
Filename: string;
destructor Destroy; override;
end;
TWordlists = class(TObjectList<TWordlist>)
public
function IndexOfFilename(const Filename: string): Integer;
end;
private
model: TStrings;
parser: TLexicalModelParser;
wordlists: TWordlists;
frameSource: TframeTextEditor;
FSetup: Integer;
procedure FillDetails;
procedure EnableControls;
procedure UpdateWordlistTabs;
function AddWordlistTab(
const WordlistFilename: string): TfrmModelEditor.TWordlist;
function MoveDesignToSource: Boolean;
function MoveSourceToDesign: Boolean;
procedure SourceChanged(Sender: TObject);
function CheckModifiedWordlistsForRemoval(
newParser: TLexicalModelParser): Boolean;
{ Private declarations }
protected
function GetHelpTopic: string; override;
function DoOpenFile: Boolean; override;
function DoSaveFile: Boolean; override;
function GetFileNameFilter: string; override;
function GetDefaultExt: string; override;
function GetProjectFile: TProjectFile; override;
public
procedure FindError(const Filename: string; s: string; line: Integer); override; // I4081
procedure NotifyStartedWebDebug;
end;
implementation
uses
System.UITypes,
Keyman.Developer.System.Project.modeltsProjectFileAction,
TextFileFormat,
UmodWebHttpServer,
UfrmSendURLsToEmail,
utilexecute,
utilsystem;
{$R *.dfm}
function FormatToIndex(format: TLexicalModelFormat): Integer;
begin
Result := Ord(format) - 1; // unknown = -1
end;
function WordBreakerToIndex(wordBreaker: TLexicalModelWordBreaker): Integer;
begin
Result := Ord(wordBreaker) - 1; // unknown = -1
end;
function FormatFromIndex(format: Integer): TLexicalModelFormat;
begin
Result := TLexicalModelFormat(format+1); // unknown = -1
end;
function WordBreakerFromIndex(wordBreaker: Integer): TLexicalModelWordBreaker;
begin
Result := TLexicalModelWordBreaker(wordBreaker+1); // unknown = -1
end;
{ TfrmModelEditor }
function TfrmModelEditor.DoOpenFile: Boolean;
begin
model := TStringList.Create;
model.LoadFromFile(FileName);
parser := TLexicalModelParser.Create(model.Text);
wordlists := TWordlists.Create;
Inc(FSetup);
try
FillDetails;
UpdateWordlistTabs;
finally
Dec(FSetup);
end;
Result := True;
end;
function TfrmModelEditor.DoSaveFile: Boolean;
var
wordlist: TWordlist;
begin
for wordlist in wordlists do
begin
wordlist.Frame.SaveToFile(wordlist.Frame.Filename);
end;
model.Text := parser.Text;
model.SaveToFile(FileName);
editOutPath.Text := (ProjectFile as TmodelTsProjectFile).TargetFilename; // I4688
Result := True;
end;
procedure TfrmModelEditor.editTestKeyboardChange(Sender: TObject);
begin
if FSetup > 0 then
Exit;
(ProjectFile as TmodelTsProjectFile).TestKeyboard := editTestKeyboard.Text;
end;
procedure TfrmModelEditor.EnableControls;
var
e: Boolean;
begin
e := parser.IsEditable;
{ Details tab }
lblFormat.Enabled := e;
cbFormat.Enabled := e;
lblWordBreaker.Enabled := e;
cbWordBreaker.Enabled := e;
lblComments.Enabled := e;
memoComments.Enabled := e;
cmdAddWordlist.Enabled := e;
gridWordlists.Enabled := e and (parser.Wordlists.Count > 0);
cmdRemoveWordlist.Enabled := e and (parser.Wordlists.Count > 0);
lblReadOnly.Visible := not e;
{ Build tab }
cmdOpenDebugHost.Enabled := lbDebugHosts.ItemIndex >= 0;
cmdSendURLsToEmail.Enabled := lbDebugHosts.Items.Count > 0; // I4506
end;
procedure TfrmModelEditor.NotifyStartedWebDebug;
begin
lbDebugHosts.Clear;
modWebHttpServer.GetURLs(lbDebugHosts.Items);
if lbDebugHosts.Items.Count > 0 then
lbDebugHosts.ItemIndex := 0;
EnableControls;
end;
procedure TfrmModelEditor.FindError(const Filename: string; s: string;
line: Integer);
begin
inherited;
// TODO
end;
procedure TfrmModelEditor.FormCreate(Sender: TObject);
begin
inherited;
Inc(FSetup);
try
frameSource := TframeTextEditor.Create(Self);
frameSource.Parent := pageSource;
frameSource.Align := alClient;
frameSource.EditorFormat := efJS;
frameSource.Visible := True;
frameSource.OnChanged := SourceChanged;
frameSource.TextFileFormat := tffUTF8;
pages.ActivePage := pageDetails;
finally
Dec(FSetup);
end;
end;
procedure TfrmModelEditor.FormDestroy(Sender: TObject);
begin
inherited;
FreeAndNil(parser);
FreeAndNil(model);
FreeAndNil(wordlists);
end;
function TfrmModelEditor.GetDefaultExt: string;
begin
Result := '.model.ts'; // TODO: test if this actually works!
end;
function TfrmModelEditor.GetFileNameFilter: string;
begin
Result := 'Lexical model files (*.model.ts)|*.model.ts|All files (*.*)|*.*';
end;
function TfrmModelEditor.GetHelpTopic: string;
begin
Result := ''; //SHelpTopic_Context_WordlistEditor; // TODO: use a better topic
end;
function TfrmModelEditor.GetProjectFile: TProjectFile;
begin
Result := inherited GetProjectFile;
if not Assigned(Result) then
begin
FStandaloneProjectFile := TmodelTsProjectFileAction.Create(nil, FileName, nil);
Result := FStandaloneProjectFile;
end;
end;
procedure TfrmModelEditor.gridWordlistsDblClick(Sender: TObject);
begin
pages.ActivePageIndex := gridWordlists.Row + 1;
end;
procedure TfrmModelEditor.memoCommentsChange(Sender: TObject);
begin
if FSetup > 0 then
Exit;
parser.Comment := memoComments.Text;
Modified := True;
end;
procedure TfrmModelEditor.SourceChanged(Sender: TObject);
begin
if FSetup > 0 then
Exit;
Modified := True;
end;
function TfrmModelEditor.CheckModifiedWordlistsForRemoval(newParser: TLexicalModelParser): Boolean;
var
wordlist: TWordlist;
begin
for wordlist in wordlists do
begin
if (newParser.Wordlists.IndexOf(wordlist.Filename) < 0) and
wordlist.Frame.Modified then
begin
case MessageDlg(Format('The wordlist %s has been removed but has been modified. Save changes before removal?',
[ExtractFileName(wordlist.Filename)]), mtConfirmation, mbYesNoCancel, 0) of
mrYes: wordlist.Frame.SaveToFile(wordlist.Frame.Filename);
mrNo: ;
mrCancel: Exit(False);
end;
end;
end;
Result := True;
end;
function TfrmModelEditor.MoveSourceToDesign: Boolean;
var
newParser: TLexicalModelParser;
begin
Inc(FSetup);
try
newParser := TLexicalModelParser.Create(frameSource.EditorText);
if not CheckModifiedWordlistsForRemoval(newParser) then
begin
FreeAndNil(newParser);
Exit(False);
end;
FreeAndNil(parser);
parser := newParser;
FillDetails;
UpdateWordlistTabs;
finally
Dec(FSetup);
end;
Result := True;
end;
function TfrmModelEditor.MoveDesignToSource: Boolean;
begin
frameSource.EditorText := parser.Text;
Result := True;
end;
procedure TfrmModelEditor.pagesChanging(Sender: TObject;
var AllowChange: Boolean);
begin
if FSetup > 0 then Exit;
if pages.ActivePage = pageSource then
AllowChange := MoveSourceToDesign
else
AllowChange := MoveDesignToSource
end;
{ --------- Details tab --------- }
procedure TfrmModelEditor.FillDetails;
var
i: Integer;
begin
cbFormat.ItemIndex := FormatToIndex(parser.Format);
cbWordBreaker.ItemIndex := WordBreakerToIndex(parser.WordBreaker);
memoComments.Text := parser.Comment;
if parser.Wordlists.Count = 0 then
begin
gridWordlists.RowCount := 1;
gridWordlists.Cells[0, 0] := '';
end
else
begin
gridWordlists.RowCount := parser.Wordlists.Count;
for i := 0 to parser.Wordlists.Count - 1 do
begin
gridWordlists.Cells[0, i] := parser.Wordlists[i];
end;
end;
editOutPath.Text := (ProjectFile as TmodelTsProjectFile).TargetFilename; // I4688
editTestKeyboard.Text := (ProjectFile as TmodelTsProjectFile).TestKeyboard;
EnableControls;
end;
procedure TfrmModelEditor.UpdateWordlistTabs;
var
i, n: Integer;
wordlist: TWordlist;
begin
// Remove tabs that are no longer listed
for i := wordlists.Count - 1 downto 0 do
begin
if parser.Wordlists.IndexOf(wordlists[i].Filename) < 0 then
wordlists.Delete(i);
end;
// Add new tabs
for i := 0 to parser.Wordlists.Count - 1 do
begin
n := wordlists.IndexOfFilename(parser.Wordlists[i]);
if n < 0 then
begin
wordlist := AddWordlistTab(parser.Wordlists[i]);
wordlist.Tab.PageIndex := i + 1;
end
else
wordlists[n].Tab.PageIndex := i + 1;
end;
end;
function TfrmModelEditor.AddWordlistTab(const WordlistFilename: string): TfrmModelEditor.TWordlist;
begin
Result := TWordlist.Create;
wordlists.Add(Result);
Result.Filename := WordlistFilename;
Result.Tab := TTabSheet.Create(Self);
Result.Tab.TabVisible := True;
Result.Tab.ImageIndex := 17; // 'spreadsheet'
Result.Tab.Caption := ExtractFileName(Result.Filename);
Result.Tab.PageControl := pages;
Result.Frame := TframeWordlistEditor.Create(Self);
Result.Frame.LoadFromFile(ExtractFilePath(Filename) + WordlistFilename);
Result.Frame.Align := alClient;
Result.Frame.Parent := Result.Tab;
Result.Frame.Visible := True;
end;
{ TfrmModelEditor.TWordlists }
function TfrmModelEditor.TWordlists.IndexOfFilename(
const Filename: string): Integer;
begin
for Result := 0 to Count - 1 do
if SameText(Items[Result].Filename, Filename) then
Exit;
Result := -1;
end;
{ Wordlist management }
procedure TfrmModelEditor.cbFormatClick(Sender: TObject);
begin
if FSetup > 0 then
Exit;
parser.Format := FormatFromIndex(cbFormat.ItemIndex);
Modified := True;
end;
procedure TfrmModelEditor.cbWordBreakerClick(Sender: TObject);
begin
if FSetup > 0 then
Exit;
parser.WordBreaker := WordBreakerFromIndex(cbWordBreaker.ItemIndex);
Modified := True;
end;
procedure TfrmModelEditor.cmdAddWordlistClick(Sender: TObject);
begin
if dlgAddWordlist.Execute then
begin
parser.Wordlists.Add(ExtractRelativePath(Filename, dlgAddWordlist.FileName));
Inc(FSetup);
try
FillDetails;
UpdateWordlistTabs;
finally
Dec(FSetup);
end;
Modified := True;
end;
end;
procedure TfrmModelEditor.cmdBrowseTestKeyboardClick(Sender: TObject);
begin
if dlgBrowseTestKeyboard.Execute then
editTestKeyboard.Text := dlgBrowseTestKeyboard.FileName;
end;
procedure TfrmModelEditor.cmdOpenContainingFolder2Click(Sender: TObject);
begin
OpenContainingFolder(FileName);
end;
procedure TfrmModelEditor.cmdOpenDebugHostClick(Sender: TObject);
begin
TUtilExecute.URL(lbDebugHosts.Items[lbDebugHosts.ItemIndex]);
end;
procedure TfrmModelEditor.cmdRemoveWordlistClick(Sender: TObject);
var
wordlist: TWordlist;
begin
wordlist := wordlists[gridWordlists.Row];
if wordlist.Frame.Modified then
begin
case MessageDlg(Format('Save changes to wordlist %s before removing it?',
[ExtractFileName(wordlist.Filename)]),
mtConfirmation, mbYesNoCancel, 0) of
mrYes: wordlist.Frame.SaveToFile(wordlist.Frame.Filename);
mrNo: ;
mrCancel: Exit;
end;
end;
parser.Wordlists.Delete(gridWordlists.Row);
Inc(FSetup);
try
FillDetails;
UpdateWordlistTabs;
finally
Dec(FSetup);
end;
Modified := True;
end;
procedure TfrmModelEditor.cmdSendURLsToEmailClick(Sender: TObject);
begin
with TfrmSendURLsToEmail.Create(Application.MainForm) do
try
//TODO: KeyboardName := Self.FKeyboardParser.GetSystemStoreValue(ssName);
Hosts.Assign(lbDebugHosts.Items);
ShowModal;
finally
Free;
end;
end;
{ TfrmModelEditor.TWordlist }
destructor TfrmModelEditor.TWordlist.Destroy;
begin
Frame.Free;
Tab.Free;
inherited Destroy;
end;
end.

View file

@ -5,74 +5,8 @@ inherited frmWordlistEditor: TfrmWordlistEditor
ClientHeight = 299
ClientWidth = 635
Font.Name = 'Tahoma'
OnResize = FormResize
ExplicitWidth = 635
ExplicitHeight = 299
PixelsPerInch = 96
TextHeight = 13
object pages: TPageControl
Left = 0
Top = 0
Width = 635
Height = 299
ActivePage = pageDesign
Align = alClient
TabOrder = 0
TabPosition = tpBottom
OnChanging = pagesChanging
object pageDesign: TTabSheet
Caption = 'Design'
ImageIndex = -1
object gridWordlist: TStringGridEditControlled
Left = 0
Top = 0
Width = 627
Height = 232
Align = alClient
ColCount = 3
DefaultRowHeight = 16
DefaultDrawing = False
FixedCols = 0
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goEditing, goTabs, goAlwaysShowEditor]
TabOrder = 0
OnClick = gridWordlistClick
OnDrawCell = gridWordlistDrawCell
OnSetEditText = gridWordlistSetEditText
ExplicitHeight = 273
end
object panGridControls: TPanel
Left = 0
Top = 232
Width = 627
Height = 41
Align = alBottom
TabOrder = 1
ExplicitLeft = 224
ExplicitTop = 120
ExplicitWidth = 185
object cmdDeleteRow: TButton
Left = 0
Top = 6
Width = 75
Height = 25
Caption = '&Delete row'
TabOrder = 0
OnClick = cmdDeleteRowClick
end
object cmdSortByFrequency: TButton
Left = 81
Top = 6
Width = 104
Height = 25
Caption = '&Sort by frequency'
TabOrder = 1
OnClick = cmdSortByFrequencyClick
end
end
end
object pageCode: TTabSheet
Caption = 'Code'
ImageIndex = -1
end
end
end

View file

@ -13,46 +13,17 @@ uses
Vcl.Dialogs,
Vcl.Forms,
Vcl.Graphics,
Vcl.Grids,
StringGridEditControlled,
Keyman.System.WordlistTsvFile,
UframeTextEditor,
UfrmMDIEditor, Vcl.StdCtrls, Vcl.ExtCtrls;
Keyman.Developer.UI.UframeWordlistEditor,
UfrmMDIEditor;
type
TfrmWordlistEditor = class(TfrmTikeEditor)
pages: TPageControl;
pageDesign: TTabSheet;
pageCode: TTabSheet;
gridWordlist: TStringGridEditControlled;
panGridControls: TPanel;
cmdDeleteRow: TButton;
cmdSortByFrequency: TButton;
procedure pagesChanging(Sender: TObject; var AllowChange: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure gridWordlistSetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: string);
procedure gridWordlistDrawCell(Sender: TObject; ACol, ARow: Integer;
ARect: TRect; State: TGridDrawState);
procedure cmdDeleteRowClick(Sender: TObject);
procedure gridWordlistClick(Sender: TObject);
procedure cmdSortByFrequencyClick(Sender: TObject);
private
FWordlist: TWordlistTsvFile;
frameSource: TframeTextEditor;
FSetup: Integer;
procedure UpdateData;
function MoveCodeToWordlist: Boolean;
procedure FillCode;
procedure FillGrid;
function MoveDesignToWordlist: Boolean;
procedure SourceChanged(Sender: TObject);
procedure FillGridNewRow;
procedure EnableControls;
frame: TframeWordlistEditor;
procedure FrameModified(Sender: TObject);
protected
function GetHelpTopic: string; override;
function DoOpenFile: Boolean; override;
@ -74,97 +45,41 @@ uses
UfrmMain,
UfrmMessages;
const
ColWidth_Word = 120;
ColWidth_Frequency = 64;
S_AddRowText = 'Add word...';
{ TfrmWordlistEditor }
procedure TfrmWordlistEditor.FormCreate(Sender: TObject);
begin
inherited;
Inc(FSetup);
try
FWordlist := TWordlistTsvFile.Create;
frameSource := TframeTextEditor.Create(Self);
frameSource.Parent := pageCode;
frameSource.Align := alClient;
frameSource.EditorFormat := efWordlistTsv;
frameSource.Visible := True;
frameSource.OnChanged := SourceChanged;
frameSource.TextFileFormat := tffUTF8;
//TODO: frameSource.UseTabs := True;
pages.ActivePage := pageDesign;
gridWordlist.Cells[0, 0] := 'Word Form';
gridWordlist.Cells[1, 0] := 'Count';
gridWordlist.Cells[2, 0] := 'Comment';
gridWordlist.ColWidths[0] := ColWidth_Word;
gridWordlist.ColWidths[1] := ColWidth_Frequency;
gridWordlist.ColWidths[2] := gridWordlist.ClientWidth - ColWidth_Word - ColWidth_Frequency - 2;
finally
Dec(FSetup);
end;
frame := TframeWordlistEditor.Create(Self);
frame.Align := alClient;
frame.Parent := Self;
frame.OnModifiedChanged := FrameModified;
end;
procedure TfrmWordlistEditor.FormDestroy(Sender: TObject);
begin
inherited;
FWordlist.Free;
frame.Free;
end;
procedure TfrmWordlistEditor.FormResize(Sender: TObject);
procedure TfrmWordlistEditor.FrameModified(Sender: TObject);
begin
inherited;
gridWordlist.ColWidths[2] := gridWordlist.ClientWidth - ColWidth_Word - ColWidth_Frequency - 2;
end;
procedure TfrmWordlistEditor.cmdDeleteRowClick(Sender: TObject);
begin
FWordlist.RemoveWord(gridWordlist.Row-1);
FillGrid;
EnableControls;
Modified := True;
end;
procedure TfrmWordlistEditor.cmdSortByFrequencyClick(Sender: TObject);
begin
FWordlist.SortByFrequency;
FillGrid;
Modified := True;
Modified := frame.Modified;
end;
function TfrmWordlistEditor.DoOpenFile: Boolean;
begin
RefreshOptions;
if FileExists(FileName) then
begin
FWordlist.LoadFromFile(FileName);
UpdateData;
end;
Result := True;
Result := frame.LoadFromFile(Filename);
end;
function TfrmWordlistEditor.DoSaveFile: Boolean;
begin
MoveCodeToWordlist; // Does nothing if not in code page
FWordlist.SaveToFile(FileName);
Result := True;
end;
procedure TfrmWordlistEditor.EnableControls;
var
e: Boolean;
begin
e := gridWordlist.Row < gridWordlist.RowCount - 1;
cmdDeleteRow.Enabled := e;
cmdSortByFrequency.Enabled := e;
Result := frame.SaveToFile(Filename);
end;
procedure TfrmWordlistEditor.FindError(const Filename: string; s: string; line: Integer);
begin
//
frame.FindError(Filename, s, line);
end;
function TfrmWordlistEditor.GetDefaultExt: string;
@ -182,142 +97,4 @@ begin
Result := SHelpTopic_Context_WordlistEditor;
end;
procedure TfrmWordlistEditor.gridWordlistClick(Sender: TObject);
begin
EnableControls;
end;
procedure TfrmWordlistEditor.gridWordlistDrawCell(Sender: TObject; ACol,
ARow: Integer; ARect: TRect; State: TGridDrawState);
var
LText: string;
begin
inherited;
if ARow = gridWordlist.RowCount - 1 then
begin
// Drawing last row
gridWordlist.Canvas.Font.Style := [fsItalic];
end
else if gridWordlist.Cells[0, ARow] = '#' then
begin
// Drawing a comment cell
gridWordlist.Canvas.Font.Style := [fsBold];
end
else
gridWordlist.Canvas.Font.Style := [];
LText := gridWordlist.Cells[ACol, ARow];
gridWordlist.Canvas.TextRect(ARect, ARect.Left+2,
ARect.Top+((ARect.Height - gridWordlist.Canvas.TextHeight(LText)) div 2), LText);
end;
procedure TfrmWordlistEditor.gridWordlistSetEditText(Sender: TObject; ACol,
ARow: Integer; const Value: string);
var
w: TWordlistWord;
begin
if FSetup > 0 then Exit;
Inc(FSetup);
try
Modified := True;
if ARow = gridWordlist.RowCount - 1 then
begin
if (Value = '') or (Value = S_AddRowText) then
Exit;
w.Word := Value;
w.Frequency := 0;
w.Comment := '';
FWordlist.AddWord(w);
gridWordlist.RowCount := gridWordlist.RowCount + 1;
FillGridNewRow;
end
else
begin
w := FWordlist.Word[ARow-1];
case ACol of
0: w.Word := Value;
1: w.Frequency := StrToIntDef(Value, 0);
2: w.Comment := Value;
end;
FWordlist.Word[ARow-1] := w;
end;
finally
Dec(FSetup);
end;
end;
procedure TfrmWordlistEditor.pagesChanging(Sender: TObject;
var AllowChange: Boolean);
begin
if FSetup > 0 then Exit;
if pages.ActivePage = pageCode then
AllowChange := MoveCodeToWordlist
else
AllowChange := MoveDesignToWordlist
end;
function TfrmWordlistEditor.MoveCodeToWordlist: Boolean;
begin
if pages.ActivePage <> pageCode then
Exit(False);
FWordlist.Text := frameSource.EditorText;
FillGrid;
Result := True;
end;
function TfrmWordlistEditor.MoveDesignToWordlist: Boolean;
begin
FillCode;
Result := True;
end;
procedure TfrmWordlistEditor.UpdateData;
begin
if pages.ActivePage = pageCode
then FillCode
else FillGrid;
end;
procedure TfrmWordlistEditor.SourceChanged(Sender: TObject);
begin
if FSetup = 0 then
Modified := True;
end;
procedure TfrmWordlistEditor.FillCode;
begin
frameSource.EditorText := FWordlist.Text;
end;
procedure TfrmWordlistEditor.FillGrid;
var
i: Integer;
w: TWordlistWord;
begin
gridWordlist.RowCount := FWordlist.Count + 2;
for i := 0 to FWordlist.Count - 1 do
begin
w := FWordlist.Word[i];
gridWordlist.Cells[0, i+1] := w.Word;
if w.Frequency = 0
then gridWordlist.Cells[1, i+1] := ''
else gridWordlist.Cells[1, i+1] := IntToStr(w.Frequency);
gridWordlist.Cells[2, i+1] := w.Comment;
end;
FillGridNewRow;
gridWordlist.FixedRows := 1;
end;
procedure TfrmWordlistEditor.FillGridNewRow;
begin
gridWordlist.Cells[0, gridWordlist.RowCount - 1] := S_AddRowText;
gridWordlist.Cells[1, gridWordlist.RowCount - 1] := '';
gridWordlist.Cells[2, gridWordlist.RowCount - 1] := '';
EnableControls;
end;
end.

View file

@ -1119,6 +1119,9 @@ inherited frmPackageEditor: TfrmPackageEditor
object pageSource: TTabSheet
Caption = 'Source'
ImageIndex = 9
ExplicitLeft = 0
ExplicitWidth = 0
ExplicitHeight = 0
end
object pageCompile: TTabSheet
Caption = 'Compile'

View file

@ -1672,7 +1672,7 @@ var
FHasDesktopTarget, FHasMobileTarget: Boolean;
begin
FHasDesktopTarget := False;
FHasMobileTarget := False;
FHasMobileTarget := pack.LexicalModels.Count > 0;
for k in pack.Keyboards do
begin
for i := 0 to pack.Files.Count - 1 do

View file

@ -54,13 +54,23 @@ type
property Name: string read FName;
end;
TWebDebugModelInfo = class
strict private
FFilename: string;
public
constructor Create(const AFilename: string);
property Filename: string read FFilename;
end;
TDebuggerHttpResponder = class(TBaseHttpResponder)
private
FKeyboardsCS, FPackagesCS: TCriticalSection; // I4036
FModelsCS, FKeyboardsCS, FPackagesCS: TCriticalSection; // I4036
FModels: TObjectDictionary<string,TWebDebugModelInfo>;
FKeyboards: TObjectDictionary<string,TWebDebugKeyboardInfo>; // I4063
FPackages: TObjectDictionary<string,TWebDebugPackageInfo>;
function GetKeyboardStoredFileName(const WebFilename: string): string;
function GetPackageStoredFileName(const WebFilename: string): string;
function GetModelStoredFileName(const WebFilename: string): string;
public
constructor Create;
destructor Destroy; override;
@ -68,6 +78,8 @@ type
procedure UnregisterKeyboard(const Filename: string);
procedure RegisterPackage(const Filename, Name: string);
procedure UnregisterPackage(const Filename: string);
procedure RegisterModel(const Filename: string);
procedure UnregisterModel(const Filename: string);
procedure ProcessRequest(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
@ -114,6 +126,9 @@ begin
FPackagesCS := TCriticalSection.Create;
FPackages := TObjectDictionary<string,TWebDebugPackageInfo>.Create; // I4063
FModelsCS := TCriticalSection.Create;
FModels := TObjectDictionary<string,TWebDebugModelInfo>.Create; // I4063
end;
destructor TDebuggerHttpResponder.Destroy;
@ -124,6 +139,9 @@ begin
FreeAndNil(FPackages);
FreeAndNil(FPackagesCS); // I4036
FreeAndNil(FModels);
FreeAndNil(FModelsCS); // I4036
inherited Destroy;
end;
@ -139,6 +157,18 @@ begin
end;
end;
function TDebuggerHttpResponder.GetModelStoredFileName(
const WebFilename: string): string;
begin
FModelsCS.Enter; // I4036
try
if FModels.ContainsKey(WebFilename) then Result := FModels[WebFilename].Filename
else Result := '';
finally
FModelsCS.Leave;
end;
end;
function TDebuggerHttpResponder.GetPackageStoredFileName(
const WebFilename: string): string;
begin
@ -214,9 +244,10 @@ procedure TDebuggerHttpResponder.ProcessRequest(AContext: TIdContext;
key: string;
response: string;
value: TWebDebugKeyboardInfo;
src: string;
id, src: string;
n: Integer;
srcVersion: string;
model: string;
begin
// Get dynamic keyboard registration
@ -263,6 +294,17 @@ procedure TDebuggerHttpResponder.ProcessRequest(AContext: TIdContext;
FKeyboardsCS.Leave;
end;
FModelsCS.Enter;
try
for model in FModels.Keys do
begin
id := ChangeFileExt(model, '');
response := response + Format('registerModel("%s", "%s");', [id, model]);
end;
finally
FModelsCS.Leave;
end;
response := response + '})();';
AResponseInfo.CharSet := 'UTF-8';
@ -605,6 +647,26 @@ begin
Exit;
end;
end
else if Copy(doc, 1, 6) = 'model/' then
begin
Delete(doc, 1, 6);
// Models always expire immediately
AResponseInfo.Expires := EncodeDate(1990, 1, 1); // I4037
AResponseInfo.CacheControl := 'no-cache, no-store'; // I4037
AResponseInfo.LastModified := Now; // I4037
if not FFileRegExp.Exec(doc) then
begin
Respond404;
Exit;
end;
doc := GetModelStoredFileName(doc);
if doc = '' then
begin
Respond404;
Exit;
end;
end
else
begin
if not FFileRegExp.Exec(doc) then
@ -650,6 +712,19 @@ begin
end;
end;
procedure TDebuggerHttpResponder.RegisterModel(const Filename: string);
var
m: TWebDebugModelInfo;
begin
m := TWebDebugModelInfo.Create(Filename);
FModelsCS.Enter;
try
FModels.AddOrSetValue(ExtractFileName(Filename), m);
finally
FModelsCS.Leave;
end;
end;
procedure TDebuggerHttpResponder.RegisterPackage(const Filename, Name: string);
var
p: TWebDebugPackageInfo;
@ -673,6 +748,16 @@ begin
end;
end;
procedure TDebuggerHttpResponder.UnregisterModel(const Filename: string);
begin
FModelsCS.Enter; // I4036
try
FModels.Remove(ExtractFileName(Filename));
finally
FModelsCS.Leave;
end;
end;
procedure TDebuggerHttpResponder.UnregisterPackage(const Filename: string);
begin
FPackagesCS.Enter; // I4036
@ -798,4 +883,12 @@ begin
FName := AName;
end;
{ TWebDebugModelInfo }
constructor TWebDebugModelInfo.Create(const AFilename: string);
begin
inherited Create;
FFilename := AFilename;
end;
end.

View file

@ -0,0 +1,234 @@
unit Keyman.Developer.System.LexicalModelParser;
interface
uses
System.Classes,
System.RegularExpressions,
Keyman.Developer.System.LexicalModelParserTypes;
type
TLexicalModelParser = class
private
FText: TStrings;
FModified: Boolean;
FComment: string;
FFormat: TLexicalModelFormat;
FWordlists: TStrings;
FWordBreaker: TLexicalModelWordBreaker;
FIsEditable: Boolean;
function GetText: string;
procedure PrepareText;
procedure SetComment(const Value: string);
procedure SetFormat(const Value: TLexicalModelFormat);
procedure SetWordBreaker(const Value: TLexicalModelWordBreaker);
procedure Parse;
procedure Modify;
function ReplaceFormat(const m: TMatch): string;
function ReplaceWordBreaker(const m: TMatch): string;
function ReplaceSources(const m: TMatch): string;
function ReplaceComment(const m: TMatch): string;
procedure WordlistsChange(Sender: TObject);
public
constructor Create(Source: string);
destructor Destroy; override;
property Text: string read GetText;
property Format: TLexicalModelFormat read FFormat write SetFormat;
property WordBreaker: TLexicalModelWordBreaker read FWordBreaker write SetWordBreaker;
property Wordlists: TStrings read FWordlists;
property Comment: string read FComment write SetComment;
property IsEditable: Boolean read FIsEditable;
end;
implementation
uses
System.SysUtils;
{ TLexicalModelParser }
const
SComment = '^\s*\/\*(.+?)\*\/';
SFormat = 'format\s*:\s*([''"])(.+?)(\1)';
SWordBreaker = 'wordBreaker\s*:\s*([''"])(.+?)(\1)';
SSources = 'sources\s*:\s*\[(.+?)\]';
SSource = '\s*([''"])(.+?)(\1)\s*(,?)';
constructor TLexicalModelParser.Create(Source: string);
begin
inherited Create;
FWordlists := TStringList.Create;
(FWordlists as TStringList).OnChange := WordlistsChange;
FText := TStringList.Create;
FText.Text := Source;
Parse;
FModified := False;
end;
destructor TLexicalModelParser.Destroy;
begin
FreeAndNil(FWordlists);
FreeAndNil(FText);
inherited Destroy;
end;
function TLexicalModelParser.GetText: string;
begin
PrepareText;
Result := FText.Text;
end;
procedure TLexicalModelParser.Modify;
begin
FModified := True;
end;
procedure TLexicalModelParser.Parse;
var
re: TRegEx;
m: TMatch;
s: string;
begin
// Long term, we should probably consider using the TypeScript compiler
// to real-time generate an AST and work from that. But that introduces a
// layer of glue to the Delphi code that I don't want to get into just now.
FIsEditable := True;
FFormat := lmfUnknown;
FWordBreaker := lmwbUnknown;
FComment := '';
s := FText.Text;
// /* Comment */
m := TRegEx.Match(s, SComment, [roSingleLine]);
if m.Success then
FComment := m.Groups[1].Value;
// format:
m := TRegEx.Match(s, SFormat, [roMultiLine]);
if m.Success then
FFormat := TLexicalModelParserTypes.FormatFromText(m.Groups[2].Value);
// wordBreaker:
m := TRegEx.Match(s, SWordBreaker, [roMultiLine]);
if m.Success then
FWordBreaker := TLexicalModelParserTypes.WordBreakerFromText(m.Groups[2].Value);
// sources:
FWordlists.Clear;
m := TRegEx.Match(s, SSources, [roMultiLine]);
if m.Success then
begin
re := TRegEx.Create(SSource, [roMultiLine]);
m := re.Match(m.Groups[1].Value);
while m.Success do
begin
FWordlists.Add(m.Groups[2].Value);
m := m.NextMatch;
end;
end
else
FIsEditable := False;
FIsEditable := FIsEditable and (FFormat <> lmfUnknown) and (FWordBreaker <> lmwbUnknown);
end;
function TLexicalModelParser.ReplaceComment(const m: TMatch): string;
begin
if FComment = ''
then Result := ''
else Result := '/*'+FComment+'*/';
end;
function TLexicalModelParser.ReplaceFormat(const m: TMatch): string;
begin
Result := m.Value.Substring(0, m.Groups[2].Index - m.Index) +
TLexicalModelParserTypes.FormatToText(FFormat) +
m.Value.Substring(m.Groups[2].Index - m.Index + m.Groups[2].Length);
end;
function TLexicalModelParser.ReplaceWordBreaker(const m: TMatch): string;
begin
Result := m.Value.Substring(0, m.Groups[2].Index - m.Index) +
TLexicalModelParserTypes.WordBreakerToText(FWordBreaker) +
m.Value.Substring(m.Groups[2].Index - m.Index + m.Groups[2].Length);
end;
function TLexicalModelParser.ReplaceSources(const m: TMatch): string;
var
sources: string;
source: string;
begin
sources := '';
for source in FWordlists do
begin
if sources <> '' then
sources := sources + ', ';
sources := sources + '''' + source + ''''; // assuming no quote characters
end;
Result := m.Value.Substring(0, m.Groups[1].Index - m.Index) +
sources +
m.Value.Substring(m.Groups[1].Index - m.Index + m.Groups[1].Length);
end;
procedure TLexicalModelParser.PrepareText;
var
s: string;
begin
if not FModified then Exit;
s := FText.Text;
// Replace tokens
s := TRegEx.Replace(s, SFormat, ReplaceFormat, [roMultiLine]);
s := TRegEx.Replace(s, SWordBreaker, ReplaceWordBreaker, [roMultiLine]);
s := TRegEx.Replace(s, SSources, ReplaceSources, [roMultiLine]);
// Replace, remove or add comment
if TRegEx.IsMatch(s, SComment, [roSingleLine]) then
s := TRegEx.Replace(s, SComment, ReplaceComment, [roSingleLine])
else if FComment <> '' then
s := '/*'+FComment+'*/'#13#10+s;
FText.Text := s;
end;
procedure TLexicalModelParser.SetComment(const Value: string);
begin
Assert(FIsEditable);
if FComment <> Value then
begin
FComment := Value;
Modify;
end;
end;
procedure TLexicalModelParser.SetFormat(const Value: TLexicalModelFormat);
begin
Assert(FIsEditable);
if FFormat <> Value then
begin
FFormat := Value;
Modify;
end;
end;
procedure TLexicalModelParser.SetWordBreaker(const Value: TLexicalModelWordBreaker);
begin
Assert(FIsEditable);
if FWordBreaker <> Value then
begin
FWordBreaker := Value;
Modify;
end;
end;
procedure TLexicalModelParser.WordlistsChange(Sender: TObject);
begin
Modify;
end;
end.

View file

@ -0,0 +1,52 @@
unit Keyman.Developer.System.LexicalModelParserTypes;
interface
type
TLexicalModelFormat = (lmfUnknown, lmfTrie10, lmfCustom10);
TLexicalModelWordBreaker = (lmwbUnknown, lmwbDefault, lmwbAscii, lmwbCustom);
TLexicalModelParserTypes = class sealed
private
const
SLexicalModelFormats: array[TLexicalModelFormat] of string = ('?', 'trie-1.0', 'custom-1.0');
SLexicalModelWordBreakers: array[TLexicalModelWordBreaker] of string = ('?', 'default', 'ascii', 'custom');
LexicalModelFormats: set of TLexicalModelFormat = [lmfUnknown..lmfCustom10];
LexicalModelWordBreakers: set of TLexicalModelWordBreaker = [lmwbUnknown..lmwbCustom];
public
class function FormatFromText(const Value: string): TLexicalModelFormat; static;
class function FormatToText(const Value: TLexicalModelFormat): string; static;
class function WordBreakerFromText(const Value: string): TLexicalModelWordBreaker; static;
class function WordBreakerToText(const Value: TLexicalModelWordBreaker): string; static;
end;
implementation
uses
System.SysUtils;
class function TLexicalModelParserTypes.FormatFromText(const Value: string): TLexicalModelFormat;
begin
for Result in LexicalModelFormats do
if SLexicalModelFormats[Result].Equals(Value) then Exit;
Result := lmfUnknown;
end;
class function TLexicalModelParserTypes.FormatToText(const Value: TLexicalModelFormat): string;
begin
Result := SLexicalModelFormats[Value];
end;
class function TLexicalModelParserTypes.WordBreakerFromText(const Value: string): TLexicalModelWordBreaker;
begin
for Result in LexicalModelWordBreakers do
if SLexicalModelWordBreakers[Result].Equals(Value) then Exit;
Result := lmwbUnknown;
end;
class function TLexicalModelParserTypes.WordBreakerToText(const Value: TLexicalModelWordBreaker): string;
begin
Result := SLexicalModelWordBreakers[Value];
end;
end.

View file

@ -1116,7 +1116,15 @@ begin
try
j.AddPair('x', TJSONNumber.Create(X));
j.AddPair('y', TJSONNumber.Create(Y));
j.AddPair('text', cdo.Text[cdo.InsertType]);
// The character map insert format actually only
// makes sense for the .kmn source editor. For all
// other contexts, we currently only support cmimCharacter.
// It would be possible to do \uxxxx for JS/JSON etc but
// for now that is low priority.
if FEditorFormat = efKMN
then j.AddPair('text', cdo.Text[cdo.InsertType])
else j.AddPair('text', cdo.Text[cmimCharacter]);
ExecuteCommand('charmapDragDrop', j);
finally
j.Free;

View file

@ -2950,7 +2950,19 @@ inherited frmKeymanDeveloper: TfrmKeymanDeveloper
Action = modActionsMain.actProjectSettings
end
end
object Keyboards1: TMenuItem
object mnuModel: TMenuItem
Caption = '&Model'
object CompileModel1: TMenuItem
Action = modActionsModelEditor.actModelCompile
end
object N2: TMenuItem
Caption = '-'
end
object estLexicalModel1: TMenuItem
Action = modActionsModelEditor.actModelTest
end
end
object mnuKeyboard: TMenuItem
Caption = '&Keyboard'
object CompileKeyboard1: TMenuItem
Action = modActionsKeyboardEditor.actKeyboardCompile
@ -2989,7 +3001,7 @@ inherited frmKeymanDeveloper: TfrmKeymanDeveloper
Action = modActionsKeyboardEditor.actKeyboardFontHelper
end
end
object Debug2: TMenuItem
object mnuDebug: TMenuItem
Caption = '&Debug'
object SetBreakpoint1: TMenuItem
Action = modActionsKeyboardEditor.actDebugSetClearBreakpoint

View file

@ -97,6 +97,7 @@ uses
mrulist,
UfrmUnicodeDataStatus,
CharacterDragObject,
Keyman.Developer.UI.dmActionsModelEditor,
dmActionsMain, UnicodeData, UserMessages, webhelp,
dmActionsKeyboardEditor, Dialogs, UfrmTike, AppEvnts,
DropTarget,
@ -156,8 +157,8 @@ type
Edit1: TMenuItem;
View1: TMenuItem;
Project1: TMenuItem;
Keyboards1: TMenuItem;
Debug2: TMenuItem;
mnuKeyboard: TMenuItem;
mnuDebug: TMenuItem;
ools1: TMenuItem;
Help1: TMenuItem;
New1: TMenuItem;
@ -269,6 +270,10 @@ type
DebugTests1: TMenuItem;
CrashTest1: TMenuItem;
CloseProject1: TMenuItem;
mnuModel: TMenuItem;
CompileModel1: TMenuItem;
N2: TMenuItem;
estLexicalModel1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure mnuFileClick(Sender: TObject);
@ -341,6 +346,7 @@ type
procedure SaveDockLayout;
procedure CEFShutdownComplete(Sender: TObject);
procedure ActivateActiveChild;
function OpenModelEditor(FFileName: string): TfrmTikeEditor;
protected
procedure WndProc(var Message: TMessage); override;
@ -432,6 +438,7 @@ uses
Keyman.Developer.UI.Project.ProjectFileUI,
Keyman.Developer.UI.Project.ProjectUI,
Keyman.Developer.UI.UfrmWordlistEditor,
Keyman.Developer.UI.UfrmModelEditor,
TextFileFormat,
RedistFiles,
ErrorControlledRegistry,
@ -479,6 +486,7 @@ begin
modActionsTextEditor := TmodActionsTextEditor.Create(Self);
modActionsKeyboardEditor := TmodActionsKeyboardEditor.Create(Self);
modActionsMain := TmodActionsMain.Create(Self);
modActionsModelEditor := TmodActionsModelEditor.Create(Self);
FProjectMRU := TMRUList.Create('Project');
FProjectMRU.OnChange := ProjectMRUChange;
@ -1104,6 +1112,11 @@ begin
end;
function TfrmKeymanDeveloper.OpenFile(FFileName: string; FCloseNewFile: Boolean): TfrmTikeChild;
function FileHasModelTsExt(Filename: string): Boolean;
begin
// We cannot use ExtractFileExt because of the two-part extension
Result := Filename.ToLower.EndsWith('.model.ts');
end;
var
ext: string;
begin
@ -1137,6 +1150,7 @@ begin
else if ext = '.kvks' then Result := OpenKVKEditor(FFileName)
else if ext = '.bmp' then Result := OpenEditor(FFileName, TfrmBitmapEditor)
else if ext = '.tsv' then Result := OpenTSVEditor(FFileName)
else if FileHasModelTsExt(FFileName) then Result := OpenModelEditor(FFileName)
else Result := OpenEditor(FFileName, TfrmEditor);
end;
@ -1166,6 +1180,11 @@ begin
//else Result := OpenEditor(FFileName, TfrmEditor);
end;
function TfrmKeymanDeveloper.OpenModelEditor(FFileName: string): TfrmTikeEditor;
begin
Result := OpenEditor(FFileName, TfrmModelEditor);
end;
function TfrmKeymanDeveloper.OpenKPSEditor(FFileName: string): TfrmTikeEditor;
begin
Result := OpenEditor(FFileName, TfrmPackageEditor);
@ -1414,6 +1433,9 @@ begin
if PrevFocus.Visible then
PrevFocus.SetFocus;
end;
modActionsKeyboardEditor.actKeyboardCompile.Update;
modActionsModelEditor.actModelCompile.Update;
end;
procedure TfrmKeymanDeveloper.UDUI_Error(Sender: TUnicodeData;

View file

@ -677,7 +677,7 @@ begin
try
j.AddPair('x', TJSONNumber.Create(X));
j.AddPair('y', TJSONNumber.Create(Y));
j.AddPair('text', cdo.Text[cdo.InsertType]);
j.AddPair('text', cdo.Text[cmimCharacter]); // It never makes sense to drop anything other than char
BuilderCommand('charmapDragDrop', j);
finally
j.Free;

View file

@ -34,7 +34,8 @@ type
TmodelTsProjectFile = class(TOpenableProjectFile)
private
FDebug: Boolean;
FWarnAsError: Boolean; // I4706
FWarnAsError: Boolean;
FTestKeyboard: string; // I4706
function GetTargetFilename: string;
protected
@ -49,10 +50,10 @@ type
procedure SaveState(node: IXMLNode); override; // I4698
property Debug: Boolean read FDebug write FDebug;
property TestKeyboard: string read FTestKeyboard write FTestKeyboard;
property WarnAsError: Boolean read FWarnAsError write FWarnAsError; // I4706
// property OutputFilename: string read GetOutputFilename;
property TargetFilename: string read GetTargetFilename;
end;
@ -80,6 +81,7 @@ procedure TmodelTsProjectFile.SaveState(node: IXMLNode); // I4698
begin
inherited SaveState(node);
node.AddChild('Debug').NodeValue := FDebug;
node.AddChild('TestKeyboard').NodeValue := FTestKeyboard;
end;
procedure TmodelTsProjectFile.Load(node: IXMLNode; LoadState: Boolean); // I4698
@ -95,8 +97,12 @@ begin
inherited LoadState(node);
try
if node.ChildNodes.IndexOf('Debug') >= 0 then FDebug := node.ChildValues['Debug'];
if node.ChildNodes.IndexOf('TestKeyboard') >= 0
then FTestKeyboard := node.ChildValues['TestKeyboard']
else FTestKeyboard := '';
except
FDebug := False;
FTestKeyboard := '';
end;
end;

View file

@ -37,6 +37,8 @@ type
function GetDebug: Boolean;
procedure SetDebug(const Value: Boolean);
function CompileModel(FSilent: Boolean): Boolean;
function TestKeymanWeb(FSilent: Boolean): Boolean;
function TestModelState(FCompiledName: string; FSilent: Boolean): Boolean;
public
function DoAction(action: TProjectFileAction; FSilent: Boolean): Boolean; override;
property Debug: Boolean read GetDebug write SetDebug;
@ -51,10 +53,13 @@ uses
Vcl.Dialogs,
Vcl.Graphics,
Vcl.Controls,
dmActionsMain,
KeyboardFonts,
UmodWebHttpServer,
UfrmMain,
UfrmMDIEditor,
KeyboardFonts,
Keyman.Developer.UI.UfrmModelEditor,
KeymanDeveloperUtils,
KeymanDeveloperOptions,
System.Classes,
@ -64,8 +69,9 @@ uses
function TmodelTsProjectFileUI.DoAction(action: TProjectFileAction; FSilent: Boolean): Boolean;
begin
case action of
pfaCompile: Result := CompileModel(FSilent);
pfaClean: Result := ProjectFile.Clean;
pfaCompile: Result := CompileModel(FSilent);
pfaClean: Result := ProjectFile.Clean;
pfaTestKeymanWeb: Result := TestKeymanWeb(FSilent);
else
Result := False;
end;
@ -108,6 +114,73 @@ begin
ProjectFile.Debug := Value;
end;
function TmodelTsProjectFileUI.TestKeymanWeb(FSilent: Boolean): Boolean;
var
FCompiledName: string;
editor: TfrmTikeEditor;
wizard: TfrmModelEditor;
FontNames: TKeyboardFontArray;
i: TKeyboardFont;
begin
editor := frmKeymanDeveloper.FindEditorByFileName(ProjectFile.FileName); // I4021
if not Assigned(editor) or not (editor is TfrmModelEditor) then
Exit(False);
wizard := editor as TfrmModelEditor;
FCompiledName := ProjectFile.TargetFilename;
if not TestModelState(FCompiledName, FSilent) then
Exit(False);
for i := Low(TKeyboardFont) to High(TKeyboardFont) do
FontNames[i] := '';
if FileExists(ProjectFile.TestKeyboard) then
modWebHttpServer.Debugger.RegisterKeyboard(ProjectFile.TestKeyboard, '1.0', FontNames);
modWebHttpServer.Debugger.RegisterModel(FCompiledName);
wizard.NotifyStartedWebDebug; // I4021
Result := True;
end;
function TmodelTsProjectFileUI.TestModelState(FCompiledName: string;
FSilent: Boolean): Boolean;
var
ftts, ftjs: TDateTime;
begin
Result := False;
if not FileExists(FCompiledName) then
if FSilent then
begin
if not CompileModel(FSilent) then Exit;
end
else
case MessageDlg('You need to compile the model before you can continue. Compile now?',
mtConfirmation, mbOkCancel, 0) of
mrOk: if not CompileModel(FSilent) then Exit;
mrCancel: Exit;
end;
FileAge(ProjectFile.FileName, ftts);
FileAge(FCompiledName, ftjs);
if ProjectFile.Modified or (ftts > ftjs) then
if FSilent then
begin
if not CompileModel(FSilent) then Exit;
end
else
case MessageDlg('The source file has changed. Recompile before continuing?',
mtConfirmation, mbYesNoCancel, 0) of
mrYes: if not CompileModel(FSilent) then Exit;
mrNo: ;
mrCancel: Exit;
end;
Result := True;
end;
initialization
RegisterProjectFileUIType(TmodelTsProjectFileAction, TmodelTsProjectFileUI);
end.

View file

@ -59,6 +59,7 @@
.touch-device #install-link,
.touch-device #install-link-packages,
.touch-device #model-link,
.touch-device-ios #install-link-ios,
.touch-device-android #install-link-android {
display: inline-block;
@ -132,10 +133,6 @@
<script src="resource/keymanweb.js"></script>
<script src="resource/kmwuibutton.js"></script>
<!-- The following dynamic script will register each of the additional keyboards -->
<script src="/inc/keyboards.js" type="text/javascript"></script>
<!-- This script loads the dynamic keyboard fonts -->
<link href="/inc/keyboards.css" type="text/css" rel="stylesheet" />
@ -156,7 +153,15 @@
<body class='osk-always-visible'>
<div class='header'>
<div><h2>Keyboard Test</h2></div>
<div class='float-right'><a href='/packages.html' class='install-link' id='install-link-packages'>Install packages</a></div>
<div class='float-right'>
<span id='model-link' class='install-link' onclick=''>Models</span>
<div id='model-list'>
<div id='model-list-inner'>
<span id='model-list-empty'>No models are currently loaded.</span>
</div>
</div>
<a href='/packages.html' class='install-link' id='install-link-packages'>Install packages</a>
</div>
<div class='clear'></div>
</div>
@ -322,7 +327,62 @@
//document.getElementById('ta1').focus();
keyman.moveToElement('ta1');
}, 10);
document.getElementById('model-link').addEventListener('click', modelLinkClick);
}
/* Lexical models */
var firstModel = true;
/**
* Register a model for debugging. Called by keyboards.js. The
* first model registered will be activated automatically.
*/
function registerModel(model, src) {
var list = document.getElementById('model-list-inner');
var a = document.createElement('a');
a.href = '#';
a.innerText = model;
a.addEventListener('click', function(ev) {
ev.returnValue = false;
var lastModel = keyman.modelManager.activeModel;
if(lastModel)
keyman.modelManager.deregister(lastModel.id);
keyman.modelManager.register({
id: model,
languages: ['en'],
path: 'http://'+location.host+'/model/'+src
});
});
list.appendChild(a);
if(firstModel) {
keyman.modelManager.register({
id: model,
languages: ['en'],
path: 'http://'+location.host+'/model/'+src
});
document.getElementById('model-list-empty').style.display = 'none';
firstModel = false;
}
}
/**
* Toggle visibility of the model menu
*/
function modelLinkClick(e) {
var elem = document.getElementById('model-list');
elem.className = elem.className == '' ? 'model-list-visible' : '';
e.returnValue = false;
return false;
}
</script>
<!-- The following dynamic script will register each of the additional keyboards -->
<script src="/inc/keyboards.js" type="text/javascript"></script>
</body>
</html>

View file

@ -1,55 +1,81 @@
html, body {
margin: 0;
padding: 0;
}
html, body {
margin: 0;
padding: 0;
}
h2 {
font-family: sans-serif
}
h2 {
font-family: sans-serif
}
.install-link {
background: none repeat scroll 0 0 #CCCCCC;
border: 1px solid #444444;
border-radius: 4px;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25);
display: inline-block;
color: #444444;
font-family: Sans-serif;
font-size: 10pt;
padding: 6px;
margin: 12px 2px 0 2px;
text-decoration: none;
}
.install-link {
background: none repeat scroll 0 0 #CCCCCC;
border: 1px solid #444444;
border-radius: 4px;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25);
display: inline-block;
color: #444444;
font-family: Sans-serif;
font-size: 10pt;
padding: 6px;
margin: 12px 2px 0 2px;
text-decoration: none;
}
.header {
padding: 4px 8px;
background: #424248;
color: #f0f0ff;
}
.header {
padding: 4px 8px;
background: #424248;
color: #f0f0ff;
}
.header div {
display: inline-block;
}
.header div {
display: inline-block;
}
.header div h2 {
margin: 4px;
}
.header div h2 {
margin: 4px;
}
.header div.float-right {
display: block;
position: absolute;
right: 0;
top: 0;
}
.header div.float-right {
display: block;
position: absolute;
right: 0;
top: 0;
}
.float-right a.install-link {
margin: 8px 8px 0 0 ;
}
.float-right a.install-link {
margin: 8px 8px 0 0 ;
}
.clear {
clear: both;
}
.clear {
clear: both;
}
#content {
margin: 8px 16px;
}
#content {
margin: 8px 16px;
}
/* Lexical model menu */
.model-list-visible#model-list {
display: block;
}
#model-list {
display: none;
position: absolute;
z-index: 3;
margin-top: 4px;
padding: 5px 5px 5px 5px;
background: #424248;
border-left: solid 1px #442244;
border-right: solid 1px #442244;
border-bottom: solid 1px #442244;
border-radius: 0 0 4px 4px;
box-shadow: 4px 4px 4px rgba(64,64,64,0.5);
}
#model-list a {
display: block;
color: white;
padding: 6px;
}

View file

@ -4,6 +4,8 @@
* Start version 13.0
* Feature: Add unsupported kmdecomp decompiler utility (#2419)
* Feature: Show QRCode for web debugger URLs in Keyboard and Package editors (#2433)
* Feature: Hotkeys defined in .kmn no longer need to be quoted (#2432)
* Bug Fix: Keyboard ID was not clean by default with Import Windows Keyboard (#2431)
## 2019-11-18 12.0.55 stable
* Bug Fix: Some keyboards were incorrectly marked as mobile-capable (#2334)

View file

@ -2792,6 +2792,8 @@ DWORD ProcessEthnologueStore(PWSTR p) // I2646
return res;
}
#define K_HOTKEYSHIFTFLAGS (K_SHIFTFLAG | K_CTRLFLAG | K_ALTFLAG | ISVIRTUALKEY)
DWORD ProcessHotKey(PWSTR p, DWORD *hk)
{
PWSTR q, r;
@ -2800,6 +2802,25 @@ DWORD ProcessHotKey(PWSTR p, DWORD *hk)
*hk = 0;
if(*p == UC_SENTINEL && *(p+1) == CODE_EXTENDED) {
WORD Key = *(p + 3);
WORD ShiftFlags = *(p + 2);
// Convert virtual key to hotkey (different bitflags)
if (ShiftFlags & ~K_HOTKEYSHIFTFLAGS) {
AddWarning(CWARN_HotkeyHasInvalidModifier);
}
if (ShiftFlags & K_SHIFTFLAG) *hk |= HK_SHIFT;
if (ShiftFlags & K_CTRLFLAG) *hk |= HK_CTRL;
if (ShiftFlags & K_ALTFLAG) *hk |= HK_ALT;
*hk |= Key;
return CERR_None;
}
q = wcschr(p, '[');
if(q)
{

View file

@ -222,5 +222,6 @@ END
STRINGTABLE
BEGIN
CWARN_LanguageHeadersDeprecatedInKeyman10 "This language header has been deprecated in Keyman 10. Instead, add language metadata in the package file"
CWARN_HotkeyHasInvalidModifier "Hotkey has modifiers that are not supported. Use only SHIFT, CTRL and ALT"
CINFO_NonUnicodeFile "Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8"
END

View file

@ -37,9 +37,8 @@ int main(int argc, char *argv[])
if(argc < 3)
{
puts("Usage: kcframe infile.kmn outfile.kmx");
return 0;
return 1;
}
CompileKeyboardFile(argv[1], argv[2], TRUE, FALSE, TRUE, msgproc); // I4865 // I4866
return 1;
return CompileKeyboardFile(argv[1], argv[2], TRUE, FALSE, TRUE, msgproc) ? 0 : 1; // I4865 // I4866
}

View file

@ -73,6 +73,7 @@ uses
Keyman.Developer.System.ImportKeyboardDLL,
Keyman.Developer.System.TouchLayoutToVisualKeyboardConverter,
Keyman.System.Util.RenderLanguageIcon,
Keyman.System.KeyboardUtils,
KeymanVersion,
KeyboardParser,
kmxfileconsts,
@ -107,7 +108,7 @@ begin
r.ValueExists(SRegValue_KeyboardLayoutText) then
Exit(False);
KeyboardID := ChangeFileExt(r.ReadString(SRegValue_KeyboardLayoutFile), '');
KeyboardID := TKeyboardUtils.CleanKeyboardID(ChangeFileExt(r.ReadString(SRegValue_KeyboardLayoutFile), ''));
Name := r.ReadString(SRegValue_KeyboardLayoutText);
finally
r.Free;

View file

@ -189,6 +189,8 @@
#define CWARN_TooManyErrorsOrWarnings 0x000020A7
#define CWARN_HotkeyHasInvalidModifier 0x000020A8
#define CERR_BufferOverflow 0x000080C0
#define CERR_Break 0x000080C1

View file

@ -0,0 +1,130 @@
unit Keyman.System.Test.LexicalModelParserTest;
interface
uses
System.Classes,
System.SysUtils,
DUnitX.TestFramework;
type
[TestFixture]
TLexicalModelParserTest = class(TObject)
private
m: TStringList;
AssetRootPath: string;
mcustom: TStringList;
mnocomment: TStrings;
public
[Setup]
procedure Setup;
[TearDown]
procedure TearDown;
[Test]
procedure TestRead;
[Test]
procedure TestWrite;
[Test]
procedure TestWriteDeleteComment;
[Test]
procedure TestWriteNewComment;
end;
implementation
uses
Keyman.Developer.System.LexicalModelParser,
Keyman.Developer.System.LexicalModelParserTypes;
procedure TLexicalModelParserTest.Setup;
begin
// Running from platform/configuration/ folder has
// assets two levels up.
if FileExists('..\..\assets\nrc.en.mtnt.model.ts')
then AssetRootPath := '..\..\assets\'
else AssetRootPath := '';
m := TStringList.Create;
m.LoadFromFile(AssetRootPath + 'nrc.en.mtnt.model.ts');
mcustom := TStringList.Create;
mcustom.LoadFromFile(AssetRootPath + 'custom.model.ts');
mnocomment := TStringList.Create;
mnocomment.LoadFromFile(AssetRootPath + 'nocomment.model.ts');
end;
procedure TLexicalModelParserTest.TearDown;
begin
m.Free;
mcustom.Free;
mnocomment.Free;
end;
procedure TLexicalModelParserTest.TestRead;
var
lm: TLexicalModelParser;
begin
lm := TLexicalModelParser.Create(m.Text);
try
Assert.IsTrue(lm.Format = lmfTrie10, 'Expected lmfTrie10');
Assert.IsTrue(lm.WordBreaker = lmwbDefault, 'Expected lmwbDefault');
Assert.AreEqual(1, lm.Wordlists.Count, 'Expected 1 wordlist');
Assert.AreEqual('mtnt.tsv', lm.Wordlists[0], 'Wordlist name');
Assert.AreEqual(#13#10' Sample model for testing parser'#13#10, lm.Comment);
finally
lm.Free;
end;
end;
procedure TLexicalModelParserTest.TestWrite;
var
lm: TLexicalModelParser;
begin
lm := TLexicalModelParser.Create(m.Text);
try
lm.Comment := 'Testing';
lm.Format := lmfCustom10;
lm.WordBreaker := lmwbAscii;
lm.Wordlists.Clear;
lm.Wordlists.Add('foo.tsv');
lm.Wordlists.Add('bar.tsv');
Assert.AreEqual(mcustom.Text.Trim, lm.Text.Trim); // Ignoring whitespace before/after
finally
lm.Free;
end;
end;
procedure TLexicalModelParserTest.TestWriteNewComment;
var
lm: TLexicalModelParser;
begin
lm := TLexicalModelParser.Create(mnocomment.Text);
try
lm.Comment := #13#10' Sample model for testing parser'#13#10;
Assert.AreEqual(m.Text.Trim, lm.Text.Trim); // Ignoring whitespace before/after
finally
lm.Free;
end;
end;
procedure TLexicalModelParserTest.TestWriteDeleteComment;
var
lm: TLexicalModelParser;
begin
lm := TLexicalModelParser.Create(m.Text);
try
lm.Comment := '';
Assert.AreEqual(mnocomment.Text.Trim, lm.Text.Trim); // Ignoring whitespace before/after
finally
lm.Free;
end;
end;
initialization
TDUnitX.RegisterTestFixture(TLexicalModelParserTest);
end.

View file

@ -0,0 +1,61 @@
program ModelTsParserTest;
{$IFNDEF TESTINSIGHT}
{$APPTYPE CONSOLE}
{$ENDIF}{$STRONGLINKTYPES ON}
uses
System.SysUtils,
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX,
{$ENDIF }
DUnitX.Loggers.Console,
DUnitX.Loggers.Xml.NUnit,
DUnitX.TestFramework,
Keyman.System.Test.LexicalModelParserTest in 'Keyman.System.Test.LexicalModelParserTest.pas',
Keyman.Developer.System.LexicalModelParser in '..\..\..\developer\TIKE\main\Keyman.Developer.System.LexicalModelParser.pas',
Keyman.Developer.System.LexicalModelParserTypes in '..\..\..\developer\TIKE\main\Keyman.Developer.System.LexicalModelParserTypes.pas';
var
runner : ITestRunner;
results : IRunResults;
logger : ITestLogger;
nunitLogger : ITestLogger;
begin
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX.RunRegisteredTests;
exit;
{$ENDIF}
try
//Check command line options, will exit if invalid
TDUnitX.CheckCommandLine;
//Create the test runner
runner := TDUnitX.CreateRunner;
//Tell the runner to use RTTI to find Fixtures
runner.UseRTTI := True;
//tell the runner how we will log things
//Log to the console window
logger := TDUnitXConsoleLogger.Create(true);
runner.AddLogger(logger);
//Generate an NUnit compatible XML File
nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile);
runner.AddLogger(nunitLogger);
runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests;
//Run tests
results := runner.Execute;
if not results.AllPassed then
System.ExitCode := EXIT_ERRORS;
{$IFNDEF CI}
//We don't want this happening when running under CI.
if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then
begin
System.Write('Done.. press <Enter> key to quit.');
System.Readln;
end;
{$ENDIF}
except
on E: Exception do
System.Writeln(E.ClassName, ': ', E.Message);
end;
end.

View file

@ -0,0 +1,765 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{0158CB55-B9BC-4F32-B860-FD6073AE2EB7}</ProjectGuid>
<ProjectVersion>18.7</ProjectVersion>
<FrameworkType>None</FrameworkType>
<MainSource>ModelTsParserTest.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Console</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_UnitSearchPath>$(DUnitX);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<SanitizedProjectName>ModelTsParserTest</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;mbColorLibD10;dsnapcon;FireDACADSDriver;scFontCombo;DCPdelphi2009;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;FireDAC;vcltouch;JvCore;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;inetdb;CEF4Delphi;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;EmbeddedWebBrowser_XE;VCLRESTComponents;soapserver;dbxcds;VclSmp;JvDocking;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;keyman_components;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="Keyman.System.Test.LexicalModelParserTest.pas"/>
<DCCReference Include="..\..\..\developer\TIKE\main\Keyman.Developer.System.LexicalModelParser.pas"/>
<DCCReference Include="..\..\..\developer\TIKE\main\Keyman.Developer.System.LexicalModelParserTypes.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Console</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">ModelTsParserTest.dpr</Source>
</Source>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="Win32\Debug\ModelTsParserTest.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>ModelTsParserTest.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidFileProvider">
<Platform Name="Android">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules"/>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View file

@ -0,0 +1,8 @@
/*Testing*/
const source: LexicalModelSource = {
format: 'custom-1.0',
wordBreaker: 'ascii',
sources: ['foo.tsv', 'bar.tsv']
};
export default source;

View file

@ -0,0 +1,7 @@
const source: LexicalModelSource = {
format: 'trie-1.0',
wordBreaker: 'default',
sources: ['mtnt.tsv']
};
export default source;

View file

@ -0,0 +1,10 @@
/*
Sample model for testing parser
*/
const source: LexicalModelSource = {
format: 'trie-1.0',
wordBreaker: 'default',
sources: ['mtnt.tsv']
};
export default source;