diff --git a/lazproj/coedit.lpi b/lazproj/coedit.lpi
index ec0441ed..cc62d073 100644
--- a/lazproj/coedit.lpi
+++ b/lazproj/coedit.lpi
@@ -128,7 +128,7 @@
-
+
@@ -228,6 +228,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/lazproj/coedit.lpr b/lazproj/coedit.lpr
index 4098f904..85d751c0 100644
--- a/lazproj/coedit.lpr
+++ b/lazproj/coedit.lpr
@@ -9,7 +9,7 @@ uses
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, ce_widget,
ce_dmdwrap, ce_common, ce_synmemo, ce_main, ce_messages, ce_editor,
ce_projinspect, ce_projconf, jsonparser, ce_project,
- ce_widgettypes, ce_staticexplorer, ce_search;
+ ce_widgettypes, ce_staticexplorer, ce_search, ce_dlang, ce_dlangutils;
{$R *.res}
diff --git a/src/ce_d2syn.pas b/src/ce_d2syn.pas
index f1cf0885..ad75fe51 100644
--- a/src/ce_d2syn.pas
+++ b/src/ce_d2syn.pas
@@ -6,7 +6,8 @@ interface
uses
Classes, SysUtils, Graphics,
- SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes;
+ SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes,
+ ce_dlangutils;
const
@@ -152,95 +153,6 @@ type
implementation
-function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := c in [#0..#32];
-end;
-
-function isSpace(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := c in [#9,' '];
-end;
-
-function isAlpha(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := (c in ['a'..'z']) or (c in ['A'..'Z']);
-end;
-
-function isNumber(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := (c in ['0'..'9']);
-end;
-
-function isDigit(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := (c in ['0'..'1']);
-end;
-
-function isAlNum(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := isAlpha(c) or isNumber(c);
-end;
-
-function isHex(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := isNumber(c) or (c in ['A'..'F']) or (c in ['a'..'f']);
-end;
-
-function isSymbol(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := c in [';', '{', '}', '(', ')', '[', ']', ',', '.', ':' , '"', #39, '?'];
-end;
-
-function isOperator(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := c in ['/', '*', '-', '+', '%', '>', '<', '=', '!',
- '&', '|', '^', '~', '$'];
-end;
-
-function isDoubleOperator(const s: string): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
-begin
- result := false;
- case s[1] of
- '.': result := (s[2] = '.');
-
- '>': result := s[2] in ['>', '='];
- '<': result := s[2] in ['<', '=', '>'];
- '=': result := s[2] in ['=', '>'];
- '!': result := s[2] in ['=', '>', '<'];
-
- '+': result := s[2] in ['+', '='];
- '-': result := s[2] in ['-', '='];
- '/': result := s[2] in ['='];
- '*': result := s[2] in ['='];
- '%': result := s[2] in ['='];
- '~': result := s[2] in ['='];
-
- '&': result := s[2] in ['&', '='];
- '|': result := s[2] in ['|', '='];
- '^': result := s[2] in ['^', '='];
- end;
-end;
-
-function isTripleOperator(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
-begin
- result := false;
- case s[1] of
- '.': result := (s[2] = '.') and (s[3] = '.');
- '^': result := (s[2] = '^') and (s[3] = '=');
- '>': result := (s[2] = '>') and (s[3] in ['>', '=']);
- '<': result := ((s[2] = '<') and (s[3] in ['<', '=']))
- or (s[2] = '>') and (s[3] = '=');
- '!': result := ((s[2] = '<') and (s[3] in ['>', '=']))
- or ((s[2] = '>')and (s[3] = '='));
- end;
-end;
-
-function isQuadOperator(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
-begin
- result := (s = '>>>=') or (s = '!<>=');
-end;
-
{$IFDEF USE_DICT_LINKEDCHARMAP}
constructor TD2Dictionary.create;
var
@@ -526,6 +438,7 @@ TODO:
- string literals: escape bug: std.path/std.regex: "\\"
- comments: correct nested comments handling.
}
+{$BOOLEVAL ON}
procedure TSynD2Syn.next;
label
_postString1;
@@ -670,7 +583,7 @@ begin
fRange := rkNone;
readNext;
// check postfix
- if readCurr in ['c','w','d'] then
+ if isStringPostfix(readCurr) then
readNext;
exit;
end;
@@ -679,7 +592,7 @@ begin
begin
if fRange = rkNone then
begin
- // check hex/WYSIWYG prefix
+ // check WYSIWYG/hex prefix
if readCurr in ['r','x'] then
begin
if not (readNext = '"') then
@@ -695,7 +608,7 @@ begin
begin
readNext;
// check postfix
- if readCurr in ['c','w','d'] then
+ if isStringPostfix(readCurr) then
readNext;
end;
fTokKind := tkStrng;
@@ -720,7 +633,7 @@ begin
fRange := rkNone;
readNext;
// check postfix
- if readCurr in ['c','w','d'] then
+ if isStringPostfix(readCurr) then
readNext;
exit;
end;
@@ -736,7 +649,7 @@ begin
begin
readNext;
// check postfix
- if readCurr in ['c','w','d'] then
+ if isStringPostfix(readCurr) then
readNext;
end;
fTokKind := tkStrng;
@@ -778,30 +691,30 @@ begin
end;
// symbols 2: operators
- if isOperator(readCurr) then
+ if isOperator1(readCurr) then
begin
fTokKind := tkSymbl;
- while isOperator(readNext) do (*!*);
+ while isOperator1(readNext) do (*!*);
case fTokStop - fTokStart of
1:begin
- if not isOperator(readCurr) then exit
+ if not isOperator1(readCurr) then exit
else Dec(fTokStop);
end;
2:begin
- if (not isOperator(readCurr)) and
- isDoubleOperator(fLineBuf[fTokStart..fTokStop-1])
+ if (not isOperator1(readCurr)) and
+ isOperator2(fLineBuf[fTokStart..fTokStop-1])
then exit
else Dec(fTokStop, 2);
end;
3:begin
- if (not isOperator(readCurr)) and
- isTripleOperator(fLineBuf[fTokStart..fTokStop-1])
+ if (not isOperator1(readCurr)) and
+ isOperator3(fLineBuf[fTokStart..fTokStop-1])
then exit
else Dec(fTokStop, 3);
end;
4:begin
- if (not isOperator(readCurr)) and
- isQuadOperator(fLineBuf[fTokStart..fTokStop-1])
+ if (not isOperator1(readCurr)) and
+ isOperator4(fLineBuf[fTokStart..fTokStop-1])
then exit
else Dec(fTokStop, 4);
end;
@@ -817,7 +730,7 @@ begin
begin
if isWhite(readNext) then break;
if isSymbol(readCurr) then break;
- if isOperator(readCurr) then break;
+ if isOperator1(readCurr) then break;
end;
if fKeyWords.find(fLineBuf[FTokStart..fTokStop-1]) then
fTokKind := tkKeywd
@@ -832,6 +745,7 @@ begin
// Should not happend
assert(false);
end;
+{$BOOLEVAL OFF}
function TSynD2Syn.GetEol: Boolean;
begin
diff --git a/src/ce_dlang.pas b/src/ce_dlang.pas
new file mode 100644
index 00000000..3d403e08
--- /dev/null
+++ b/src/ce_dlang.pas
@@ -0,0 +1,831 @@
+unit ce_dlang;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, ce_dlangutils;
+
+const
+
+ D2Kw: array[0..109] of string =
+ ( 'abstract', 'alias', 'align', 'asm', 'assert', 'auto',
+ 'body', 'bool', 'break', 'byte',
+ 'case', 'cast', 'catch', 'cdouble', 'cent', 'cfloat', 'char', 'class',
+ 'const', 'continue', 'creal',
+ 'dchar', 'debug', 'default', 'delegate', 'delete', 'deprecated', 'do', 'double',
+ 'else', 'enum', 'export', 'extern',
+ 'false', 'final', 'finally', 'float', 'for', 'foreach',
+ 'foreach_reverse', 'function',
+ 'goto',
+ 'idouble', 'if', 'ifloat', 'immutable', 'import', 'in', 'inout', 'int',
+ 'interface', 'invariant', 'ireal', 'is',
+ 'lazy', 'long',
+ 'macro', 'mixin', 'module',
+ 'new', 'nothrow', 'null',
+ 'out', 'override',
+ 'package', 'pragma', 'private', 'protected', 'ptrdiff_t', 'public', 'pure',
+ 'real', 'ref', 'return',
+ 'size_t', 'scope', 'shared', 'short', 'static', 'string', 'struct',
+ 'super', 'switch', 'synchronized',
+ 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typeof',
+ 'ubyte', 'ucent', 'uint', 'ulong', 'union', 'unittest', 'ushort',
+ 'version', 'void', 'volatile',
+ 'wchar', 'while', 'with',
+ '__FILE__', '__MODULE__', '__LINE__', '__FUNCTION__', '__PRETTY_FUNCTION__'
+ );
+
+type
+
+ (**
+ * sector for an array of Keyword with a common hash.
+ *)
+ TD2DictionaryEntry = record
+ filled: Boolean;
+ values: array of string;
+ end;
+
+ (**
+ * Dictionary for the D2 keywords.
+ *)
+ TD2Dictionary = object
+ private
+ fLongest, fShortest: NativeInt;
+ fEntries: array[Byte] of TD2DictionaryEntry;
+ function toHash(const aValue: string): Byte; {$IFNDEF DEBUG}inline;{$ENDIF}
+ procedure addEntry(const aValue: string);
+ public
+ constructor create;
+ destructor destroy; // do not remove even if empty (compat with char-map version)
+ function find(const aValue: string): boolean;
+ end;
+
+ (**
+ * Represents the pointer in a source file.
+ * Automatically updates the line and the column.
+ *)
+ TReaderHead = object
+ private
+ fLineIndex: Integer;
+ fColumnIndex: Integer;
+ fAbsoluteIndex: Integer;
+ fReaderHead: PChar;
+ function getColAndLine: TPoint;
+ public
+ constructor create(const aText: PChar; const aColAndLine: TPoint);
+ procedure setReader(const aText: PChar; const aColAndLine: TPoint);
+ //
+ function next: PChar;
+ function previous: PChar;
+ //
+ property AbsoluteIndex: Integer read fAbsoluteIndex;
+ property LineIndex: Integer read fLineIndex;
+ property ColumnIndex: Integer read fColumnIndex;
+ property LineAnColumn: TPoint read getColAndLine;
+ //
+ property head: PChar read fReaderHead;
+ end;
+
+ TLexTokenKind = (ltkIllegal, ltkChar, ltkComment, ltkIdentifier, ltkKeyword,
+ ltkNumber, ltkOperator, ltkString, ltkSymbol);
+
+const
+ LexTokenKindString : array[TLexTokenKind] of string =
+ ( 'Illegal', 'Character', 'Comment', 'Identifier', 'Keyword',
+ 'Number', 'Operator', 'String', 'Symbol');
+
+type
+
+ (*****************************************************************************
+ * Lexer token
+ *)
+ PLexToken = ^TLexToken;
+ TLexToken = record
+ position: TPoint;
+ kind: TLexTokenKind;
+ data: string;
+ end;
+
+ (*****************************************************************************
+ * List of lexer tokens
+ *)
+ TLexTokenList = class(TList)
+ private
+ function getToken(index: integer): TLexToken;
+ public
+ procedure clear; override;
+ procedure addToken(aValue: PLexToken);
+ property token[index: integer]: TLexToken read getToken;
+ end;
+
+ TLexTokenEnumerator = class
+ fList: TLexTokenList;
+ fIndex: Integer;
+ function GetCurrent: TLexToken;
+ function MoveNext: Boolean;
+ property Current: TLexToken read GetCurrent;
+ end;
+
+ (*****************************************************************************
+ * Error record
+ *)
+ PLexError = ^TLexError;
+ TLexError = record
+ position: TPoint;
+ msg: string;
+ end;
+
+ (*****************************************************************************
+ * Error list
+ *)
+ TLexErrorList = class(TList)
+ private
+ function getError(index: integer): TLexError;
+ public
+ procedure clear; override;
+ procedure addError(aValue: PLexError);
+ property error[index: integer]: TLexError read getError;
+ end;
+
+ TLexErrorEnumerator = class
+ fList: TLexErrorList;
+ fIndex: Integer;
+ function GetCurrent: TLexError;
+ function MoveNext: Boolean;
+ property Current: TLexError read GetCurrent;
+ end;
+
+ operator enumerator(aTokenList: TLexTokenList): TLexTokenEnumerator;
+ operator enumerator(anErrorList: TLexErrorList): TLexErrorEnumerator;
+
+ (*****************************************************************************
+ * Lexes aText and fills aList with the TLexToken found.
+ *)
+ procedure lex(const aText: string; const aList: TLexTokenList);
+ (*****************************************************************************
+ * Detects various syntaxic error in a TLexTokenList
+ *)
+ procedure checkSyntaxicErrors(const aTokenList: TLexTokenList; const anErrorList: TLexErrorList);
+
+
+
+ (*****************************************************************************
+ * Compares two TPoints.
+ *)
+ operator = (lhs: TPoint; rhs: TPoint): boolean;
+
+implementation
+
+var
+ D2Dictionary: TD2Dictionary;
+
+{$REGION TReaderHead------------------------------------------------------------}
+operator = (lhs: TPoint; rhs: TPoint): boolean;
+begin
+ exit( (lhs.y = rhs.y) and (lhs.x = rhs.x) );
+end;
+
+constructor TReaderHead.create(const aText: PChar; const aColAndLine: TPoint);
+begin
+ setReader(aText,aColAndLine);
+end;
+
+procedure TReaderHead.setReader(const aText: PChar; const aColAndLine: TPoint);
+begin
+ fLineIndex := aColAndLine.y;
+ fColumnIndex := aColAndLine.x;
+ fReaderHead := aText;
+ while (LineAnColumn <> aColAndLine) do next;
+ //
+ // editor not 0 based ln index
+ if fLineIndex = 0 then fLineIndex := 1;
+end;
+
+function TReaderHead.getColAndLine: TPoint;
+begin
+ exit( Point(fColumnIndex, fLineIndex) );
+end;
+
+function TReaderHead.next: PChar;
+begin
+ Inc(fReaderHead);
+ Inc(fAbsoluteIndex);
+ Inc(fColumnIndex);
+ if (fReaderHead^ = #10) then
+ begin
+ Inc(fLineIndex);
+ fColumnIndex := 0;
+ end;
+ exit(fReaderHead);
+end;
+
+function TReaderHead.previous: PChar;
+begin
+ // note: it breaks the column but not the line count
+ Dec(fReaderHead);
+ Dec(fColumnIndex);
+ Dec(fAbsoluteIndex);
+ exit(fReaderHead);
+end;
+{$ENDREGION}
+
+{$REGION TD2Dictionary----------------------------------------------------------}
+constructor TD2Dictionary.create;
+var
+ value: string;
+begin
+ for value in D2Kw do
+ addEntry(value);
+end;
+
+destructor TD2Dictionary.destroy;
+begin
+end;
+
+{$IFDEF DEBUG}{$R-}{$ENDIF}
+function TD2Dictionary.toHash(const aValue: string): Byte;
+var
+ i: Integer;
+begin
+ result := 0;
+ for i := 1 to length(aValue) do result +=
+ (Byte(aValue[i]) shl (4 and (1-i))) xor 25;
+end;
+{$IFDEF DEBUG}{$R+}{$ENDIF}
+
+procedure TD2Dictionary.addEntry(const aValue: string);
+var
+ hash: Byte;
+begin
+ if find(aValue) then exit;
+ hash := toHash(aValue);
+ fEntries[hash].filled := true;
+ setLength(fEntries[hash].values, length(fEntries[hash].values) + 1);
+ fEntries[hash].values[high(fEntries[hash].values)] := aValue;
+ if fLongest <= length(aValue) then
+ fLongest := length(aValue);
+ if fShortest >= length(aValue) then
+ fShortest := length(aValue);
+end;
+
+function TD2Dictionary.find(const aValue: string): boolean;
+var
+ hash: Byte;
+ i: NativeInt;
+begin
+ result := false;
+ if length(aValue) > fLongest then exit;
+ if length(aValue) < fShortest then exit;
+ hash := toHash(aValue);
+ if (not fEntries[hash].filled) then exit(false);
+ for i:= 0 to high(fEntries[hash].values) do
+ if fEntries[hash].values[i] = aValue then exit(true);
+end;
+{$ENDREGION}
+
+{$REGION Lexing-----------------------------------------------------------------}
+function TLexTokenList.getToken(index: integer): TLexToken;
+begin
+ result := PLexToken(Items[index])^;
+end;
+
+procedure TLexTokenList.clear;
+begin
+ while Count > 0 do
+ begin
+ Dispose( PLexToken(Items[Count-1]) );
+ Delete(Count-1);
+ end;
+end;
+
+procedure TLexTokenList.addToken(aValue: PLexToken);
+begin
+ add(Pointer(aValue));
+end;
+
+function TLexTokenEnumerator.GetCurrent: TLexToken;
+begin
+ exit(fList.token[fIndex]);
+end;
+
+function TLexTokenEnumerator.MoveNext: Boolean;
+begin
+ Inc(fIndex);
+ exit(fIndex < fList.Count);
+end;
+
+operator enumerator(aTokenList: TLexTokenList): TLexTokenEnumerator;
+begin
+ result := TLexTokenEnumerator.Create;
+ result.fList := aTokenList;
+ result.fIndex := -1;
+end;
+
+{$BOOLEVAL ON}
+procedure lex(const aText: string; const aList: TLexTokenList);
+var
+ reader: TReaderHead;
+ identifier: string;
+
+ function isOutOfBound: boolean;
+ begin
+ exit(reader.AbsoluteIndex > length(aText))
+ end;
+
+ procedure addToken(aTk: TLexTokenKind);
+ var
+ ptk: PLexToken;
+ begin
+ ptk := new(PLexToken);
+ ptk^.kind := aTk;
+ ptk^.position := reader.LineAnColumn;
+ ptk^.data := identifier;
+ aList.Add(ptk);
+ end;
+
+begin
+
+ reader.create(@aText[1], Point(0,0));
+ while (true) do
+ begin
+
+ if isOutOfBound then
+ exit;
+
+ identifier := '';
+
+ // skip blanks
+ while isWhite(reader.head^) do
+ begin
+ reader.next;
+ if isOutOfBound then exit;
+ end;
+
+ // line comment
+ if (reader.head^ = '/') then
+ begin
+ if (reader.next^ = '/') then
+ begin
+ if isOutOfBound then exit;
+ while (reader.head^ <> #10) do
+ begin
+ reader.next;
+ identifier += reader.head^;
+ if isOutOfBound then exit;
+ end;
+ reader.next;
+ addToken(ltkComment);
+ continue;
+ end
+ else
+ reader.previous;
+ end;
+
+ // block comments 1
+ if (reader.head^ = '/') then
+ begin
+ if (reader.next^ = '*') then
+ begin
+ if isOutOfBound then exit;
+ while (reader.head^ <> '*') or (reader.next^ <> '/') do
+ if isOutOfBound then exit;
+ reader.next;
+ addToken(ltkComment);
+ continue;
+ end
+ else
+ reader.previous;
+ end;
+
+ // block comments 2
+ if (reader.head^ = '/') then
+ begin
+ if (reader.next^ = '+') then
+ begin
+ if isOutOfBound then exit;
+ while (reader.head^ <> '+') or (reader.next^ <> '/') do
+ if isOutOfBound then exit;
+ reader.next;
+ addToken(ltkComment);
+ continue;
+ end
+ else
+ reader.previous;
+ end;
+
+ // string 1, note: same escape error as in SynD2Syn
+ if (reader.head^ in ['r', 'x']) then
+ begin
+ if not (reader.next^ = '"') then
+ reader.previous;
+ end;
+ if (reader.head^ = '"') then
+ begin
+ reader.next;
+ if isOutOfBound then exit;
+ if (reader.head^ = '"') then
+ begin
+ reader.next;
+ addToken(ltkString);
+ continue;
+ end;
+ while (true) do
+ begin
+ if reader.head^ = '\' then
+ begin
+ reader.next;
+ if (reader.head^ = '"') then
+ begin
+ reader.next;
+ continue;
+ end;
+ end;
+ if (reader.head^ = '"') then
+ break;
+ identifier += reader.head^;
+ reader.next;
+ if isOutOfBound then exit;
+ end;
+ if isStringPostfix(reader.next^) then
+ reader.next;
+ addToken(ltkString);
+ continue;
+ end;
+
+ // string 2
+ if (reader.head^ = '`') then
+ begin
+ reader.next;
+ if isOutOfBound then exit;
+ while (reader.head^ <> '`') do
+ begin
+ identifier += reader.head^;
+ reader.next;
+ if isOutOfBound then exit;
+ end;
+ if isStringPostfix(reader.next^) then
+ reader.next;
+ if isOutOfBound then exit;
+ addToken(ltkString);
+ continue;
+ end;
+
+ //chars, note: same escape error as in SynD2Syn
+ if (reader.head^ = #39) then
+ begin
+ reader.next;
+ if isOutOfBound then exit;
+ if (reader.head^ = #39) then
+ begin
+ reader.next;
+ addToken(ltkString);
+ continue;
+ end;
+ while (true) do
+ begin
+ if reader.head^ = '\' then
+ begin
+ reader.next;
+ if (reader.head^ = #39) then
+ begin
+ reader.next;
+ continue;
+ end;
+ end;
+ if (reader.head^ = #39) then
+ break;
+ identifier += reader.head^;
+ reader.next;
+ if isOutOfBound then exit;
+ end;
+ reader.next;
+ addToken(ltkChar);
+ continue;
+ end;
+
+ // check negative float '-0.'
+ if (reader.head^ = '-') then
+ begin
+ identifier += reader.head^;
+ if reader.next^ = '0' then
+ begin
+ if reader.next^ = '.' then
+ reader.previous // back to 0, get into "binary/hex numbr/float"
+ else
+ begin
+ reader.previous;
+ reader.previous; // back to -
+ identifier := '';
+ end;
+ end
+ else
+ begin
+ reader.previous; // back to -
+ identifier := '';
+ end;
+ end;
+
+ // + suffixes
+ // + exponent
+ // float .xxxx
+
+ // binary/hex numbr/float
+ if (reader.head^ = '0') then
+ begin
+ identifier += reader.head^;
+ if (reader.next^ in ['b','B']) then
+ begin
+ identifier += reader.head^;
+ while isBit(reader.next^) or (reader.head^ = '_') do
+ begin
+ if isOutOfBound then exit;
+ identifier += reader.head^;
+ end;
+ addToken(ltkNumber);
+ continue;
+ end
+ else reader.previous;
+ if (reader.next^ in ['x','X']) then
+ begin
+ identifier += reader.head^;
+ while isHex(reader.next^) or (reader.head^ = '_') do
+ begin
+ if isOutOfBound then exit;
+ identifier += reader.head^;
+ end;
+ addToken(ltkNumber);
+ continue;
+ end
+ else reader.previous;
+ if (reader.next^ = '.') then
+ begin
+ identifier += reader.head^;
+ while isNumber(reader.next^) do
+ begin
+ if isOutOfBound then exit;
+ identifier += reader.head^;
+ end;
+ addToken(ltkNumber);
+ continue;
+ end
+ else reader.previous;
+ identifier := '';
+ end;
+
+ // check negative float/int '-xxx'
+ if (reader.head^ = '-') then
+ begin
+ identifier += reader.head^;
+ if not isNumber(reader.next^) then
+ begin
+ reader.previous; // back to '-'
+ identifier := '';
+ end;
+ end;
+
+ // numbers
+ if isNumber(reader.head^) then
+ begin
+ identifier += reader.head^;
+ while isNumber(reader.next^) or (reader.head^ = '_') do
+ begin
+ if isOutOfBound then exit;
+ identifier += reader.head^;
+ end;
+ addToken(ltkNumber);
+ continue;
+ end;
+
+ // symbols
+ if isSymbol(reader.head^) then
+ begin
+ identifier += reader.head^;
+ reader.next;
+ addToken(ltkSymbol);
+ if isOutOfBound then exit;
+ continue;
+ end;
+
+ // operators
+ if isOperator1(reader.head^) then
+ begin
+ identifier += reader.head^;
+ while isOperator1(reader.next^) do
+ begin
+ if isOutOfBound then exit;
+ identifier += reader.head^;
+ end;
+ case length(identifier) of
+ 4:begin
+ if (not isOperator1(reader.head^)) and
+ isOperator4(identifier) then
+ begin
+ addToken(ltkOperator);
+ continue;
+ end;
+ end;
+ 3:begin
+ if (not isOperator1(reader.head^)) and
+ isOperator3(identifier) then
+ begin
+ addToken(ltkOperator);
+ continue;
+ end;
+ end;
+ 2:begin
+ if (not isOperator1(reader.head^)) and
+ isOperator2(identifier) then
+ begin
+ addToken(ltkOperator);
+ continue;
+ end;
+ end;
+ 1:begin
+ if not isOperator1(reader.head^)
+ then
+ begin
+ addToken(ltkOperator);
+ continue;
+ end;
+ end;
+ end;
+ end;
+
+ // identifier accum
+ if isFirstIdentifier(reader.head^) then
+ begin
+ while isIdentifier(reader.head^) do
+ begin
+ identifier += reader.head^;
+ reader.next;
+ if isOutOfBound then exit;
+ end;
+ if D2Dictionary.find(identifier) then
+ addToken(ltkKeyword)
+ else
+ addToken(ltkIdentifier);
+ continue;
+ end;
+
+ // error
+ identifier += ' (unrecognized lexer input)';
+ addToken(ltkIllegal);
+
+ end;
+end;
+{$BOOLEVAL OFF}
+{$ENDREGION}
+
+{$REGION Syntaxic errors}
+function TLexErrorList.getError(index: integer): TLexError;
+begin
+ result := PLexError(Items[index])^;
+end;
+
+procedure TLexErrorList.clear;
+begin
+ while Count > 0 do
+ begin
+ Dispose( PLexError(Items[Count-1]) );
+ Delete(Count-1);
+ end;
+end;
+
+procedure TLexErrorList.addError(aValue: PLexError);
+begin
+ add(Pointer(aValue));
+end;
+
+function TLexErrorEnumerator.GetCurrent: TLexError;
+begin
+ exit(fList.error[fIndex]);
+end;
+
+function TLexErrorEnumerator.MoveNext: Boolean;
+begin
+ Inc(fIndex);
+ exit(fIndex < fList.Count);
+end;
+
+operator enumerator(anErrorList: TLexErrorList): TLexErrorEnumerator;
+begin
+ result := TLexErrorEnumerator.Create;
+ result.fList := anErrorList;
+ result.fIndex := -1;
+end;
+
+procedure checkSyntaxicErrors(const aTokenList: TLexTokenList; const anErrorList: TLexErrorList);
+const
+ errPrefix = 'syntaxic error: ';
+var
+ tk, old1, old2: TLexToken;
+ err: PLexError;
+ tkIndex: NativeInt;
+ pareCnt, curlCnt, squaCnt: NativeInt;
+procedure addError(const aMsg: string);
+begin
+ err := new(PLexError);
+ err^.msg := errPrefix + aMsg;
+ err^.position := aTokenList.token[tkIndex].position;
+ anErrorList.addError(err);
+end;
+label
+ _preSeq;
+begin
+
+ tkIndex := -1;
+ pareCnt := 0;
+ curlCnt := 0;
+ squaCnt := 0;
+
+ for tk in aTokenList do
+ begin
+
+ // token index
+ Inc(tkIndex);
+
+ // brackets count
+ if tk.kind = ltkSymbol then
+ begin
+ case tk.data of
+ '(': Inc(pareCnt);
+ '{': Inc(curlCnt);
+ '[': Inc(squaCnt);
+ ')': Dec(pareCnt);
+ '}': Dec(curlCnt);
+ ']': Dec(squaCnt);
+ end;
+
+ // only for the first occurence
+ if pareCnt = -1 then
+ addError('a left parenthesis is missing');
+ if curlCnt = -1 then
+ addError('a left curly bracket is missing');
+ if squaCnt = -1 then
+ addError('a left square bracket is missing');
+
+ // at the end
+ if (tkIndex = aTokenList.Count-1) then
+ begin
+ if pareCnt > 0 then
+ addError('a right parenthesis is missing');
+ if curlCnt > 0 then
+ addError('a right curly bracket is missing');
+ if squaCnt > 0 then
+ addError('a right square bracket is missing');
+ end;
+
+ goto _preSeq;
+ end;
+
+ // lexer invalid token
+ if tk.kind = ltkIllegal then
+ begin
+ addError(tk.data);
+ goto _preSeq;
+ end;
+
+ // invalid numbers
+ if tk.kind = ltkNumber then
+ begin
+
+ goto _preSeq;
+ end;
+
+_preSeq:
+ // invalid sequences
+ if tkIndex > 0 then // can use old1
+ begin
+ if (old1.kind = ltkKeyword) and (tk.kind = ltkKeyword) then
+ if old1.data = tk.data then
+ addError('keyword is duplicated');
+
+ // needs negative numbr to be tokenized correctly: ... = -1; '-' is currently token as an operator.
+ if (old1.kind = ltkOperator) and (tk.kind = ltkOperator) then
+ addError('operator rhs cannot be an operator');
+
+ if (old1.kind = ltkNumber) and (tk.kind = ltkNumber) then
+ addError('symbol or operator expected after number');
+
+ end;
+ if tkIndex > 1 then // can use old2
+ begin
+
+ end;
+
+
+ old1 := tk;
+ old2 := old1;
+ end;
+
+
+end;
+{$ENDREGION}
+
+initialization
+ D2Dictionary.create;
+finalization
+ D2Dictionary.destroy;
+end.
+
diff --git a/src/ce_dlangutils.pas b/src/ce_dlangutils.pas
new file mode 100644
index 00000000..684aa91d
--- /dev/null
+++ b/src/ce_dlangutils.pas
@@ -0,0 +1,135 @@
+unit ce_dlangutils;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils;
+
+function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isSpace(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isAlpha(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isNumber(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isBit(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isAlNum(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isHex(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isSymbol(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isOperator1(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isOperator2(const s: string): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isOperator3(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
+function isOperator4(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
+function isStringPostfix(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+function isFirstIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+
+implementation
+
+{$BOOLEVAL ON}
+function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(c in [#0..#32]);
+end;
+
+function isSpace(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(c in [#9,' ']);
+end;
+
+function isAlpha(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit((c in ['a'..'z']) or (c in ['A'..'Z']));
+end;
+
+function isNumber(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(c in ['0'..'9']);
+end;
+
+function isBit(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit((c in ['0'..'1']));
+end;
+
+function isAlNum(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(isAlpha(c) or isNumber(c));
+end;
+
+function isHex(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(isNumber(c) or (c in ['A'..'F']) or (c in ['a'..'f']));
+end;
+
+function isSymbol(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(c in [';', '{', '}', '(', ')', '[', ']', ',', '.', ':' , '"', #39, '?', '$']);
+end;
+
+function isOperator1(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(c in ['/', '*', '-', '+', '%', '>', '<', '=', '!',
+ '&', '|', '^', '~']);
+end;
+
+function isOperator2(const s: string): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ result := false;
+ case s[1] of
+ '.': result := (s[2] = '.');
+
+ '>': result := s[2] in ['>', '='];
+ '<': result := s[2] in ['<', '=', '>'];
+ '=': result := s[2] in ['=', '>'];
+ '!': result := s[2] in ['=', '>', '<'];
+
+ '+': result := s[2] in ['+', '='];
+ '-': result := s[2] in ['-', '='];
+ '/': result := s[2] in ['='];
+ '*': result := s[2] in ['='];
+ '%': result := s[2] in ['='];
+ '~': result := s[2] in ['='];
+
+ '&': result := s[2] in ['&', '='];
+ '|': result := s[2] in ['|', '='];
+ '^': result := s[2] in ['^', '='];
+ end;
+end;
+
+function isOperator3(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
+begin
+ result := false;
+ case s[1] of
+ '.': result := (s[2] = '.') and (s[3] = '.');
+ '^': result := (s[2] = '^') and (s[3] = '=');
+ '>': result := (s[2] = '>') and (s[3] in ['>', '=']);
+ '<': result := ((s[2] = '<') and (s[3] in ['<', '=']))
+ or (s[2] = '>') and (s[3] = '=');
+ '!': result := ((s[2] = '<') and (s[3] in ['>', '=']))
+ or ((s[2] = '>')and (s[3] = '='));
+ end;
+end;
+
+function isOperator4(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
+begin
+ result := (s = '>>>=') or (s = '!<>=');
+end;
+
+function isStringPostfix(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(c in ['c', 'w', 'd']);
+end;
+
+function isIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit((not isSymbol(c)) and (not isOperator1(c)) and (not isWhite(c)));
+end;
+
+function isFirstIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
+begin
+ exit(isIdentifier(c) and (not isNumber(c)));
+end;
+{$BOOLEVAL OFF}
+
+end.
+
diff --git a/src/ce_editor.pas b/src/ce_editor.pas
index 11a605d3..03d91322 100644
--- a/src/ce_editor.pas
+++ b/src/ce_editor.pas
@@ -8,7 +8,8 @@ uses
Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype,
Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus,
SynEditHighlighterFoldBase, SynMacroRecorder, SynPluginSyncroEdit, SynEdit,
- SynHighlighterLFM, ce_widget, ce_d2syn, ce_synmemo, ce_common, AnchorDocking;
+ SynHighlighterLFM, ce_widget, ce_d2syn, ce_synmemo, ce_common, AnchorDocking,
+ ce_dlang;
type
{ TCEEditorWidget }
@@ -26,7 +27,6 @@ type
fKeyChanged: boolean;
fSyncEdit: TSynPluginSyncroEdit;
procedure memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
- procedure memoKeyPress(Sender: TObject; var Key: Char);
procedure memoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure memoChange(Sender: TObject);
procedure memoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
@@ -138,7 +138,6 @@ begin
memo.OnMouseDown := @memoMouseDown;
memo.OnChange := @memoChange;
memo.OnMouseMove := @memoMouseMove;
- memo.OnKeyPress := @memoKeyPress;
//
pageControl.ActivePage := sheet;
//http://bugs.freepascal.org/view.php?id=26320
@@ -158,15 +157,13 @@ end;
procedure TCEEditorWidget.memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
-end;
-
-procedure TCEEditorWidget.memoKeyPress(Sender: TObject; var Key: Char);
-begin
- if (sender is TCESynMemo) then
+if (sender is TCESynMemo) then
identifierToD2Syn(TCESynMemo(Sender));
+ fKeyChanged := true;
case Byte(Key) of
- VK_UNKNOWN..VK_BACK: exit;
- VK_PRIOR..VK_HELP: exit;
+ VK_UNKNOWN..VK_XBUTTON2: exit;
+ VK_SHIFT..VK_HELP: fKeyChanged := false;
+ VK_LWIN..VK_SLEEP: exit;
VK_F1..$91: exit;
end;
fKeyChanged := true;
@@ -200,6 +197,9 @@ const
modstr: array[boolean] of string = ('...', 'MODIFIED');
var
ed: TCESynMemo;
+ tokLst: TLexTokenList;
+ errLst: TLexErrorList;
+ err: TLexError;
begin
ed := getCurrentEditor;
if ed <> nil then
@@ -210,8 +210,31 @@ begin
end;
//
if fKeyChanged then if editorIndex <> -1 then
+ begin
mainForm.docChangeNotify(Self, editorIndex);
+
+ mainForm.MessageWidget.List.Clear;
+ tokLst := TLexTokenList.Create;
+ errLst := TLexErrorList.Create;
+ try
+ lex( ed.Lines.Text, tokLst );
+ checkSyntaxicErrors( tokLst, errLst);
+
+ for err in errLst do
+ mainForm.MessageWidget.addMessage(format(
+ '%s (@line:%4.d @char:%.4d)',[err.msg, err.position.y, err.position.x]));
+
+ mainForm.MessageWidget.scrollToBack;
+
+ finally
+ tokLst.Free;
+ errLst.Free;
+ end;
+
+
+ end;
fKeyChanged := false;
+
end;
end.
diff --git a/src/ce_main.lfm b/src/ce_main.lfm
index 71471e14..4d461d75 100644
--- a/src/ce_main.lfm
+++ b/src/ce_main.lfm
@@ -2547,39 +2547,39 @@ object CEMainForm: TCEMainForm
0000000000330000003300000033000000332D73BAAF1B3D60523F93D4FF3F93
D4FF102438413578BAC300000024000000000000000000000000000000000000
0000000000000000000000000000000000000000001F00000008000000330000
- 0033000000040000002400000000B3B3B1EFB0B0ADFFAEAEACFFAEAEABFFAEAE
- ABFFAEAEABFFADAEABFFAEAEABFFAFAFADFFB0B0AEEAB3B3B100B5B5B300B5B5
- B300B5B5B300B5B5B300B5B5B300AFAFADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
- FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9E9E9FFAEAEACA6B3B3B100B5B5
- B300B5B5B300B5B5B300B5B5B300AEAEACFFFFFFFFFFE0DFDEFFE1DFDEFFE1E0
- DFFFE1DFDEFFE0DFDEFFFFFFFFFFA5A5A3FFFFFFFFFFE8E8E8FFAFAFACA7B3B3
- B100B5B5B300B5B5B300B6B6B400AEAEABFFFFFFFFFFE3E3E2FFE4E4E3FFE4E5
- E4FFE4E4E3FFE3E3E2FFFFFFFFFFA7A7A5FFECECEBFFFFFFFFFFEAEAEAFFB1B1
- AFACB6B6B400B8B8B600B9B9B700ADAEABFFFFFFFFFFE7E5E4FFE8E7E6FFE8E7
- E6FFE8E7E6FFE7E6E5FFFFFFFFFFCDCDCCFFAAAAA8FFADADABFFFFFFFFFFB3B3
- B1FFB8B9B7008A8886008C898700ADADABFFFFFFFFFFE9E9E8FFEAEAE9FFEAEA
- E9FFEAEAE9FFECECEBFFFAFAF9FFFFFFFFFFFFFFFFFF7B7976FF7E7B79FFB8B8
- B6FF979593008D8B89008F8D8B00ADADABFFFFFFFFFFECEBEAFFEDECEBFFEDEC
- EBFFEEEDECFFF3F2F1FF7B7977FF8C8987FFCBCAC8FFB2AFADFFB5B2B0FFA3A3
- A1FF979593FF8D8B89FF908E8B00ADADABFFFFFFFFFFEFEFEEFFEFEFEEFFEFEF
- EEFFF1F1F0FFF7F8F7FF8B8987FFD8D5D5FF9B9996FFD0CECDFFD1CFCEFF9D9B
- 99FFDCDAD9FF918F8DFF94929000ADADABFFFFFFFFFFF2F1F0FFF2F1F0FFF3F1
- F0FFF6F5F4FFFFFEFDFFB6B3B3FF9B9996FFBCBAB9FF92908FFF92908FFFBCBA
- B9FF9E9C9AFF6C6B699B908E8C00ADADABFFFFFFFFFFF4F4F3FFF4F4F3FFF5F6
- F4FFFCFCFBFF73706EFFABA9A8FFCCCAC9FF918F8DFFE1E1E1FFECECEBFF918F
- 8CFFCDCBCBFFB1AFAEFF8F8D8BFFADADABFFFFFFFFFFF6F6F6FFF6F6F6FFF7F8
- F8FFFEFFFFFF726F6DFFAAA8A7FFCAC8C7FF8E8C8BFFFFFFFFFFFFFFFFFF8E8C
- 8BFFCBC9C8FFB0AEADFF8E8C8AFFADADABFFFFFFFFFFFAF8F8FFF9F8F8FFFAF9
- F9FFFEFDFDFFE1E1E0FFC2C1C0FF959392FFB5B3B2FF8D8B89FF8D8B88FFB5B3
- B2FF999796FF646260894847465BAEAEABFFFFFFFFFFFDFDFDFFFCFCFDFFFCFD
- FDFFFFFFFFFFFFFFFFFF84817FFFCCCAC9FF949291FFC5C3C2FFC6C4C3FF9694
- 93FFD0CECDFF8B8988FF0000000AB0B0ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
- FFFFFFFFFFFFFFFFFFFF787573FF817E7CFFDDDCDDFFA5A3A2FFA7A5A4FFA4A3
- A1FF878583FF868482FF88868400A4A4A2C0AFAFADFFAEAEABFFADADABFFADAD
- ABFFAEAEACFFB1B1AEFFB6B6B4FFB7B8B6FFB9BAB7FF797776FF7A7877FFADAE
- ACB9000000330000003388868400000000000000003300000033000000330000
- 0033000000330000003300000033000000330000003300000033000000330000
- 0022000000000000000000000000FFFFFF000000000000000000000000000000
+ 0033000000040000002400000000BB871F00BB871F00BB871E00B9841A00B67E
+ 0FEAC4973BFFC79D49FFC39538FFB37904FFB47A07FFB47A07FFB47A08FFB57C
+ 0AFFB67F0FFFB88114FFBA851B23BB871F00BB871F00BA861D00B7801283E4CF
+ A7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFE9DABAFFEEE2C9FFB67F14BFBB871F00BB871F00B9851B00B27A09E5FFFF
+ FFFFFFFFFFFFFEFEFBFFFEFEFBFFFEFEFCFFFEFEFCFFFEFEFCFFFFFFFEFFFFFF
+ FFFFC69941FFECDFC2FFC19234FFBB871F00BB871E00B9831800C89E49FFFFFF
+ FFFFFCF9F3FFFBF8F1FFFBF8F1FFFBF8F1FFFBF8F1FFFCF9F3FFFDFBF6FFFFFF
+ FFFFB27701FFBA851BFFBC8921FFBB871F00BB861E00B882150CCCA556FFFFFF
+ FFFFF9F6EBFFF9F5EAFFFAF6ECFFFBF7EDFFFDF9EEFFFFFCF1FFFFFFFCFFFFFF
+ FFFFAB7405CE0000003300000033BB871F00BB861D00B07B1134DBBF88FFFFFF
+ FFFFF7F2E5FFFAF4E6FFFEF7E9FFFFF9EAFFFFFCEDFF767574FF777778FFF8E9
+ CAFFAA7200A8888D99008B8E9700BB871F00BA861D00AD790E73EADBBBFFFAF7
+ EEFFF6EFDEFFFCF4E2FF7B797AFF8B8A89FFD2CCBFFFB1AFAEFFB1B1B1FFC3B2
+ 8EFF939499FF8C8B8EFF8E8E8E00BB871F00BA851C00AA760C9BF0E4CCFFF6EF
+ E0FFF4ECD7FFFAF2DCFF8B8A8AFFD7D6D6FF9A9997FFD0CECEFFD0CFCFFF9C9A
+ 9AFFDBDADBFF918F8EFF94929000BB871F00BA851C00B0790BD2FFFFFFFFF1E9
+ D2FFF4EBD2FFFCF2D7FFB4AFA2FF9B9997FFBCBABAFF939191FF929191FFBCBA
+ BAFF9E9C9AFF6C6B699B908E8C00BB871E00B9841900B8831BEFFFFFFFFFF2E9
+ D3FFF7EDD4FF747577FFABA9AAFFCCCACAFF92908FFFDCD2B9FFE9E7E2FF918F
+ 8EFFCECCCBFFB1AFAEFF8F8D8BFFB98419FFB67E0EFFB67F0FFFC0902EFFC08E
+ 29FFC59128FF747578FFAAA8A9FFCAC8C7FF8F8D8EFFFFF2D2FFFFFFF5FF8F8D
+ 8DFFCBC9C9FFB0AEADFF8E8C8AFFB78012FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFE3E3DFFFC2C1BBFF959493FFB5B3B4FF8D8C8CFF8D8C8BFFB6B4
+ B3FF999796FF646260894847465BAC7A14CADCC189FFF5F0E0FFF4EDDBFFF4ED
+ DBFFF6EFDBFFFDF4DCFF878789FFCECDCEFF969698FFC6C5C6FFC7C5C5FF9896
+ 95FFD1CFCEFF8B8988FF0000000A60440E44B88114FFB67E0FFFB57D0DFFB57D
+ 0CFFB67E0CFFBC7F06FF7F8188FF86878AFFA87F2DFFA8A8ABFFAAA8A8FF5250
+ 4F698A8886FF868482FF88868400000000070000003300000033000000330000
+ 003300000033000000330000003300000033000000337C7C81FF7E7D7DFF0000
+ 000E000000330000003388868400000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000033000000330000
+ 0000000000000000000000000000FFFFFF000000000000000000000000000000
0000000000000000000000000000A6A4A133A5A39FE5AEACA9FFB9B6B5FFABA9
A5FFA7A5A2D2A8A6A323FFFFFF00FFFFFF000000000000000000000000000000
00000000000000000000A19F9C48AEACAAFFDADAD9FFF0EEEFFFECEBEAFFE2E0
diff --git a/src/ce_main.pas b/src/ce_main.pas
index 38a706a5..9c4e1a9e 100644
--- a/src/ce_main.pas
+++ b/src/ce_main.pas
@@ -16,7 +16,7 @@ type
TCEMainForm = class;
(**
- * Encapsulates the options.
+ * Encapsulates the options in a writable component.
* note: likely to change however needed to test correctly Coedit.
*)
TCEOptions = class(TComponent)
@@ -45,7 +45,7 @@ type
procedure saveToFile(const aFilename: string);
procedure loadFromFile(const aFilename: string);
procedure beforeSave;
- procedure afterSave;
+ procedure afterLoad;
procedure DefineProperties(Filer: TFiler); override;
end;
@@ -375,8 +375,8 @@ begin
actEdIndent.Enabled := true;
actEdUnIndent.Enabled := true;
//
- actFileCompAndRun.Enabled := true;
- actFileCompAndRunWithArgs.Enabled := true;
+ actFileCompAndRun.Enabled := curr.isDSource;
+ actFileCompAndRunWithArgs.Enabled := curr.isDSource;
actFileSave.Enabled := true;
actFileSaveAs.Enabled := true;
actFileClose.Enabled := true;
@@ -694,7 +694,7 @@ var
begin
if fEditWidg = nil then exit;
if fEditWidg.editorIndex < 0 then exit;
- if fEditWidg.editor[fEditWidg.editorIndex].Highlighter = LfmSyn
+ if fEditWidg.editor[fEditWidg.editorIndex].isProjectSource
then exit;
//
str := fEditWidg.editor[fEditWidg.editorIndex].fileName;
@@ -1327,10 +1327,10 @@ begin
except
exit;
end;
- afterSave;
+ afterLoad;
end;
-procedure TCEOptions.afterSave;
+procedure TCEOptions.afterLoad;
var
widg: TCEWidget;
begin
diff --git a/src/ce_synmemo.pas b/src/ce_synmemo.pas
index 75bbf3c6..26e617f9 100644
--- a/src/ce_synmemo.pas
+++ b/src/ce_synmemo.pas
@@ -15,12 +15,17 @@ type
fFilename: string;
fModified: boolean;
fAssocProject: TCEProject;
+ function getIfDSource: Boolean;
+ function getIfConfig: Boolean;
public
constructor Create(aOwner: TComponent); override;
//
property fileName: string read fFilename write fFilename;
property modified: boolean read fModified write fModified;
property project: TCEProject read fAssocProject write fAssocProject;
+ //
+ property isDSource: boolean read getIfDSource;
+ property isProjectSource: boolean read getIfConfig;
end;
var
@@ -29,7 +34,7 @@ var
implementation
uses
- graphics;
+ graphics, ce_main;
constructor TCESynMemo.Create(aOwner: TComponent);
begin
@@ -52,6 +57,16 @@ begin
Highlighter := D2Syn;
end;
+function TCESynMemo.getIfDSource: Boolean;
+begin
+ exit(Highlighter = D2Syn);
+end;
+
+function TCESynMemo.getIfConfig: Boolean;
+begin
+ exit(Highlighter = mainForm.LfmSyn);
+end;
+
initialization
D2Syn := TSynD2Syn.create(nil);
finalization
diff --git a/src/ce_widget.pas b/src/ce_widget.pas
index 801704f2..e1c1158b 100644
--- a/src/ce_widget.pas
+++ b/src/ce_widget.pas
@@ -100,9 +100,6 @@ type
implementation
{$R *.lfm}
-uses
- ce_main;
-
(*******************************************************************************
* TCEWidget
*)
@@ -119,8 +116,8 @@ begin
fUpdaterAuto.OnTimer := @updaterAutoProc;
fUpdaterDelay := TTimer.Create(self);
- updaterByLoopInterval := 50;
- updaterByDelayDuration := 1000;
+ updaterByLoopInterval := 70;
+ updaterByDelayDuration := 1250;
DockMaster.MakeDockable(Self, true, true, true);
DockMaster.GetAnchorSite(Self).Header.HeaderPosition := adlhpTop;