Fix inconsistencies in brace closing behavior.

This commit is contained in:
Marco Leise 2019-01-27 17:35:09 +01:00 committed by Basile-z
parent 1335208d25
commit 5698637bec
1 changed files with 94 additions and 65 deletions

View File

@ -44,6 +44,12 @@ type
TAutoClosePairs = set of TAutoClosedPair; TAutoClosePairs = set of TAutoClosedPair;
TBraceCloseOption = (
braceClosePositive,
braceCloseLessEven,
braceCloseInvalid
);
const const
autoClosePair2Char: array[TAutoClosedPair] of char = (#39, '"', '`', ']'); autoClosePair2Char: array[TAutoClosedPair] of char = (#39, '"', '`', ']');
@ -279,8 +285,9 @@ type
procedure completionCodeCompletion(var value: string; SourceValue: string; procedure completionCodeCompletion(var value: string; SourceValue: string;
var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char; Shift: TShiftState); var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char; Shift: TShiftState);
procedure showCallTipsString(const tips: string; indexOfExpected: integer); procedure showCallTipsString(const tips: string; indexOfExpected: integer);
function lexCanCloseBrace: boolean; function lexCanCloseBrace: TBraceCloseOption;
function canInsertLeadingDdocSymbol: char; function canInsertLeadingDdocSymbol: char;
function autoIndentationLevel(line: Integer): Integer;
procedure handleStatusChanged(Sender: TObject; Changes: TSynStatusChanges); procedure handleStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
procedure goToChangedArea(next: boolean); procedure goToChangedArea(next: boolean);
procedure goToProtectionGroup(next: boolean); procedure goToProtectionGroup(next: boolean);
@ -339,7 +346,7 @@ type
procedure forceIndentation(m: TIndentationMode; w: integer); procedure forceIndentation(m: TIndentationMode; w: integer);
procedure addBreakPoint(line: integer); procedure addBreakPoint(line: integer);
procedure removeBreakPoint(line: integer); procedure removeBreakPoint(line: integer);
procedure curlyBraceCloseAndIndent; procedure curlyBraceCloseAndIndent(close: boolean = true);
procedure insertLeadingDDocSymbol(c: char); procedure insertLeadingDDocSymbol(c: char);
procedure commentSelection; procedure commentSelection;
procedure commentIdentifier; procedure commentIdentifier;
@ -1671,35 +1678,33 @@ begin
EndUndoBlock; EndUndoBlock;
end; end;
procedure TDexedMemo.curlyBraceCloseAndIndent; function TDexedMemo.autoIndentationLevel(line: Integer): Integer;
var var
i: integer; i: integer;
beg: string = ''; beg: string = '';
balanceInBeg: Integer = 0;
numTabs: integer = 0; numTabs: integer = 0;
numSpac: integer = 0; numSpac: integer = 0;
numSkip: integer = 0; numSkip: integer = 0;
c: Char;
begin begin
if not fIsDSource and not alwaysAdvancedFeatures then if not fIsDSource and not alwaysAdvancedFeatures or
exit; not (eoAutoIndent in Options) then
exit(0);
i := CaretY - 1; for i := line - 2 downto 0 do
while true do
begin begin
if i < 0 then
break;
beg := Lines[i]; beg := Lines[i];
if (Pos('}', beg) <> 0) then balanceInBeg := 0;
begin for c in beg do
numSkip += 1; if c = '}' then
end balanceInBeg -= 1
else if (Pos('{', beg) <> 0) then else if c = '{' then
begin balanceInBeg += 1;
numSkip -= 1; numSkip -= balanceInBeg;
end;
if numSkip < 0 then if numSkip < 0 then
break break
else else
i -= 1;
end; end;
for i:= 1 to beg.length do for i:= 1 to beg.length do
@ -1710,22 +1715,35 @@ begin
else break; else break;
end; end;
end; end;
numTabs += numSpac div TabWidth; result := numTabs + numSpac div TabWidth;
if balanceInBeg > 0 then
result += 1;
end;
procedure TDexedMemo.curlyBraceCloseAndIndent(close: boolean = true);
var
numTabs, i: integer;
begin
if not fIsDSource and not alwaysAdvancedFeatures then
exit;
BeginUndoBlock; BeginUndoBlock;
CommandProcessor(ecInsertLine, '', nil); CommandProcessor(ecLineBreak, '', nil);
CommandProcessor(ecDown, '', nil); numTabs := autoIndentationLevel(CaretY);
if close then
CommandProcessor(ecInsertLine, '', nil); begin
CommandProcessor(ecDown, '', nil); if not isBlank(lineText) then // put rest of line on a new one after the `}`
while CaretX <> 1 do CommandProcessor(ecLeft, '' , nil); CommandProcessor(ecInsertLine, '', nil);
for i:= 0 to numTabs-1 do CommandProcessor(ecTab, '', nil); CommandProcessor(ecLineBreak, '', nil);
CommandProcessor(ecChar, '}', nil); CommandProcessor(ecDeleteBOL, '', nil);
for i:= 1 to numTabs-1 do CommandProcessor(ecTab, '', nil);
CommandProcessor(ecUp, '', nil); CommandProcessor(ecChar, '}', nil);
while CaretX <> 1 do CommandProcessor(ecLeft, '' , nil); CommandProcessor(ecUp, '', nil);
for i:= 0 to numTabs do CommandProcessor(ecTab, '', nil); CommandProcessor(ecLineEnd, '', nil);
end;
CommandProcessor(ecDeleteBOL, '', nil);
for i:= 1 to numTabs do CommandProcessor(ecTab, '', nil);
EndUndoBlock; EndUndoBlock;
end; end;
@ -3148,7 +3166,7 @@ begin
end; end;
end; end;
function TDexedMemo.lexCanCloseBrace: boolean; function TDexedMemo.lexCanCloseBrace: TBraceCloseOption;
var var
i: integer; i: integer;
p: integer; p: integer;
@ -3168,16 +3186,18 @@ begin
end else end else
bet := false; bet := false;
if bet and (tok^.kind = ltkComment) then if bet and (tok^.kind = ltkComment) then
exit(false); exit(braceCloseInvalid);
c += byte((tok^.kind = TLexTokenKind.ltkSymbol) and (((tok^.Data = '{')) or (tok^.Data = 'q{'))); c += byte((tok^.kind = TLexTokenKind.ltkSymbol) and (((tok^.Data = '{')) or (tok^.Data = 'q{')));
c -= byte((tok^.kind = TLexTokenKind.ltkSymbol) and (tok^.Data = '}')); c -= byte((tok^.kind = TLexTokenKind.ltkSymbol) and (tok^.Data = '}'));
if bet and (c = 0) then if bet and (c = 0) then
exit(false); exit(braceCloseLessEven);
end; end;
if (tok <> nil) and (tok^.kind = ltkIllegal) then if (tok <> nil) and (tok^.kind = ltkIllegal) then
result := false result := braceCloseInvalid
else if c > 0 then
result := braceClosePositive
else else
result := c > 0; result := braceCloseLessEven;
end; end;
procedure TDexedMemo.SetHighlighter(const Value: TSynCustomHighlighter); procedure TDexedMemo.SetHighlighter(const Value: TSynCustomHighlighter);
@ -3481,6 +3501,7 @@ var
line: string; line: string;
ddc: char; ddc: char;
lxd: boolean; lxd: boolean;
ccb: TBraceCloseOption;
begin begin
case Key of case Key of
VK_BACK: VK_BACK:
@ -3496,52 +3517,58 @@ begin
line := LineText; line := LineText;
if [ssCtrl] <> Shift then if [ssCtrl] <> Shift then
begin begin
lxd := false;
case fAutoCloseCurlyBrace of case fAutoCloseCurlyBrace of
autoCloseOnNewLineAlways: if (CaretX > 1) and (line[LogicalCaretXY.X - 1] = '{') then autoCloseAlways, autoCloseOnNewLineAlways:
if (CaretX > 1) and (line[LogicalCaretXY.X - 1] = '{') then
begin begin
Key := 0; Key := 0;
curlyBraceCloseAndIndent; curlyBraceCloseAndIndent;
end; end;
autoCloseOnNewLineEof: if (CaretX > 1) and (line[LogicalCaretXY.X - 1] = '{') then autoCloseAtEof, autoCloseOnNewLineEof:
if (CaretX > 1) and (line[LogicalCaretXY.X - 1] = '{') then
if (CaretY = Lines.Count) and (CaretX = line.length+1) then if (CaretY = Lines.Count) and (CaretX = line.length+1) then
begin begin
Key := 0; Key := 0;
curlyBraceCloseAndIndent; curlyBraceCloseAndIndent;
end; end;
end; autoCloseNever:
if (fAutoCloseCurlyBrace = autoCloseOnNewLineLexically) or if (CaretX > 1) and (line[LogicalCaretXY.X - 1] = '{') then
fSmartDdocNewline then begin
begin Key := 0;
lxd := false; curlyBraceCloseAndIndent(false);
if (LogicalCaretXY.X - 1 >= line.length) end;
or isBlank(line[LogicalCaretXY.X .. line.length]) then autoCloseLexically, autoCloseOnNewLineLexically:
if ((LogicalCaretXY.X - 1 >= line.length) or
isBlank(line[LogicalCaretXY.X .. line.length])) then
begin begin
lxd := true;
fLexToks.Clear; fLexToks.Clear;
lex(lines.Text, fLexToks); lex(lines.Text, fLexToks);
if lexCanCloseBrace then lxd := true;
ccb := lexCanCloseBrace;
if ccb <> braceCloseInvalid then
begin begin
Key := 0; Key := 0;
curlyBraceCloseAndIndent; curlyBraceCloseAndIndent(ccb = braceClosePositive);
lxd := false; lxd := false;
end; end;
end; end;
if (fSmartDdocNewline) then end;
if (fSmartDdocNewline) then
begin
if not lxd then
begin begin
if not lxd then fLexToks.Clear;
begin lex(lines.Text, fLexToks);
fLexToks.Clear; end;
lex(lines.Text, fLexToks); ddc := canInsertLeadingDdocSymbol;
end; if ddc in ['*', '+'] then
ddc := canInsertLeadingDdocSymbol; begin
if ddc in ['*', '+'] then inherited;
begin insertLeadingDDocSymbol(ddc);
inherited; fCanShowHint:=false;
insertLeadingDDocSymbol(ddc); fDDocWin.Hide;
fCanShowHint:=false; exit;
fDDocWin.Hide;
exit;
end;
end; end;
end; end;
end end
@ -3643,8 +3670,10 @@ begin
begin begin
fLexToks.Clear; fLexToks.Clear;
lex(lines.Text, fLexToks); lex(lines.Text, fLexToks);
if lexCanCloseBrace then case lexCanCloseBrace of
curlyBraceCloseAndIndent; braceClosePositive: curlyBraceCloseAndIndent;
braceCloseLessEven: curlyBraceCloseAndIndent(false);
end;
end; end;
end; end;
end; end;