mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2026-01-04 23:10:46 +01:00
SynEdit: Added Copy and paste with ability to keep folded text
git-svn-id: trunk@20587 -
This commit is contained in:
parent
47b8c987cb
commit
9d97223c5c
@ -85,7 +85,11 @@ uses
|
||||
{$ENDIF}
|
||||
SynEditMiscClasses, SynEditTextBuffer, SynEditHighlighter, SynTextDrawer,
|
||||
SynEditLines,
|
||||
LResources;
|
||||
LResources, Clipbrd
|
||||
{$IFDEF SYN_COMPILER_4_UP}
|
||||
, StdActns
|
||||
{$ENDIF}
|
||||
;
|
||||
|
||||
const
|
||||
DIGIT = ['0'..'9'];
|
||||
@ -124,13 +128,6 @@ const
|
||||
// maximum scroll range
|
||||
MAX_SCROLL = 32767;
|
||||
|
||||
SYNEDIT_CLIPBOARD_FORMAT = 'SynEdit Control Block Type';
|
||||
|
||||
{$IFNDEF SYN_LAZARUS}
|
||||
var
|
||||
SynEditClipboardFormat: UINT;
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF SYN_MBCSSUPPORT}
|
||||
{$IFNDEF SYN_COMPILER_4_UP}
|
||||
{Windows.pas in D4}
|
||||
@ -155,8 +152,6 @@ type
|
||||
TSynEditMarkupClass = SynEditMarkup.TSynEditMarkupClass;
|
||||
TSynReplaceAction = (raCancel, raSkip, raReplace, raReplaceAll);
|
||||
|
||||
ESynEditError = class(Exception);
|
||||
|
||||
TSynDropFilesEvent = procedure(Sender: TObject; X, Y: integer; AFiles: TStrings)
|
||||
of object;
|
||||
|
||||
@ -232,7 +227,8 @@ type
|
||||
TSynEditorOption2 = (
|
||||
eoCaretSkipsSelection, // Caret skips selection on VK_LEFT/VK_RIGHT
|
||||
eoAlwaysVisibleCaret, // Move caret to be always visible when scrolling
|
||||
eoEnhanceEndKey // end key jumps to visual/hard line end whichever is nearer
|
||||
eoEnhanceEndKey, // end key jumps to visual/hard line end whichever is nearer
|
||||
eoFoldedCopyPaste // Remember folds in copy/paste operations
|
||||
);
|
||||
TSynEditorOptions2 = set of TSynEditorOption2;
|
||||
{$ENDIF}
|
||||
@ -254,6 +250,7 @@ const
|
||||
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
SYNEDIT_DEFAULT_OPTIONS2 = [
|
||||
eoFoldedCopyPaste
|
||||
];
|
||||
{$ENDIF}
|
||||
|
||||
@ -604,6 +601,7 @@ type
|
||||
function GetViewedTextBuffer: TSynEditStrings; override;
|
||||
function GetTextBuffer: TSynEditStrings; override;
|
||||
procedure SetLines(Value: TStrings); override;
|
||||
procedure ScanFromAfterLock;
|
||||
procedure DecPaintLock;
|
||||
procedure DestroyWnd; override;
|
||||
procedure DragOver(Source: TObject; X, Y: Integer;
|
||||
@ -699,6 +697,7 @@ type
|
||||
property TextView : TSynEditFoldedView read FFoldedLinesView;
|
||||
property TopView: Integer read GetTopView write SetTopView; // TopLine converted into Visible(View) lines
|
||||
{$ENDIF}
|
||||
function PasteFromClipboardEx(ClipHelper: TSynClipboardStream): Boolean;
|
||||
public
|
||||
procedure FindMatchingBracket; virtual;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
@ -732,7 +731,7 @@ type
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
procedure CutToClipboard;
|
||||
destructor Destroy; override;
|
||||
procedure DoCopyToClipboard(const SText: string);
|
||||
procedure DoCopyToClipboard(const SText: string; FoldInfo: String = '');
|
||||
procedure DragDrop(Source: TObject; X, Y: Integer); override;
|
||||
procedure EndUndoBlock(aList: TSynEditUndoList = nil);
|
||||
procedure EndUpdate;
|
||||
@ -1105,25 +1104,12 @@ type
|
||||
property OnStatusChange;
|
||||
end;
|
||||
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
function SynEditClipboardFormat: TClipboardFormat;
|
||||
{$ENDIF}
|
||||
procedure Register;
|
||||
|
||||
implementation
|
||||
|
||||
// { $R SynEdit.res}
|
||||
|
||||
uses
|
||||
{$IFDEF SYN_COMPILER_4_UP}
|
||||
StdActns,
|
||||
{$ENDIF}
|
||||
{$IFNDEF SYN_LAZARUS}
|
||||
// ToDo ShellAPI
|
||||
ShellAPI, SynEditStrConst,
|
||||
{$ENDIF}
|
||||
Clipbrd;
|
||||
|
||||
type
|
||||
|
||||
{ TSynEditUndoCaret }
|
||||
@ -1174,6 +1160,9 @@ type
|
||||
function PerformUndo(Caller: TObject): Boolean; override;
|
||||
end;
|
||||
|
||||
var
|
||||
SynDefaultBeautifier: TSynCustomBeautifier;
|
||||
|
||||
{ TSynEditUndoCaret }
|
||||
|
||||
function TSynEditUndoCaret.IsEqualContent(AnItem: TSynEditUndoItem): Boolean;
|
||||
@ -1268,24 +1257,6 @@ begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
var
|
||||
SynDefaultBeautifier: TSynCustomBeautifier;
|
||||
|
||||
const
|
||||
fSynEditClipboardFormat: TClipboardFormat = 0;
|
||||
|
||||
function SynEditClipboardFormat: TClipboardFormat;
|
||||
begin
|
||||
if fSynEditClipboardFormat=0 then
|
||||
fSynEditClipboardFormat := ClipboardRegisterFormat(SYNEDIT_CLIPBOARD_FORMAT);
|
||||
Result:=fSynEditClipboardFormat;
|
||||
end;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
function Roundoff(X: Extended): Longint;
|
||||
begin
|
||||
if (x >= 0) then begin
|
||||
@ -1327,13 +1298,14 @@ end;
|
||||
|
||||
procedure TCustomSynEdit.AquirePrimarySelection;
|
||||
var
|
||||
FormatList: TClipboardFormat;
|
||||
FormatList: Array [0..1] of TClipboardFormat;
|
||||
begin
|
||||
if (not SelAvail)
|
||||
or (PrimarySelection.OnRequest=@PrimarySelectionRequest) then exit;
|
||||
FormatList:=CF_TEXT;
|
||||
FormatList[0] := CF_TEXT;
|
||||
FormatList[1] := TSynClipboardStream.ClipboardFormatId;
|
||||
try
|
||||
PrimarySelection.SetSupportedFormats(1,@FormatList);
|
||||
PrimarySelection.SetSupportedFormats(2, @FormatList[0]);
|
||||
PrimarySelection.OnRequest:=@PrimarySelectionRequest;
|
||||
except
|
||||
end;
|
||||
@ -1438,111 +1410,49 @@ begin
|
||||
CaretXY := PixelsToRowColumn(Point(X,Y));
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.DoCopyToClipboard(const SText: string);
|
||||
procedure TCustomSynEdit.DoCopyToClipboard(const SText: string; FoldInfo: String = '');
|
||||
var
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
Buf: Pointer;
|
||||
BufSize: integer;
|
||||
{$ELSE}
|
||||
Mem: HGLOBAL;
|
||||
Failed: boolean;
|
||||
{$ENDIF}
|
||||
P: PChar;
|
||||
SLen: integer;
|
||||
ClipHelper: TSynClipboardStream;
|
||||
begin
|
||||
if SText = '' then exit;
|
||||
SLen := Length(SText);
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
Clipboard.Clear;
|
||||
Clipboard.AsText:=SText;
|
||||
if not Clipboard.HasFormat(CF_TEXT) then
|
||||
raise ESynEditError.Create('Clipboard copy operation failed: HasFormat');
|
||||
// Copy it in our custom format so we know what kind of block it is.
|
||||
// That effects how it is pasted in.
|
||||
BufSize:=SLen+SizeOf(TSynSelectionMode)+1;
|
||||
GetMem(Buf,BufSize);
|
||||
if Buf = nil then
|
||||
raise ESynEditError.Create('Clipboard copy operation failed: GetMem');
|
||||
ClipHelper := TSynClipboardStream.Create;
|
||||
try
|
||||
P:=PChar(Buf);
|
||||
// Our format: TSynSelectionMode value followed by text.
|
||||
PSynSelectionMode(P)^ := SelectionMode;
|
||||
inc(P, SizeOf(TSynSelectionMode));
|
||||
if SLen>0 then begin
|
||||
Move(SText[1], P^, SLen);
|
||||
inc(P,SLen);
|
||||
end;
|
||||
P[0]:=#0;
|
||||
if not Clipboard.AddFormat(SynEditClipboardFormat,Buf^,BufSize) then
|
||||
ClipHelper.Text := SText;
|
||||
ClipHelper.SelectionMode := SelectionMode;
|
||||
// Fold
|
||||
if length(FoldInfo) > 0 then
|
||||
ClipHelper.AddTag(synClipTagFold, @FoldInfo[1], length(FoldInfo));
|
||||
if not ClipHelper.WriteToClipboard(Clipboard) then
|
||||
raise ESynEditError.Create('Clipboard copy operation failed: AddFormat');
|
||||
finally
|
||||
FreeMem(Buf);
|
||||
ClipHelper.Free;
|
||||
end;
|
||||
{$ELSE}
|
||||
Failed := true; // assume the worst.
|
||||
// Open and Close are the only TClipboard methods we use because TClipboard
|
||||
// is very hard (impossible) to work with if you want to put more than one
|
||||
// format on it at a time.
|
||||
Clipboard.Open;
|
||||
try
|
||||
// Clear anything already on the clipboard.
|
||||
EmptyClipboard;
|
||||
// Put it on the clipboard as normal text format so it can be pasted into
|
||||
// things like notepad or Delphi.
|
||||
Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, SLen + 1);
|
||||
if Mem <> 0 then begin
|
||||
P := GlobalLock(Mem);
|
||||
try
|
||||
if P <> nil then begin
|
||||
Move(PChar(SText)^, P^, SLen + 1);
|
||||
// Put it on the clipboard in text format
|
||||
Failed := SetClipboardData(CF_TEXT, Mem) = 0;
|
||||
end;
|
||||
finally
|
||||
GlobalUnlock(Mem);
|
||||
end;
|
||||
end;
|
||||
// Don't free Mem! It belongs to the clipboard now, and it will free it
|
||||
// when it is done with it.
|
||||
if not Failed then begin
|
||||
// Copy it in our custom format so we know what kind of block it is.
|
||||
// That effects how it is pasted in.
|
||||
Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, SLen +
|
||||
SizeOf(TSynSelectionMode) + 1);
|
||||
P := GlobalLock(Mem);
|
||||
try
|
||||
if P <> nil then begin
|
||||
// Our format: TSynSelectionMode value followed by text.
|
||||
PSynSelectionMode(P)^ := SelectionMode;
|
||||
inc(P, SizeOf(TSynSelectionMode));
|
||||
Move(PChar(SText)^, P^, SLen + 1);
|
||||
Failed := SetClipboardData(SynEditClipboardFormat, Mem) = 0;
|
||||
end;
|
||||
finally
|
||||
GlobalUnlock(Mem);
|
||||
end;
|
||||
// Don't free Mem! It belongs to the clipboard now, and it will free it
|
||||
// when it is done with it.
|
||||
end;
|
||||
finally
|
||||
Clipboard.Close;
|
||||
if Failed then
|
||||
raise ESynEditError.Create('Clipboard copy operation failed');
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.CopyToClipboard;
|
||||
var
|
||||
FInfo: String;
|
||||
begin
|
||||
if SelAvail then begin
|
||||
DoCopyToClipboard(SelText);
|
||||
if eoFoldedCopyPaste in fOptions2 then
|
||||
FInfo := FFoldedLinesView.GetFoldDescription(
|
||||
FBlockSelection.FirstLineBytePos.Y - 1, FBlockSelection.FirstLineBytePos.X,
|
||||
FBlockSelection.LastLineBytePos.Y - 1, FBlockSelection.LastLineBytePos.X);
|
||||
DoCopyToClipboard(SelText, FInfo);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.CutToClipboard;
|
||||
var
|
||||
FInfo: String;
|
||||
begin
|
||||
if SelAvail then begin
|
||||
DoCopyToClipboard(SelText);
|
||||
if eoFoldedCopyPaste in fOptions2 then
|
||||
FInfo := FFoldedLinesView.GetFoldDescription(
|
||||
FBlockSelection.FirstLineBytePos.Y - 1, FBlockSelection.FirstLineBytePos.X,
|
||||
FBlockSelection.LastLineBytePos.Y - 1, FBlockSelection.LastLineBytePos.X);
|
||||
DoCopyToClipboard(SelText, FInfo);
|
||||
SetSelTextExternal('');
|
||||
end;
|
||||
end;
|
||||
@ -1764,12 +1674,10 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.DecPaintLock;
|
||||
procedure TCustomSynEdit.ScanFromAfterLock;
|
||||
var
|
||||
LastLineChanged: LongInt;
|
||||
begin
|
||||
if (fPaintLock=1) and HandleAllocated then begin
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
if fHighlighterNeedsUpdateStartLine>0 then begin
|
||||
//DebugLn('TCustomSynEdit.DecPaintLock ',dbgs(fHighlighterNeedsUpdateStartLine),'-',dbgs(fHighlighterNeedsUpdateEndLine));
|
||||
if fHighlighterNeedsUpdateStartLine<=FTheLinesView.Count then begin
|
||||
@ -1789,7 +1697,12 @@ begin
|
||||
fHighlighterNeedsUpdateStartLine:=0;
|
||||
fHighlighterNeedsUpdateEndLine:=0;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.DecPaintLock;
|
||||
begin
|
||||
if (fPaintLock=1) and HandleAllocated then begin
|
||||
ScanFromAfterLock;
|
||||
end;
|
||||
FCaret.Unlock; // Maybe after FFoldedLinesView;
|
||||
FTrimmedLinesView.UnLock; // Must be unlocked after caret
|
||||
@ -2380,10 +2293,10 @@ var
|
||||
end;
|
||||
|
||||
var
|
||||
PrimarySelText: String;
|
||||
ACommand: TSynEditorMouseCommand;
|
||||
Handled: Boolean;
|
||||
AnAction: TSynEditMouseAction;
|
||||
ClipHelper: TSynClipboardStream;
|
||||
begin
|
||||
AnAction := nil;
|
||||
Result := False;
|
||||
@ -2459,15 +2372,19 @@ begin
|
||||
end;
|
||||
emcPasteSelection:
|
||||
begin
|
||||
MoveCaret;
|
||||
PrimarySelText := PrimarySelection.AsText;
|
||||
if ((PrimarySelText<>'') or SelAvail) then begin
|
||||
FBlockSelection.StartLineBytePos := AnInfo.NewCaret.LineBytePos;
|
||||
FBlockSelection.EndLineBytePos := AnInfo.NewCaret.LineBytePos;
|
||||
SelText:=PrimarySelText;
|
||||
end
|
||||
else
|
||||
Result :=False;
|
||||
ClipHelper := TSynClipboardStream.Create;
|
||||
try
|
||||
ClipHelper.ReadFromClipboard(PrimarySelection);
|
||||
if ClipHelper.TextP <> nil then begin
|
||||
MoveCaret;
|
||||
FBlockSelection.StartLineBytePos := FCaret.LineBytePos;
|
||||
Result := PasteFromClipboardEx(ClipHelper);
|
||||
end
|
||||
else
|
||||
Result := False;
|
||||
finally
|
||||
ClipHelper.Free;
|
||||
end;
|
||||
end;
|
||||
emcMouseLink:
|
||||
begin
|
||||
@ -3706,63 +3623,45 @@ end;
|
||||
|
||||
procedure TCustomSynEdit.PasteFromClipboard;
|
||||
var
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
MemStream: TMemoryStream;
|
||||
Buf: Pointer;
|
||||
BufSize: integer;
|
||||
{$ELSE}
|
||||
Mem: HGLOBAL;
|
||||
{$ENDIF}
|
||||
PasteMode: TSynSelectionMode;
|
||||
P: PChar;
|
||||
ClipHelper: TSynClipboardStream;
|
||||
begin
|
||||
BeginUndoBlock; //mh 2000-11-20
|
||||
ClipHelper := TSynClipboardStream.Create;
|
||||
try
|
||||
// Check for our special format first.
|
||||
if Clipboard.HasFormat(SynEditClipboardFormat) then begin
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
MemStream:=TMemoryStream.Create;
|
||||
Buf:=nil;
|
||||
try
|
||||
Clipboard.GetFormat(SynEditClipboardFormat,MemStream);
|
||||
BufSize:=integer(MemStream.Size);
|
||||
if BufSize>=SizeOf(TSynSelectionMode)+1 then begin
|
||||
GetMem(Buf,BufSize+1);
|
||||
MemStream.Position:=0;
|
||||
MemStream.Read(Buf^,BufSize);
|
||||
P:=PChar(Buf);
|
||||
P[BufSize]:=#0;
|
||||
{$ELSE}
|
||||
Clipboard.Open;
|
||||
try
|
||||
Mem := Clipboard.GetAsHandle(SynEditClipboardFormat);
|
||||
P := GlobalLock(Mem);
|
||||
if P <> nil then begin
|
||||
{$ENDIF}
|
||||
// Our format: SelectionMode value followed by text.
|
||||
// See CopyToClipboard
|
||||
PasteMode := PSynSelectionMode(P)^;
|
||||
inc(P, SizeOf(TSynSelectionMode));
|
||||
SetSelTextPrimitive(PasteMode, P, true);
|
||||
end else
|
||||
raise ESynEditError.Create('Clipboard paste operation failed.');
|
||||
finally
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
MemStream.Free;
|
||||
if Buf<>nil then FreeMem(Buf);
|
||||
{$ELSE}
|
||||
Clipboard.Close;
|
||||
{$ENDIF}
|
||||
ClipHelper.ReadFromClipboard(Clipboard);
|
||||
PasteFromClipboardEx(ClipHelper);
|
||||
finally
|
||||
ClipHelper.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomSynEdit.PasteFromClipboardEx(ClipHelper: TSynClipboardStream) : Boolean;
|
||||
var
|
||||
PTxt: PChar;
|
||||
InsStart: TPoint;
|
||||
begin
|
||||
Result := False;
|
||||
BeginUndoBlock;
|
||||
try
|
||||
if ClipHelper.TextP = nil then
|
||||
exit;
|
||||
|
||||
Result := True;
|
||||
InsStart := FBlockSelection.StartLineBytePos;
|
||||
SetSelTextPrimitive(ClipHelper.SelectionMode, ClipHelper.TextP, true);
|
||||
|
||||
if eoFoldedCopyPaste in fOptions2 then begin
|
||||
PTxt := ClipHelper.GetTagPointer(synClipTagFold);
|
||||
if PTxt <> nil then begin
|
||||
ScanFromAfterLock;
|
||||
FFoldedLinesView.ApplyFoldDescription(InsStart.Y -1, InsStart.X,
|
||||
FBlockSelection.StartLinePos-1, FBlockSelection.StartBytePos,
|
||||
PTxt, ClipHelper.GetTagLen(synClipTagFold));
|
||||
end;
|
||||
// If our special format isn't there, check for regular text format.
|
||||
end else if Clipboard.HasFormat(CF_TEXT) then begin
|
||||
// Normal text is much easier...
|
||||
SelText := Clipboard.AsText;
|
||||
end;
|
||||
finally
|
||||
EndUndoBlock; //mh 2000-11-20
|
||||
EndUndoBlock;
|
||||
EnsureCursorPosVisible;
|
||||
end;
|
||||
EnsureCursorPosVisible;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.SelectAll;
|
||||
@ -4838,7 +4737,7 @@ end;
|
||||
function TCustomSynEdit.GetCanPaste:Boolean;
|
||||
begin
|
||||
Result := Clipboard.HasFormat(CF_TEXT)
|
||||
or Clipboard.HasFormat(SynEditClipboardFormat)
|
||||
or Clipboard.HasFormat(TSynClipboardStream.ClipboardFormatId)
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.InsertBlock(BB: TPoint; ChangeStr: PChar);
|
||||
@ -5198,6 +5097,8 @@ var
|
||||
BB, BE: TPoint;
|
||||
DragDropText: string;
|
||||
Adjust: integer;
|
||||
FoldInfo: String;
|
||||
BlockSel: TSynEditSelection;
|
||||
begin
|
||||
if not ReadOnly and (Source is TCustomSynEdit)
|
||||
and TCustomSynEdit(Source).SelAvail
|
||||
@ -5226,6 +5127,11 @@ begin
|
||||
BeginUndoBlock; //mh 2000-11-20
|
||||
try
|
||||
DragDropText := TCustomSynEdit(Source).SelText;
|
||||
BlockSel := TCustomSynEdit(Source).FBlockSelection;
|
||||
if eoFoldedCopyPaste in fOptions2 then
|
||||
FoldInfo := TCustomSynEdit(Source).FFoldedLinesView.GetFoldDescription(
|
||||
BlockSel.FirstLineBytePos.Y - 1, BlockSel.FirstLineBytePos.X,
|
||||
BlockSel.LastLineBytePos.Y - 1, BlockSel.LastLineBytePos.X);
|
||||
// delete the selected text if necessary
|
||||
if DropMove then begin
|
||||
if Source <> Self then
|
||||
@ -5250,10 +5156,13 @@ begin
|
||||
try
|
||||
CaretXY := NewCaret;
|
||||
BlockBegin := NewCaret;
|
||||
if Source = Self then
|
||||
SetSelTextPrimitive(smNormal, PChar(DragDropText), true)
|
||||
else
|
||||
SetSelTextPrimitive(smNormal, PChar(DragDropText), true);
|
||||
SetSelTextPrimitive(smNormal, PChar(DragDropText), true);
|
||||
if FoldInfo <> '' then begin
|
||||
ScanFromAfterLock;
|
||||
FFoldedLinesView.ApplyFoldDescription(NewCaret.Y -1, NewCaret.X,
|
||||
FBlockSelection.StartLinePos-1, FBlockSelection.StartBytePos,
|
||||
PChar(FoldInfo), length(FoldInfo));
|
||||
end;
|
||||
finally
|
||||
FCaret.DecForcePastEOL;
|
||||
end;
|
||||
@ -8876,12 +8785,36 @@ end;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
procedure TCustomSynEdit.PrimarySelectionRequest(
|
||||
const RequestedFormatID: TClipboardFormat; Data: TStream);
|
||||
var s: string;
|
||||
var
|
||||
s: string;
|
||||
ClipHelper: TSynClipboardStream;
|
||||
begin
|
||||
if (not SelAvail) or (RequestedFormatID<>CF_TEXT) then exit;
|
||||
if (not SelAvail) then exit;
|
||||
s:=SelText;
|
||||
if s<>'' then
|
||||
if s = '' then
|
||||
exit;
|
||||
if RequestedFormatID = CF_TEXT then begin
|
||||
Data.Write(s[1],length(s));
|
||||
end
|
||||
else
|
||||
if RequestedFormatID = TSynClipboardStream.ClipboardFormatId then begin
|
||||
ClipHelper := TSynClipboardStream.Create;
|
||||
try
|
||||
ClipHelper.SelectionMode := SelectionMode;
|
||||
// InternalText, so we don't need a 2nd call for CF_TEXT
|
||||
ClipHelper.InternalText := s;
|
||||
// Fold
|
||||
if eoFoldedCopyPaste in fOptions2 then
|
||||
s := FFoldedLinesView.GetFoldDescription(
|
||||
FBlockSelection.FirstLineBytePos.Y - 1, FBlockSelection.FirstLineBytePos.X,
|
||||
FBlockSelection.LastLineBytePos.Y - 1, FBlockSelection.LastLineBytePos.X);
|
||||
if length(s) > 0 then
|
||||
ClipHelper.AddTag(synClipTagFold, @s[1], length(s));
|
||||
Data.Write(ClipHelper.Memory^, ClipHelper.Size);
|
||||
finally
|
||||
ClipHelper.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
@ -8942,9 +8875,6 @@ begin
|
||||
end;
|
||||
|
||||
initialization
|
||||
{$IFNDEF SYN_LAZARUS}
|
||||
SynEditClipboardFormat := RegisterClipboardFormat(SYNEDIT_CLIPBOARD_FORMAT);
|
||||
{$ENDIF}
|
||||
SynDefaultBeautifier := TSynBeautifier.Create(Application);
|
||||
Register;
|
||||
|
||||
|
||||
@ -289,6 +289,14 @@ type
|
||||
Previous: Boolean = False): Integer;
|
||||
|
||||
procedure CollapseDefaultFolds;
|
||||
// Load/Save folds to string
|
||||
// AStartIndex, AEndIndex: (0 based) First/last line (EndIndex = -1 = open end)
|
||||
// AStartCol, AEndCol: (1 based) Logical text pos in Line. (AEndCol = -1 = full line)
|
||||
function GetFoldDescription(AStartIndex, AStartCol, AEndIndex,
|
||||
AEndCol: Integer) :String;
|
||||
procedure ApplyFoldDescription(AStartIndex, AStartCol, AEndIndex,
|
||||
AEndCol: Integer; FoldDesc: PChar;
|
||||
FoldDescLen: Integer);
|
||||
|
||||
procedure UnfoldAll;
|
||||
procedure FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
|
||||
@ -315,6 +323,12 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
type
|
||||
TFoldExportEntry = Record
|
||||
Line, LogX, LogX2, ELine, ELogX, ELogX2, FType: Integer;
|
||||
end;
|
||||
|
||||
|
||||
{ TSynTextFoldAVLNodeData }
|
||||
|
||||
function TSynTextFoldAVLNodeData.TreeDepth : integer;
|
||||
@ -1850,12 +1864,12 @@ begin
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
// AStartIndex is 0-based
|
||||
// FoldTree is 1-based AND first line remains visble
|
||||
c := hl.FoldNodeInfoCount[AStartIndex];
|
||||
c := hl.FoldNodeInfoCount[AStartIndex, []];
|
||||
if c = 0 then
|
||||
exit(-1);
|
||||
i := 0;
|
||||
while i < c do begin
|
||||
nd := hl.FoldNodeInfo[aStartIndex, i];
|
||||
nd := hl.FoldNodeInfo[aStartIndex, i, []];
|
||||
if sfaOpen in nd.FoldAction then begin
|
||||
if (nd.LogXStart >= LogX) then begin
|
||||
dec(i);
|
||||
@ -1887,10 +1901,10 @@ begin
|
||||
// Currently PascalHl Type 2 = Region
|
||||
c := hl.FoldOpenCount(i, 2);
|
||||
if c > 0 then begin
|
||||
c := hl.FoldNodeInfoCount[i];
|
||||
c := hl.FoldNodeInfoCount[i, []];
|
||||
j := 0;
|
||||
while j < c do begin
|
||||
nd := hl.FoldNodeInfo[i, j];
|
||||
nd := hl.FoldNodeInfo[i, j, []];
|
||||
if (sfaDefaultCollapsed in nd.FoldAction) and
|
||||
(not IsFoldedAtTextIndex(i, j))
|
||||
then
|
||||
@ -1902,6 +1916,149 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynEditFoldedView.GetFoldDescription(AStartIndex, AStartCol, AEndIndex,
|
||||
AEndCol: Integer): String;
|
||||
var
|
||||
node: TSynTextFoldAVLNode;
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
ndinfo, ndinfo2: TSynFoldNodeInfo;
|
||||
EndIndex: Integer;
|
||||
c, i, x: Integer;
|
||||
entry: TFoldExportEntry;
|
||||
begin
|
||||
Result := '';
|
||||
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
|
||||
then exit;
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
|
||||
node := fFoldTree.FindFoldForLine(AStartIndex + 1, True);
|
||||
if not node.IsInFold then
|
||||
exit;
|
||||
|
||||
// Node.startline is first hidden line
|
||||
while (node.StartLine = AStartIndex + 2) and (AStartCol > 1) do begin
|
||||
ndinfo := hl.FoldNodeInfo[aStartIndex, node.FoldIndex, [sfaOpen]];
|
||||
if (sfaInvalid in ndinfo.FoldAction) or (ndinfo.LogXStart >= AStartIndex)
|
||||
then break;
|
||||
node := node.Next;
|
||||
if not node.IsInFold then
|
||||
exit;
|
||||
end;
|
||||
|
||||
while node.IsInFold and
|
||||
((AEndIndex < 0) or (node.StartLine-2 <= AEndIndex)) do
|
||||
begin
|
||||
if (node.StartLine > AStartIndex + 2) then
|
||||
AStartCol := 0;
|
||||
|
||||
EndIndex := node.StartLine-2 + node.LineCount;
|
||||
if (AEndIndex >= 0) and (EndIndex > AEndIndex) then begin
|
||||
node := node.Next;
|
||||
continue;
|
||||
end;
|
||||
|
||||
ndinfo := hl.FoldNodeInfo[node.StartLine-2, node.FoldIndex, [sfaOpen]];
|
||||
c := hl.FoldNodeInfoCount[EndIndex, [sfaClose]];
|
||||
i := 0;
|
||||
while i < c do begin
|
||||
ndinfo2 := hl.FoldNodeInfo[EndIndex, i, [sfaClose]];
|
||||
if ndinfo2.FoldLvlStart = ndinfo.FoldLvlEnd then break;
|
||||
inc(i);
|
||||
end;
|
||||
if (i = c) or (sfaInvalid in ndinfo2.FoldAction) or
|
||||
((AEndIndex = EndIndex) and (AEndCol > 0) and (ndinfo2.LogXEnd > AEndCol))
|
||||
then begin
|
||||
node := node.Next;
|
||||
continue;
|
||||
end;
|
||||
|
||||
// Add the fold
|
||||
x := ndinfo.LogXStart;
|
||||
if AStartCol > 0 then
|
||||
x := x - AStartCol + 1;
|
||||
|
||||
with entry do begin
|
||||
LogX := x;
|
||||
LogX2 := ndinfo.LogXEnd - ndinfo.LogXStart + x;
|
||||
Line := node.StartLine - 2 - AStartIndex;
|
||||
ELogX := ndinfo2.LogXStart;
|
||||
ELogX2 := ndinfo2.LogXEnd;
|
||||
ELine := node.StartLine - 2 - AStartIndex + node.LineCount;
|
||||
FType := PtrUInt(ndinfo.FoldType);
|
||||
end;
|
||||
i := length(Result);
|
||||
SetLength(Result, i + SizeOf(TFoldExportEntry));
|
||||
System.Move(entry, Result[i+1], sizeof(TFoldExportEntry));
|
||||
|
||||
node := node.Next;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditFoldedView.ApplyFoldDescription(AStartIndex, AStartCol, AEndIndex,
|
||||
AEndCol: Integer; FoldDesc: PChar; FoldDescLen: Integer);
|
||||
var
|
||||
c, i, j: Integer;
|
||||
Line, Line2: Integer;
|
||||
entry: TFoldExportEntry;
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
ndinfo, ndinfo2: TSynFoldNodeInfo;
|
||||
FoldDescEnd: PChar;
|
||||
begin
|
||||
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
|
||||
then exit;
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
|
||||
FoldDescEnd := FoldDesc + FoldDescLen;
|
||||
if AStartCol > 0 then
|
||||
dec(AStartCol);
|
||||
while true do begin
|
||||
if FoldDesc + sizeof(TFoldExportEntry) > FoldDescEnd then
|
||||
exit;
|
||||
System.Move(FoldDesc^, entry, sizeof(TFoldExportEntry));
|
||||
inc(FoldDesc, sizeof(TFoldExportEntry));
|
||||
|
||||
if entry.Line > 0 then
|
||||
AStartCol := 0;
|
||||
|
||||
Line := AStartIndex + entry.Line;
|
||||
if Line >= FLines.Count then
|
||||
continue;
|
||||
c := hl.FoldNodeInfoCount[Line, [sfaOpen]];
|
||||
j := 0;
|
||||
while j < c do begin
|
||||
ndinfo := hl.FoldNodeInfo[Line, j, [sfaOpen]];
|
||||
if ndinfo.LogXStart >= entry.LogX + AStartCol then
|
||||
break;
|
||||
inc(j);
|
||||
end;
|
||||
if (sfaInvalid in ndinfo.FoldAction) or
|
||||
(ndinfo.LogXStart <> entry.LogX + AStartCol) or
|
||||
(ndinfo.LogXEnd <> entry.LogX2 + AStartCol) or
|
||||
//(ndinfo.FoldType <> entry.FType) or
|
||||
(entry.ELine - entry.Line <> LengthForFoldAtTextIndex(Line, j))
|
||||
then
|
||||
continue;
|
||||
|
||||
Line2 := AStartIndex + entry.ELine;
|
||||
if Line2 >= FLines.Count then
|
||||
continue;
|
||||
c := hl.FoldNodeInfoCount[Line2, [sfaClose]];
|
||||
i := 0;
|
||||
while i < c do begin
|
||||
ndinfo2 := hl.FoldNodeInfo[Line2, i, [sfaClose]];
|
||||
if ndinfo2.FoldLvlStart = ndinfo.FoldLvlEnd then break;
|
||||
inc(i);
|
||||
end;
|
||||
if (sfaInvalid in ndinfo2.FoldAction) or
|
||||
(ndinfo2.LogXStart <> entry.ELogX) or
|
||||
(ndinfo2.LogXEnd <> entry.ELogX2)
|
||||
then
|
||||
continue;
|
||||
|
||||
FoldAtTextIndex(Line, j);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditFoldedView.FoldAtTextIndex(AStartIndex : Integer;
|
||||
ColIndex : Integer = -1; ColCount : Integer = 1; Skip: Boolean = False);
|
||||
var
|
||||
@ -2281,8 +2438,8 @@ begin
|
||||
(hl.FoldCloseCount(aStartIndex) > 0) then begin
|
||||
o := hl.FoldOpenCount(AStartIndex);
|
||||
n := o;
|
||||
for i := hl.FoldNodeInfoCount[aStartIndex] - 1 downto 0 do begin
|
||||
nd := hl.FoldNodeInfo[aStartIndex, i];
|
||||
for i := hl.FoldNodeInfoCount[aStartIndex, []] - 1 downto 0 do begin
|
||||
nd := hl.FoldNodeInfo[aStartIndex, i, []];
|
||||
if not(sfaFold in nd.FoldAction) then
|
||||
continue;
|
||||
t := nd.FoldGroup;
|
||||
|
||||
@ -127,8 +127,8 @@ type
|
||||
function GetFoldConfigCount: Integer; virtual;
|
||||
procedure SetFoldConfig(Index: Integer; const AValue: Boolean); virtual;
|
||||
|
||||
function GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; virtual;
|
||||
function GetFoldNodeInfoCount(Line: Integer): Integer; virtual;
|
||||
function GetFoldNodeInfo(Line, Index: Integer; Filter: TSynFoldActions): TSynFoldNodeInfo; virtual;
|
||||
function GetFoldNodeInfoCount(Line: Integer; Filter: TSynFoldActions): Integer; virtual;
|
||||
property CodeFoldRange: TSynCustomHighlighterRange read FCodeFoldRange;
|
||||
function GetRangeClass: TSynCustomHighlighterRangeClass; virtual;
|
||||
function TopCodeFoldBlockType(DownIndex: Integer = 0): Pointer;
|
||||
@ -161,8 +161,8 @@ type
|
||||
function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; virtual;
|
||||
|
||||
// All fold-nodes
|
||||
property FoldNodeInfo[Line, Index: Integer]: TSynFoldNodeInfo read GetFoldNodeInfo;
|
||||
property FoldNodeInfoCount[Line: Integer]: Integer read GetFoldNodeInfoCount;
|
||||
property FoldNodeInfo[Line, Index: Integer; Filter: TSynFoldActions]: TSynFoldNodeInfo read GetFoldNodeInfo;
|
||||
property FoldNodeInfoCount[Line: Integer; Filter: TSynFoldActions]: Integer read GetFoldNodeInfoCount;
|
||||
|
||||
procedure SetRange(Value: Pointer); override;
|
||||
procedure ResetRange; override;
|
||||
@ -337,7 +337,8 @@ begin
|
||||
result := 0;
|
||||
end;
|
||||
|
||||
function TSynCustomFoldHighlighter.GetFoldNodeInfoCount(Line: Integer): Integer;
|
||||
function TSynCustomFoldHighlighter.GetFoldNodeInfoCount(Line: Integer;
|
||||
Filter: TSynFoldActions): Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
@ -356,7 +357,8 @@ procedure TSynCustomFoldHighlighter.SetFoldConfig(Index: Integer; const AValue:
|
||||
begin
|
||||
end;
|
||||
|
||||
function TSynCustomFoldHighlighter.GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo;
|
||||
function TSynCustomFoldHighlighter.GetFoldNodeInfo(Line, Index: Integer;
|
||||
Filter: TSynFoldActions): TSynFoldNodeInfo;
|
||||
begin
|
||||
Result.FoldAction := [sfaInvalid];
|
||||
end;
|
||||
|
||||
@ -117,7 +117,7 @@ var
|
||||
begin
|
||||
repeat
|
||||
inc(NIndex);
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex];
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex, []];
|
||||
until (sfaInvalid in Result.FoldAction) or
|
||||
(Result.FoldLvlEnd <= StartNode.FoldLvlStart);
|
||||
if not (sfaInvalid in Result.FoldAction) then
|
||||
@ -133,7 +133,7 @@ var
|
||||
NIndex := -1;
|
||||
repeat
|
||||
inc(NIndex);
|
||||
Result:= HL.FoldNodeInfo[YIndex, NIndex];
|
||||
Result:= HL.FoldNodeInfo[YIndex, NIndex, []];
|
||||
until (sfaInvalid in Result.FoldAction) or
|
||||
(Result.FoldLvlEnd <= StartNode.FoldLvlStart);
|
||||
if (Result.LogXEnd = 0) then
|
||||
@ -145,7 +145,7 @@ var
|
||||
begin
|
||||
repeat
|
||||
dec(NIndex);
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex];
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex, []];
|
||||
until (sfaInvalid in Result.FoldAction) or
|
||||
(Result.FoldLvlStart <= EndNode.FoldLvlEnd);
|
||||
if not(sfaInvalid in Result.FoldAction) then
|
||||
@ -156,10 +156,10 @@ var
|
||||
dec(YIndex);
|
||||
if YIndex < 0 then
|
||||
exit;
|
||||
NIndex := HL.FoldNodeInfoCount[YIndex];
|
||||
NIndex := HL.FoldNodeInfoCount[YIndex, []];
|
||||
repeat
|
||||
dec(NIndex);
|
||||
Result:= HL.FoldNodeInfo[YIndex, NIndex];
|
||||
Result:= HL.FoldNodeInfo[YIndex, NIndex, []];
|
||||
until (sfaInvalid in Result.FoldAction) or
|
||||
(Result.FoldLvlStart <= EndNode.FoldLvlEnd);
|
||||
end;
|
||||
@ -172,7 +172,7 @@ var
|
||||
i := NIndex;
|
||||
repeat
|
||||
dec(NIndex);
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex];
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex, []];
|
||||
if (sfaMarkup in Result.FoldAction) and
|
||||
(Result.LogXStart = OrigNode.LogXStart) and (Result.LogXEnd > 0)
|
||||
then
|
||||
@ -181,7 +181,7 @@ var
|
||||
NIndex := i;
|
||||
repeat
|
||||
inc(NIndex);
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex];
|
||||
Result := HL.FoldNodeInfo[YIndex, NIndex, []];
|
||||
if (sfaMarkup in Result.FoldAction) and
|
||||
(Result.LogXStart = OrigNode.LogXStart) and (Result.LogXEnd > 0)
|
||||
then
|
||||
@ -212,14 +212,14 @@ begin
|
||||
HL.CurrentLines := Lines;
|
||||
i := 0;
|
||||
repeat
|
||||
Node1 := HL.FoldNodeInfo[y, i];
|
||||
Node1 := HL.FoldNodeInfo[y, i, []];
|
||||
inc(i);
|
||||
until (sfaInvalid in Node1.FoldAction) or
|
||||
((Node1.LogXEnd >= LogCaretXY.X - 1) and (Node1.LogXEnd > 0));
|
||||
while not(Node1.FoldAction * [sfaInvalid, sfaMarkup] <> [])
|
||||
and (Node1.LogXStart <= LogCaretXY.X - 1) do
|
||||
begin
|
||||
Node1 := HL.FoldNodeInfo[y, i];
|
||||
Node1 := HL.FoldNodeInfo[y, i, []];
|
||||
inc(i);
|
||||
end;
|
||||
if (Node1.LogXStart > LogCaretXY.X - 1) or not(sfaMarkup in Node1.FoldAction) then
|
||||
|
||||
@ -47,8 +47,8 @@ uses
|
||||
{$ELSE}
|
||||
Windows,
|
||||
{$ENDIF}
|
||||
Classes, Graphics, Controls, SysUtils, SynEditMiscProcs, SynEditTypes,
|
||||
SynEditTextBase;
|
||||
Classes, Graphics, Controls, SysUtils, Clipbrd,
|
||||
SynEditMiscProcs, SynEditTypes, SynEditTextBase;
|
||||
|
||||
type
|
||||
|
||||
@ -261,6 +261,58 @@ type
|
||||
property Options: TSynSearchOptions write SetOptions;
|
||||
end;
|
||||
|
||||
TSynClipboardStreamTag = type word;
|
||||
|
||||
{ TSynClipboardStream }
|
||||
|
||||
TSynClipboardStream = class
|
||||
private
|
||||
FMemStream: TMemoryStream;
|
||||
FText: String;
|
||||
FTextP: PChar;
|
||||
FIsPlainText: Boolean;
|
||||
|
||||
function GetMemory: Pointer;
|
||||
function GetSize: LongInt;
|
||||
function GetSelectionMode: TSynSelectionMode;
|
||||
procedure SetSelectionMode(const AValue: TSynSelectionMode);
|
||||
procedure SetInternalText(const AValue: String);
|
||||
procedure SetText(const AValue: String);
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
class function ClipboardFormatId: TClipboardFormat;
|
||||
|
||||
function CanReadFromClipboard(AClipboard: TClipboard): Boolean;
|
||||
function ReadFromClipboard(AClipboard: TClipboard): Boolean;
|
||||
function WriteToClipboard(AClipboard: TClipboard): Boolean;
|
||||
|
||||
procedure Clear;
|
||||
|
||||
function HasTag(ATag: TSynClipboardStreamTag): Boolean;
|
||||
function GetTagPointer(ATag: TSynClipboardStreamTag): Pointer;
|
||||
function GetTagLen(ATag: TSynClipboardStreamTag): Integer;
|
||||
// No check for duplicates
|
||||
Procedure AddTag(ATag: TSynClipboardStreamTag; Location: Pointer; Len: Integer);
|
||||
|
||||
// Currently Each method (or each method of a pair) must be assigned only ONCE
|
||||
property TextP: PChar read FTextP;
|
||||
property Text: String write SetText;
|
||||
property InternalText: String write SetInternalText;
|
||||
|
||||
property SelectionMode: TSynSelectionMode read GetSelectionMode write SetSelectionMode;
|
||||
|
||||
property Memory: Pointer read GetMemory;
|
||||
property Size: LongInt read GetSize;
|
||||
end;
|
||||
|
||||
const
|
||||
synClipTagText = TSynClipboardStreamTag(1);
|
||||
synClipTagExtText = TSynClipboardStreamTag(2);
|
||||
synClipTagMode = TSynClipboardStreamTag(3);
|
||||
synClipTagFold = TSynClipboardStreamTag(4);
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{ TSynSelectedColor }
|
||||
@ -746,5 +798,181 @@ begin
|
||||
FOwner.Delete(FOwner.IndexOf(self));
|
||||
end;
|
||||
|
||||
{ TSynClipboardStream }
|
||||
|
||||
function TSynClipboardStream.GetMemory: Pointer;
|
||||
begin
|
||||
Result := FMemStream.Memory;
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.GetSize: LongInt;
|
||||
begin
|
||||
Result := FMemStream.Size;
|
||||
end;
|
||||
|
||||
procedure TSynClipboardStream.SetInternalText(const AValue: String);
|
||||
begin
|
||||
FIsPlainText := False;
|
||||
// Text, if we don't need CF_TEXT // Must include a zero byte
|
||||
AddTag(synClipTagText, @AValue[1], length(AValue) + 1);
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.GetSelectionMode: TSynSelectionMode;
|
||||
var
|
||||
PasteMode: ^TSynSelectionMode;
|
||||
begin
|
||||
PasteMode := GetTagPointer(synClipTagMode);
|
||||
if PasteMode = nil then
|
||||
Result := smNormal
|
||||
else
|
||||
Result := PasteMode^;
|
||||
end;
|
||||
|
||||
procedure TSynClipboardStream.SetSelectionMode(const AValue: TSynSelectionMode);
|
||||
begin
|
||||
AddTag(synClipTagMode, @AValue, SizeOf(TSynSelectionMode));
|
||||
end;
|
||||
|
||||
procedure TSynClipboardStream.SetText(const AValue: String);
|
||||
var
|
||||
SLen: Integer;
|
||||
begin
|
||||
FIsPlainText := True;
|
||||
FText := AValue;
|
||||
SLen := length(FText);
|
||||
AddTag(synClipTagExtText, @SLen, SizeOf(Integer));
|
||||
end;
|
||||
|
||||
constructor TSynClipboardStream.Create;
|
||||
begin
|
||||
FMemStream := TMemoryStream.Create;
|
||||
end;
|
||||
|
||||
destructor TSynClipboardStream.Destroy;
|
||||
begin
|
||||
FreeAndNil(FMemStream);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
class function TSynClipboardStream.ClipboardFormatId: TClipboardFormat;
|
||||
const
|
||||
SYNEDIT_CLIPBOARD_FORMAT_TAGGED = 'Application/X-Laz-SynEdit-Tagged';
|
||||
Format: UINT = 0;
|
||||
begin
|
||||
if Format = 0 then
|
||||
Format := ClipboardRegisterFormat(SYNEDIT_CLIPBOARD_FORMAT_TAGGED);
|
||||
Result := Format;
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.CanReadFromClipboard(AClipboard: TClipboard): Boolean;
|
||||
begin
|
||||
Result := AClipboard.HasFormat(ClipboardFormatId);
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.ReadFromClipboard(AClipboard: TClipboard): Boolean;
|
||||
var
|
||||
ip: PInteger;
|
||||
len: LongInt;
|
||||
begin
|
||||
Clear;
|
||||
Result := AClipboard.GetFormat(ClipboardFormatId, FMemStream);
|
||||
// Check for embedded text
|
||||
FTextP := GetTagPointer(synClipTagText);
|
||||
if FTextP <> nil then begin
|
||||
len := GetTagLen(synClipTagText);
|
||||
if len > 0 then
|
||||
(FTextP + len - 1)^ := #0
|
||||
else
|
||||
FTextP := nil;
|
||||
end;
|
||||
// Normal text
|
||||
if (FTextP = nil) and AClipboard.HasFormat(CF_TEXT) then begin
|
||||
FText:= AClipboard.AsText;
|
||||
if FText <> '' then begin
|
||||
FTextP := @FText[1];
|
||||
ip := GetTagPointer(synClipTagExtText);
|
||||
if (length(FText) = 0) or (ip = nil) or (length(FText) <> ip^) then
|
||||
FIsPlainText := True;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.WriteToClipboard(AClipboard: TClipboard): Boolean;
|
||||
begin
|
||||
if FIsPlainText and (FText <> '') then begin
|
||||
Clipboard.AsText:= FText;
|
||||
if not Clipboard.HasFormat(CF_TEXT) then
|
||||
raise ESynEditError.Create('Clipboard copy operation failed: HasFormat');
|
||||
end;
|
||||
Result := AClipboard.AddFormat(ClipboardFormatId, FMemStream.Memory^, FMemStream.Size);
|
||||
end;
|
||||
|
||||
procedure TSynClipboardStream.Clear;
|
||||
begin
|
||||
FMemStream.Clear;
|
||||
FIsPlainText := False;
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.HasTag(ATag: TSynClipboardStreamTag): Boolean;
|
||||
begin
|
||||
Result := GetTagPointer(ATag) <> nil;
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.GetTagPointer(ATag: TSynClipboardStreamTag): Pointer;
|
||||
var
|
||||
ctag, mend: Pointer;
|
||||
begin
|
||||
Result := nil;
|
||||
if FIsPlainText then
|
||||
exit;
|
||||
ctag := FMemStream.Memory;
|
||||
mend := ctag + FMemStream.Size;
|
||||
while (result = nil) and
|
||||
(ctag + SizeOf(TSynClipboardStreamTag) + SizeOf(Integer) <= mend) do
|
||||
begin
|
||||
if TSynClipboardStreamTag(ctag^) = ATag then begin
|
||||
Result := ctag + SizeOf(TSynClipboardStreamTag) + SizeOf(Integer)
|
||||
end else begin
|
||||
inc(ctag, SizeOf(TSynClipboardStreamTag));
|
||||
inc(ctag, PInteger(ctag)^);
|
||||
inc(ctag, SizeOf(Integer));
|
||||
end;
|
||||
end;
|
||||
if (Result <> nil) and
|
||||
(ctag + Integer((ctag + SizeOf(TSynClipboardStreamTag))^) > mend) then
|
||||
begin
|
||||
Result := nil;
|
||||
raise ESynEditError.Create('Clipboard read operation failed, data corrupt');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynClipboardStream.GetTagLen(ATag: TSynClipboardStreamTag): Integer;
|
||||
var
|
||||
p: PInteger;
|
||||
begin
|
||||
Result := 0;
|
||||
p := GetTagPointer(ATag);
|
||||
if p = nil then
|
||||
exit;
|
||||
dec(p, 1);
|
||||
Result := p^;
|
||||
end;
|
||||
|
||||
procedure TSynClipboardStream.AddTag(ATag: TSynClipboardStreamTag; Location: Pointer;
|
||||
Len: Integer);
|
||||
var
|
||||
msize: Int64;
|
||||
mpos: Pointer;
|
||||
begin
|
||||
msize := FMemStream.Size;
|
||||
FMemStream.Size := msize + Len + SizeOf(TSynClipboardStreamTag) + SizeOf(Integer);
|
||||
mpos := FMemStream.Memory + msize;
|
||||
TSynClipboardStreamTag(mpos^) := ATag;
|
||||
inc(mpos, SizeOf(TSynClipboardStreamTag));
|
||||
Integer(mpos^) := Len;
|
||||
inc(mpos, SizeOf(Integer));
|
||||
System.Move(Location^, mpos^, Len);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
||||
@ -40,6 +40,8 @@ unit SynEditTypes;
|
||||
{$I synedit.inc}
|
||||
|
||||
interface
|
||||
uses
|
||||
SysUtils;
|
||||
|
||||
const
|
||||
TSynSpecialChars = [#128..#255]; // MG: special chars. Meaning depends on system encoding/codepage.
|
||||
@ -49,6 +51,8 @@ const
|
||||
')', '{', '}', '@', '^', '-', '=', '+', '*', '/', '\', '|','<','>'];
|
||||
|
||||
type
|
||||
ESynEditError = class(Exception);
|
||||
|
||||
TSynIdentChars = set of char;
|
||||
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
|
||||
@ -418,8 +418,8 @@ type
|
||||
procedure StartCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
|
||||
procedure EndCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
|
||||
|
||||
function GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; override;
|
||||
function GetFoldNodeInfoCount(Line: Integer): Integer; override;
|
||||
function GetFoldNodeInfo(Line, Index: Integer; Filter: TSynFoldActions): TSynFoldNodeInfo; override;
|
||||
function GetFoldNodeInfoCount(Line: Integer; Filter: TSynFoldActions): Integer; override;
|
||||
|
||||
property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange;
|
||||
function TopPascalCodeFoldBlockType
|
||||
@ -2555,11 +2555,11 @@ begin
|
||||
CompilerMode := PasCodeFoldRange.Mode;
|
||||
fRange := TRangeStates(Integer(PtrUInt(CodeFoldRange.RangeType)));
|
||||
FNodeInfoLine := -1;
|
||||
FSynPasRangeInfo := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[LineIndex-1];
|
||||
end;
|
||||
|
||||
procedure TSynPasSyn.StartAtLineIndex(LineNumber: Integer);
|
||||
begin
|
||||
FSynPasRangeInfo := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[LineNumber];
|
||||
inherited StartAtLineIndex(LineNumber);
|
||||
end;
|
||||
|
||||
@ -2671,10 +2671,10 @@ var
|
||||
i, j: LongInt;
|
||||
act: TSynFoldActions;
|
||||
begin
|
||||
j := GetFoldNodeInfoCount(ALineIndex);
|
||||
j := GetFoldNodeInfoCount(ALineIndex, []);
|
||||
i := 0;
|
||||
while (i < j) and (FoldIndex > 0) do begin
|
||||
act := GetFoldNodeInfo(ALineIndex, i).FoldAction;
|
||||
act := GetFoldNodeInfo(ALineIndex, i, []).FoldAction;
|
||||
if (UseCloseNodes and (sfaClose in act)) or
|
||||
((not UseCloseNodes) and (sfaOpen in act)) then
|
||||
dec(FoldIndex);
|
||||
@ -2683,7 +2683,7 @@ begin
|
||||
if i = j then
|
||||
exit(-1);
|
||||
// 0 is used for "all"
|
||||
case TPascalCodeFoldBlockType(PtrUInt(GetFoldNodeInfo(ALineIndex, i).FoldType)) of
|
||||
case TPascalCodeFoldBlockType(PtrUInt(GetFoldNodeInfo(ALineIndex, i, []).FoldType)) of
|
||||
cfbtRegion:
|
||||
Result := 2;
|
||||
cfbtIfDef:
|
||||
@ -2834,12 +2834,22 @@ begin
|
||||
Node.FoldType := Pointer(PtrInt(ABlockType));
|
||||
case ABlockType of
|
||||
cfbtRegion:
|
||||
node.FoldGroup := 2;
|
||||
begin
|
||||
node.FoldGroup := 2;
|
||||
Node.FoldLvlStart := FSynPasRangeInfo.EndLevelRegion;
|
||||
end;
|
||||
cfbtIfDef:
|
||||
node.FoldGroup := 3;
|
||||
begin
|
||||
node.FoldGroup := 3;
|
||||
Node.FoldLvlStart := FSynPasRangeInfo.EndLevelIfDef;
|
||||
end;
|
||||
else
|
||||
node.FoldGroup := 1;
|
||||
begin
|
||||
node.FoldGroup := 1;
|
||||
Node.FoldLvlStart := CurrentCodeFoldBlockLevel;
|
||||
end;
|
||||
end;
|
||||
Node.FoldLvlEnd := Node.FoldLvlStart + EndOffs;
|
||||
if ABlockType in PascalWordTrippletRanges then
|
||||
Node.FoldAction := [sfaMarkup]
|
||||
else
|
||||
@ -2869,7 +2879,7 @@ begin
|
||||
if not FFoldConfig[ABlockType] then exit;
|
||||
if FCatchNodeInfo then begin // exclude subblocks, because they do not increase the foldlevel yet
|
||||
GrowNodeInfoList;
|
||||
InitNode(FNodeInfoList[FNodeInfoCount], +1, ABlockType);
|
||||
InitNode(FNodeInfoList[FNodeInfoCount], -1, ABlockType);
|
||||
FNodeInfoList[FNodeInfoCount].FoldAction :=
|
||||
FNodeInfoList[FNodeInfoCount].FoldAction + [sfaClose, sfaFold];
|
||||
inc(FNodeInfoCount);
|
||||
@ -3214,7 +3224,8 @@ begin
|
||||
- ord(low(TSynPasDividerDrawLocation)) + 1;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo;
|
||||
function TSynPasSyn.GetFoldNodeInfo(Line, Index: Integer;
|
||||
Filter: TSynFoldActions): TSynFoldNodeInfo;
|
||||
var
|
||||
i: LongInt;
|
||||
begin
|
||||
@ -3234,16 +3245,31 @@ begin
|
||||
end;
|
||||
|
||||
if (index < 0) or (index >= FNodeInfoCount) then
|
||||
Result := inherited GetFoldNodeInfo(Line, Index)
|
||||
Result := inherited GetFoldNodeInfo(Line, Index, [])
|
||||
else
|
||||
Result := FNodeInfoList[Index];
|
||||
if Filter = [] then
|
||||
Result := FNodeInfoList[Index]
|
||||
else
|
||||
for i := 0 to FNodeInfoCount - 1 do
|
||||
if FNodeInfoList[i].FoldAction * Filter = Filter then begin
|
||||
Result := FNodeInfoList[i];
|
||||
if Index = 0 then break;
|
||||
dec(Index);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.GetFoldNodeInfoCount(Line: Integer): Integer;
|
||||
function TSynPasSyn.GetFoldNodeInfoCount(Line: Integer;
|
||||
Filter: TSynFoldActions): Integer;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
if FNodeInfoLine <> Line then
|
||||
GetFoldNodeInfo(Line, 0);
|
||||
GetFoldNodeInfo(Line, 0, []);
|
||||
Result := FNodeInfoCount;
|
||||
if Filter <> [] then
|
||||
for i := 0 to FNodeInfoCount - 1 do
|
||||
if FNodeInfoList[i].FoldAction * Filter <> Filter then
|
||||
dec(Result);
|
||||
end;
|
||||
|
||||
function TSynPasSyn.GetRangeClass: TSynCustomHighlighterRangeClass;
|
||||
|
||||
@ -2052,6 +2052,8 @@ begin
|
||||
SynEditOptName := 'AlwaysVisibleCaret';
|
||||
eoEnhanceEndKey:
|
||||
SynEditOptName := 'EnhanceEndKey';
|
||||
eoFoldedCopyPaste:
|
||||
SynEditOptName := 'FoldedCopyPaste';
|
||||
else
|
||||
SynEditOptName := '';
|
||||
end;
|
||||
@ -2302,6 +2304,8 @@ begin
|
||||
SynEditOptName := 'AlwaysVisibleCaret';
|
||||
eoEnhanceEndKey:
|
||||
SynEditOptName := 'EnhanceEndKey';
|
||||
eoFoldedCopyPaste:
|
||||
SynEditOptName := 'FoldedCopyPaste';
|
||||
else
|
||||
SynEditOptName := '';
|
||||
end;
|
||||
|
||||
@ -74,6 +74,7 @@ begin
|
||||
// copying
|
||||
Items.Add(dlgFindTextatCursor);
|
||||
Items.Add(dlgCopyWordAtCursorOnCopyNone);
|
||||
Items.Add(dlgCopyPasteKeepFolds);
|
||||
end;
|
||||
EditorTrimSpaceTypeCheckBox.Items.Add(dlgTrimSpaceTypeLeaveLine);
|
||||
EditorTrimSpaceTypeCheckBox.Items.Add(dlgTrimSpaceTypeEditLine);
|
||||
@ -94,6 +95,7 @@ begin
|
||||
Checked[Items.IndexOf(dlgShowGutterHints)] := ShowGutterHints;
|
||||
Checked[Items.IndexOf(dlgFindTextatCursor)] := FindTextAtCursor;
|
||||
Checked[Items.IndexOf(dlgCopyWordAtCursorOnCopyNone)] := CopyWordAtCursorOnCopyNone;
|
||||
Checked[Items.IndexOf(dlgCopyPasteKeepFolds)] := eoFoldedCopyPaste in SynEditOptions2;
|
||||
end;
|
||||
EditorTrimSpaceTypeCheckBox.ItemIndex := ord(TrimSpaceType);
|
||||
end;
|
||||
@ -127,6 +129,12 @@ begin
|
||||
ShowGutterHints := CheckGroupItemChecked(EditorOptionsGroupBox, dlgShowGutterHints);
|
||||
FindTextAtCursor := CheckGroupItemChecked(EditorOptionsGroupBox, dlgFindTextatCursor);
|
||||
TrimSpaceType := TSynEditStringTrimmingType(EditorTrimSpaceTypeCheckBox.ItemIndex);
|
||||
if EditorOptionsGroupBox.Checked[EditorOptionsGroupBox.Items.IndexOf
|
||||
(dlgCopyPasteKeepFolds)]
|
||||
then
|
||||
SynEditOptions2 := SynEditOptions2 + [eoFoldedCopyPaste]
|
||||
else
|
||||
SynEditOptions2 := SynEditOptions2 - [eoFoldedCopyPaste];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -1237,6 +1237,7 @@ resourcestring
|
||||
dlgTrimSpaceTypeEditLine = 'Line Edited';
|
||||
dlgTrimSpaceTypeCaretMove = 'Caret or Edit';
|
||||
dlgTrimSpaceTypePosOnly = 'Position Only';
|
||||
dlgCopyPasteKeepFolds = 'Copy/Paste with fold info';
|
||||
dlgUndoLimit = 'Undo limit';
|
||||
dlgTabWidths = 'Tab widths';
|
||||
dlgMarginGutter = 'Margin and gutter';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user