Организация памяти в текстовом редакторе
Gap buffer
Прикольно. Я ровно такое делал в начале 90-х.
Когда писал один из редакторов под DOS.
Вот тут может быть даже доступны исходники:
http://everesteditor.chat.ru/Resources/Editors/DOS/my/index.htm
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/
Прикольно,что это всплыло в 2013-м году.
Видимо - "есть потребности".
"Я уже не первый раз сталкиваюсь с тем, что некоторые технологии, разработанные для старых компьютеров с ограниченными возможностями, оказываются в наше время забытыми, что приводит к распространению неэффективных решений. Надеюсь, что описанное в этой статье «тайное знание предков» поможет появлению на свет хороших текстовых редакторов."
Ну и это перекликается вот с чем - Рефакторинг. Преодоление "алгоритма маляра".
Всё так или иначе возвращается.
Из старых исходников особенно интересно вот это:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/SSW.PAS
Это собственная реализация своппинга.
А используется своппинг тут:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/LONGEDIT.PAS
Ну а GapBuffer используется например тут:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/EDITOR.PAS
Там кстати и про SuperVision упоминания есть.
А ещё была "штука" -"редактор шаблонных документов". До сих пор мной не повторённая.
Это когда часть текста - ReadOnly а часть - "поля для заполнения".
Типа "формы ввода".
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/LONGEDIT.PAS
Ну и "длинный буфер":
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/NEW/LONGBUF.PAS
Исходники иногда "рвут крышу" - типа "данные обращаются к View". Зато они сильно документированы. Я сейчас столько комментариев - не пишу. Даже удивительно, что уогда-то писал.
А вот тут:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLER.PAS
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLER.INC
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLEC.PAS
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLEC.INC
Ещё смешнее - реализация таблиц для Plain-Text редактора.
Я уж и забыл, что "такое было".
Под каким-нибудь Lazarus'ом или Delphi1 это даже наверное соберётся.
Gap buffer
Прикольно. Я ровно такое делал в начале 90-х.
Когда писал один из редакторов под DOS.
Вот тут может быть даже доступны исходники:
http://everesteditor.chat.ru/Resources/Editors/DOS/my/index.htm
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/
Прикольно,что это всплыло в 2013-м году.
Видимо - "есть потребности".
"Я уже не первый раз сталкиваюсь с тем, что некоторые технологии, разработанные для старых компьютеров с ограниченными возможностями, оказываются в наше время забытыми, что приводит к распространению неэффективных решений. Надеюсь, что описанное в этой статье «тайное знание предков» поможет появлению на свет хороших текстовых редакторов."
Ну и это перекликается вот с чем - Рефакторинг. Преодоление "алгоритма маляра".
Всё так или иначе возвращается.
Из старых исходников особенно интересно вот это:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/SSW.PAS
{$O+} {$I-} Unit SSw; {$DEFINE FROM_SSW} Interface {$I DEFINES.INC} { - текущие директивы условной компиляции } {$I USES.INC} Const swOk = 0; swBoxInvalid = -1; swBoxNoBlock = -2; swNonCorrectBlock = -3; swReadError = -4; swWriteError = -5; swCreateError = -6; swStreamError = -7; swMemoryError = -8; Type TBlockHeader = record NextPtr,PrevPtr : LongInt; LenContext : Word; end; TBoxHeader = record CurBlock,FirstBlock : LongInt; end; PBoxCollection = ^TBoxCollection; TBoxCollection = object(TCollection) Procedure FreeItem(Item : Pointer); virtual; Function DataSize : Integer; virtual; end; const HdSize = SizeOf(TBlockHeader); type PSwapper = ^TSwapper; TSwapper = object(TObject) BoxList : PBoxCollection; {$IFDEF ENCRYPT} SwFile : PEncryptFilter; {$ELSE} SwFile : PLoFile; {$ENDIF} {$IFNDEF TEMP} FName : String; {$ENDIF} HeadSwFile : PLoFile; MaxLenCount: Word; BlockHd : TBlockHeader; FreeBox : Integer; Status : Integer; Constructor Init({$IFNDEF TEMP}Const aFName: PathStr;{$ENDIF} aMaxLenCount: Word {$IFDEF ENCRYPT} ;aKey: LongInt {$ENDIF}); Destructor Done; virtual; Procedure NewBlockBox(Var BoxNumber: Integer); Procedure FreeBlockBox(BoxNumber: Integer); Function GetBlock(BoxNumber:Integer; Var Count: Word; Var Block) : Integer; Function PutBlock(BoxNumber:Integer; Count: Word; Var Block) : Integer; Function MoveBlock(SourceBoxNum,DestBoxNum:Integer) : Integer; Function BoxValid(BoxNumber:Word) : Boolean; Function EmptyBox(BoxNumber:Word) : Boolean; function HasError : Boolean; end; Implementation var TmpCount : Word; Function TBoxCollection.DataSize: Integer; Begin DataSize:=SizeOf(TBoxHeader); end; Procedure TBoxCollection.FreeItem(Item : Pointer); Begin if Item <> Nil Then FreeMem(Item,DataSize); end; Constructor TSwapper.Init({$IFNDEF TEMP}Const aFName: PathStr;{$ENDIF} aMaxLenCount: Word {$IFDEF ENCRYPT} ;aKey: LongInt {$ENDIF}); Begin inherited Init; Status := swOk; MaxLenCount:=aMaxLenCount; {$IFNDEF TEMP} FName := aFName; {$ENDIF} {$IFNDEF TEMP} {$IFDEF ENCRYPT} SwFile:=New(PEncryptFilter,Init(aKey, New(PLoFile,Init(FName+'.sw',stCreate,cBlockSize)))); {$ELSE} SwFile:=New(PLoFile,Init(FName+'.sw',stCreate,cBlockSize)); {$ENDIF ENCRYPT} HeadSwFile:=New(PLoFile,Init(FName+'.hsw',stCreate,512)); {$ELSE} {$IFDEF ENCRYPT} SwFile:=New(PEncryptFilter,Init(aKey, New(PTempBufStream,Init(cBlockSize)))); {$ELSE} SwFile:=New(PTempBufStream,Init(cBlockSize)); {$ENDIF ENCRYPT} HeadSwFile:=New(PTempBufStream,Init(512)); {$ENDIF TEMP} if (SwFile = nil) or (HeadSwFile = nil) then begin Status := swStreamError; Exit; end; if (SwFile^.Status <> stOk) or (HeadSwFile^.Status <> stOk) then begin Status := swCreateError; Exit; end; BoxList:=New(PBoxCollection,Init(5,2)); NewBlockBox(FreeBox); end; Destructor TSwapper.Done; {$IFNDEF TEMP} var F:File; {$ENDIF TEMP} Begin if (SwFile<>nil) then Dispose(SwFile,Done); if (HeadSwFile<>nil) then Dispose(HeadSwFile,Done); if (BoxList<>nil) Then Dispose(BoxList,Done); {$IFNDEF TEMP} Assign(F,FName+'.sw'); Erase(F); Assign(F,FName+'.hsw'); Erase(F); {$ENDIF} inherited Done; end; Procedure TSwapper.NewBlockBox(Var BoxNumber : Integer); Var P : Pointer; It : Integer; Function GetFreeElem(Item: Pointer) : Boolean; far; Begin GetFreeElem:=(Item=Nil); end; Begin P:=MemAlloc(BoxList^.DataSize); If P<>Nil then Begin With TBoxHeader(P^) do Begin CurBlock:=-1; FirstBlock:=-1; end; end else Begin BoxNumber:=-1; Status := swMemoryError; Exit; end; It:=BoxList^.IndexOf(Nil); If It>=0 then Begin BoxList^.AtPut(It,P); BoxNumber:=It; end else Begin BoxNumber:=BoxList^.Count; BoxList^.Insert(P); end; end; Function TSwapper.EmptyBox(BoxNumber:Word) : Boolean; Begin EmptyBox := not(TBoxHeader(BoxList^.At(BoxNumber)^).CurBlock>0); end; {TSwapper.EmptyBox} Procedure TSwapper.FreeBlockBox(BoxNumber : Integer); Begin if BoxValid(BoxNumber) Then begin if (BoxList^.At(BoxNumber)) <> Nil Then begin while(not EmptyBox(BoxNumber)) do MoveBlock(BoxNumber,FreeBox); BoxList^.FreeItem(BoxList^.At(BoxNumber)); BoxList^.AtPut(BoxNumber,Nil); {Связать с пустыми (?!): } end; end else Status := swBoxInvalid; end; Function TSwapper.BoxValid(BoxNumber:Word) : Boolean; Begin If (BoxNumber>=0) and (BoxNumber<BoxList^.Count) then BoxValid:=True else BoxValid:=False; end; Function TSwapper.GetBlock(BoxNumber:Integer; Var Count: Word;Var Block) : Integer; Var CurPtr : LongInt; Begin If Not BoxValid(BoxNumber) then Begin Status := swBoxInvalid; GetBlock:=swBoxInvalid; Exit; end; CurPtr:=TBoxHeader(BoxList^.At(BoxNumber)^).CurBlock; If CurPtr=-1 then Begin Status := swBoxNoBlock; GetBlock:=swBoxNoBlock; Exit; end; HeadSwFile^.Seek(CurPtr*HdSize); HeadSwFile^.Read(BlockHd,HdSize); Count:=BlockHd.LenContext; SwFile^.Seek(CurPtr*MaxLenCount); SwFile^.Read(Block,{MaxLen}Count); if (HeadSwFile^.Status <> stOk) or (SwFile^.Status <> stOk) then begin Status := swReadError; GetBlock:=swReadError; Exit; end; MoveBlock(BoxNumber,FreeBox); GetBlock:=swOk; end; Function TSwapper.PutBlock(BoxNumber:Integer; Count: Word; Var Block) : Integer; Var SwLog : Integer; CurPtr : LongInt; i : Word; const NULL : Byte = 0; Begin If Not BoxValid(BoxNumber) then Begin Status := swBoxInvalid; PutBlock:=swBoxInvalid; Exit; end; if (Count > MaxLenCount) then Count := MaxLenCount; BlockHd.LenContext:=Count; SwLog:=MoveBlock(FreeBox,BoxNumber); If (SwLog=swOk) then Begin CurPtr := TBoxHeader(BoxList^.At(BoxNumber)^).CurBlock; HeadSwFile^.Seek(CurPtr*HdSize); HeadSwFile^.Read(BlockHd,HdSize); if (HeadSwFile^.Status <> stOk) then begin Status := swReadError; PutBlock:=swReadError; Exit; end; BlockHd.LenContext:=Count; HeadSwFile^.Seek(CurPtr*HdSize); HeadSwFile^.Write(BlockHd,HdSize); if (HeadSwFile^.Status <> stOk) then begin Status := swWriteError; PutBlock:=swWriteError; Exit; end; SwFile^.Seek(CurPtr*MaxLenCount); SwFile^.Write(Block,{MaxLen}Count); if (MaxLenCount > Count) then for i := 1 to MaxLenCount - Count do SwFile^.Write(NULL,1); if (SwFile^.Status <> stOk) then begin Status := swWriteError; PutBlock:=swWriteError; Exit; end; PutBlock:=swOk; end else PutBlock:=SwLog; end; Function TSwapper.MoveBlock(SourceBoxNum,DestBoxNum:Integer) : Integer; Var BlockPtr : LongInt; Begin If Not (BoxValid(SourceBoxNum) and BoxValid(DestBoxNum)) then Begin Status:=swBoxInvalid; MoveBlock:=swBoxInvalid; Exit; end; BlockPtr:=TBoxHeader(BoxList^.At(SourceBoxNum)^).CurBlock; If BlockPtr=-1 then If SourceBoxNum=FreeBox then BlockPtr:=HeadSwFile^.GetSize div HdSize else Begin Status := swBoxNoBlock; MoveBlock:=swBoxNoBlock; Exit; end else Begin HeadSwFile^.Seek(BlockPtr*HdSize); HeadSwFile^.Read(BlockHd,HdSize); if (HeadSwFile^.Status <> stOk) then begin Status := swReadError; MoveBlock:=swReadError; Exit; end; TBoxHeader(BoxList^.At(SourceBoxNum)^).CurBlock:=BlockHd.NextPtr; end; {Пpисоед. блока BlockPtr к Dest} BlockHd.NextPtr:=TBoxHeader(BoxList^.At(DestBoxNum)^).CurBlock; HeadSwFile^.Seek(BlockPtr*HdSize); HeadSwFile^.Write(BlockHd,HdSize); if (HeadSwFile^.Status <> stOk) then begin Status := swWriteError; MoveBlock:=swWriteError; Exit; end; If TBoxHeader(BoxList^.At(DestBoxNum)^).CurBlock>=0 then Begin HeadSwFile^.Seek(TBoxHeader(BoxList^.At(DestBoxNum)^).CurBlock*HdSize); HeadSwFile^.Read(BlockHd,HdSize); if (HeadSwFile^.Status <> stOk) then begin Status := swReadError; MoveBlock:=swReadError; Exit; end; BlockHd.PrevPtr:=BlockPtr; HeadSwFile^.Seek(TBoxHeader(BoxList^.At(DestBoxNum)^).CurBlock*HdSize); HeadSwFile^.Write(BlockHd,HdSize); if (HeadSwFile^.Status <> stOk) then begin Status := swWriteError; MoveBlock:=swWriteError; Exit; end; end else {Пеpвый блок}; TBoxHeader(BoxList^.At(DestBoxNum)^).CurBlock:=BlockPtr; MoveBlock:=swOk; end; function TSwapper.HasError : Boolean; var Msg : String; begin if (Status=swOk) then HasError := False else begin HasError := True; Case Status of swBoxInvalid: Msg := 'Неправильный номер коробки временного файла.'; swBoxNoBlock: Msg := 'Коробка временного файла пустая.'; swNonCorrectBlock: Msg := 'Неверный блок временного файла.'; swReadError: Msg := 'Ошибка чтения временного файла.'; swWriteError: Msg := 'Ошибка записи временного файла.'; swCreateError: Msg := 'Ошибка создания временного файла.'; swStreamError: Msg := 'Ошибка открытия временного потока.'; swMemoryError: Msg := 'Нехватка памяти для работы с временным файлом.'; else Msg := 'Неизвестная ошибка временного файла.'; end; MessageBox(^C+Msg,Nil,mfError+mfOkButton); end; end; {$UNDEF FROM_SSW} end.
Это собственная реализация своппинга.
А используется своппинг тут:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/LONGEDIT.PAS
Ну а GapBuffer используется например тут:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/EDITOR.PAS
{$O+} {$DEFINE FROM_EDITOR} Unit Editor; interface {$I DEFINES.INC} { - текущие директивы условной компиляции } {$I USES.INC} { интерфейс обьекта TEditor - простого редактора коротких файлов } type PEditor = ^TEditor; {$IFNDEF SVISION} TEditor = object(TView) {$ELSE} TEditor = object(TView) {$ENDIF} UndoMode: Boolean; HScrollBar: PLongScrollBar; VScrollBar: PLongScrollBar; Indicator: PIndicator; Buffer: PEditBuffer; BufSize: Word; BufLen: Word; GapLen: Word; SelStart: Word; SelEnd: Word; OSelectMode : Byte; { предыдущий режим выделения блока } OSelStart : Word; { старое начало блока (до подкачки из коробки) } OSelEnd : Word; { старый конец блока (до подкачки из коробки) } CurPtr: Word; CurPos: TLongPoint; Delta: TLongPoint; Limit: TLongPoint; edDrawLine: LongInt; DrawPtr: Word; IsValid: Boolean; Modified: Boolean; Selecting: Boolean; Overwrite: Boolean; LockCount: Byte; UpdateFlags: Byte; KeyState: Integer; {$IFDEF SVISION} ScrollNum : LongInt; { количество строк скроллинга в графическом реж} VertScroll : Word; { шаг вертикального скроллирования } SCY : Word; { высота привязанного шрифта } OvSelectMode: Byte; { предыдущий режим выделения блока } {$ENDIF} constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PLongScrollBar; AIndicator: PIndicator; ABufSize: Word); constructor Load(var S: TStream); procedure Store(var S: TStream); destructor Done; virtual; { "стандартные" процедуры поддержки видимого обьекта } procedure ChangeBounds(var Bounds: TRect); virtual; function GetPalette: Views.PPalette; virtual; function CursorVisible: Boolean; function Valid(Command: Word): Boolean; virtual; procedure HandleEvent(var Event: TEvent); virtual; procedure ConvertEvent(var Event: TEvent); virtual; procedure SetCmdState(Command: Word; Enable: Boolean); procedure UpdateCommands; virtual; function GetMousePtr(Mouse: TPoint): Word; procedure SetState(AState: Word; Enable: Boolean); virtual; { работа с буфером редактора } procedure InitBuffer; virtual; procedure DoneBuffer; virtual; function SetBufSize(NewSize: Word): Boolean; virtual; procedure SetBufLen(Length: Word); virtual; { процедуры перемещения по тексту } procedure SetCurPtr(P: Word; SelectMode: Byte);virtual; procedure ScrollTo(X, Y: LongInt); virtual; function GoToBlockStart : Boolean; virtual; function GoToBlockEnd : Boolean; virtual; procedure GoToPos(P:TLongPoint); { базовые процедуры вставки/удаления } function InsertBuffer(var P: PEditBuffer; Offset, Length: Word; AllowUndo, SelectText: Boolean): Boolean; virtual; function InsertFrom(Editor: PEditor): Boolean; virtual; function InsertText(Text: Pointer; Length: Word; SelectText: Boolean): Boolean; virtual; procedure DeleteRange(StartPtr, EndPtr: Word; DelSelect: Boolean); virtual; { базовые процедуры вставки/удаления для Undo файла} procedure uInsertText(AText: Pointer; ALen: Integer; StartPtr: TLongPoint); procedure uOverwriteText(AText: Pointer; ALen: Integer; StartPtr: TLongPoint); procedure uDeleteRange(StartPtr, EndPtr: TLongPoint); function PointLine(ALine: Integer; var ALineLen: Integer) : Pointer; { начало/конец транзакций для Undo-файла } procedure StartTransaction; procedure StopTransaction; { иммитация нажатия клавиш } procedure NewLine; procedure Tab; procedure Undo; virtual; function IsClipboard: Boolean; procedure ToggleInsMode; { процедуры низкого уровня для работы с буфером } function CharPos(P, Target: Word): Integer; virtual; function CharPtr(P: Word; Target: Integer): Word; virtual; function BufChar(P: Word): Char; function BufPtr(P: Word) : Word; function LineMove(P: Word; Count: Integer): Word; function LineStart(P: Word): Word; virtual; function LineEnd(P: Word): Word; virtual; function NextChar(P: Word): Word; virtual; function NextLine(P: Word): Word; function NextWord(P: Word): Word; function PrevChar(P: Word): Word; virtual; function PrevLine(P: Word): Word; function PrevWord(P: Word): Word; { процедуры работы с блоками } procedure SetSelect(NewStart, NewEnd: Word; CurStart: Boolean); virtual; function ClipCopy: Boolean; virtual; procedure ClipCut; virtual; procedure ClipPaste; virtual; procedure DeleteSelect; virtual; procedure DeleteBlock; virtual; function HasSelection: Boolean; procedure HideSelect; virtual; procedure StartSelect(P : Word); virtual; procedure EndSelect(P : Word); virtual; { процедуры отрисовки редактора } procedure Draw; virtual; procedure DrawLines(Y, Count: Integer; LinePtr: Word); virtual; procedure FormatLine(var DrawBuf; LinePtr: Word; Width: Integer; Colors: Word); procedure TrackCursor(Center: Boolean); procedure Lock; procedure Unlock; procedure Update(AFlags: Byte); procedure DoUpdate; virtual; {$IFDEF SVISION} procedure DoScroll; function CheckKeys(Key : Word) : Word; {$ENDIF} { процедуры поиска/замены } function Search(const FindStr: String; Opts: Word): Boolean; procedure DoSearchReplace; {!!!} virtual; procedure Find; procedure Replace; { Для форматирования блоков: } function CorrectSpecial(P, Len : Word) : Integer; virtual; procedure FormatParagraph(cm : Integer); virtual; { сжимает абзац в строку } function ParagraphToLine(cm : Integer;Ind : Integer) : Boolean; Procedure LineToParagraph; Function NextSpace(P : Word) : Word; { определяет левый отступ строки } Function GetIndent(P:Word) : Integer; { переносит слово } Procedure SplitWord(Const FullWord : String; Var SplitPos:Word); virtual; Procedure SplitStr; function GetThisWord(P: Word): String; function ThisWord(P: Word): Word; end; function DefEditorDialog(Dialog: Integer; Info: Pointer): Word; {$IFNDEF SVISION} function CreateFindDialog: PDialog; function CreateReplaceDialog: PDialog; {$ELSE} function CreateFindDialog: PsDialog; function CreateReplaceDialog: PsDialog; {$ENDIF} function StdEditorDialog(Dialog: Integer; Info: Pointer): Word; const LongEditWindowNum : Word = 0; const SetterInited : Boolean = False; var TheSetter : TSetter; { "настройщик" редактора } {$IFDEF USE_UNDO} const UndoFile : PsUndoFile = nil; {$ENDIF USE_UNDO} const Clipboard : PEditor = nil; const EditorDialog: TEditorDialog = StdEditorDialog; {$Ifdef MOST } EditorFlags: Word = efPromptOnReplace; {$Else } EditorFlags: Word = efBackupFiles + efPromptOnReplace; {$EndIf} const FindStr: String[80] = ''; ReplaceStr: String[80] = ''; type TFindDialogRec = record Find: String[80]; Options: Word; end; type TReplaceDialogRec = record Find: String[80]; Replace: String[80]; Options: Word; end; implementation {$I MINMAX.INC} {$I SCAN.INC } {$I COUNT.INC } { TEditor } procedure TEditor.StartTransaction; begin {$IFDEF USE_UNDO} if not IsClipboard and (UndoFile <> nil) then UndoFile^.StartTransaction; {$ENDIF USE_UNDO} end; procedure TEditor.StopTransaction; begin {$IFDEF USE_UNDO} if not IsClipboard and (UndoFile <> nil) then UndoFile^.StopTransaction; {$ENDIF USE_UNDO} end; procedure TEditor.uInsertText(AText: Pointer; ALen: Integer; StartPtr: TLongPoint); begin UndoMode := True; GoToPos(StartPtr); InsertText(AText,ALen,False); UndoMode := False; end; procedure TEditor.uOverwriteText(AText: Pointer; ALen: Integer; StartPtr: TLongPoint); begin UndoMode := True; GoToPos(StartPtr); DeleteRange(CurPtr,CurPtr+ALen,False); GoToPos(StartPtr); InsertText(AText,ALen,False); UndoMode := False; end; procedure TEditor.uDeleteRange(StartPtr, EndPtr: TLongPoint); var OB, OE, OP : TLongPoint; begin UndoMode := True; HideSelect; GoToPos(StartPtr); StartSelect(CurPtr); GoToPos(EndPtr); EndSelect(CurPtr); DeleteBlock; UndoMode := False; end; function TEditor.PointLine(ALine: Integer; var ALineLen: Integer) : Pointer; var P : TLongPoint; begin P.X := 0; P.Y := ALine; GoToPos(P); SetCurPtr(LineEnd(CurPtr),0); ALineLen := LineEnd(CurPtr) - LineStart(CurPtr); PointLine := @(Buffer^[LineStart(CurPtr)]); end; constructor TEditor.Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PLongScrollBar; AIndicator: PIndicator; ABufSize: Word); {$IFDEF SVISION} var SV : TsView absolute Self; {$ENDIF} begin inherited Init(Bounds); GrowMode := gfGrowHiX + gfGrowHiY; Options := Options or ofSelectable; {$IFDEF SVISION} Options := Options or ofClipping; {$ENDIF} EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast; ShowCursor; HScrollBar := AHScrollBar; VScrollBar := AVScrollBar; Indicator := AIndicator; BufSize := ABufSize; {$IFDEF SVISION} VertScroll := 1; SCY := SV.LinkedFont^.CharHeight; OvSelectMode := 0; {$ENDIF} InitBuffer; if Buffer <> nil then IsValid := True else begin IsValid := False; EditorDialog(edOutOfMemory, nil); BufSize := 0; {!!!} SetBufLen(0); Exit; end; SetBufLen(0); if (LongEditWindowNum = 0) then if not(SetterInited) then begin SetterInited := True; if (SetterFileName='') then TheSetter.Init('') else TheSetter.Init(GetPathString+SetterFileName); end; end; constructor TEditor.Load(var S: TStream); begin inherited Load(S); GetPeerViewPtr(S, HScrollBar); GetPeerViewPtr(S, VScrollBar); GetPeerViewPtr(S, Indicator); S.Read(BufSize, SizeOf(Word)); S.Read(SCY,SizeOf(SCY)); InitBuffer; if Buffer <> nil then IsValid := True else begin IsValid := False; EditorDialog(edOutOfMemory, nil); BufSize := 0; end; Lock; {$IFDEF SVISION} VertScroll := 1; {$ENDIF} UndoMode := False; SetBufLen(0); end; destructor TEditor.Done; begin DoneBuffer; if (LongEditWindowNum = 0) then TheSetter.Done; inherited Done; end; function TEditor.BufChar(P: Word): Char; assembler; asm LES DI,Self MOV BX,P CMP BX,ES:[DI].TEditor.CurPtr JB @@1 ADD BX,ES:[DI].TEditor.GapLen @@1: CMP BX,ES:[DI].TEditor.BufSize JB @@2 MOV BX,ES:[DI].TEditor.BufSize DEC BX @@2: LES DI,ES:[DI].TEditor.Buffer MOV AL,ES:[DI+BX] end; function TEditor.BufPtr(P: Word): Word; assembler; asm LES DI,Self MOV AX,P CMP AX,ES:[DI].TEditor.CurPtr JB @@1 ADD AX,ES:[DI].TEditor.GapLen @@1: end; procedure TEditor.ChangeBounds(var Bounds: TRect); begin SetBounds(Bounds); Delta.X := MaxLong(0, MinLong(Delta.X, Limit.X - Size.X div SCX)); Delta.Y := MaxLong(0, MinLong(Delta.Y, Limit.Y - Size.Y div SCY)); Update(ufView); end; function TEditor.CharPos(P, Target: Word): Integer; var Pos: Integer; begin Pos := 0; while P < Target do begin if BufChar(P) = #9 then Pos := Pos or 7; Inc(Pos); Inc(P); end; CharPos := Pos; end; function TEditor.CharPtr(P: Word; Target: Integer): Word; var Pos: Integer; begin Pos := 0; while (Pos < Target) and (P < BufLen) and (BufChar(P) <> #13) do begin if BufChar(P) = #9 then Pos := Pos or 7; Inc(Pos); Inc(P); end; if Pos > Target then Dec(P); CharPtr := P; end; function TEditor.ClipCopy: Boolean; begin ClipCopy := False; if (Clipboard <> nil) and (Clipboard <> @Self) then begin ClipCopy := Clipboard^.InsertFrom(@Self); Selecting := False; Update(ufUpdate); {$IFDEF SVISION} OvSelectMode := smExtend {$ENDIF SVISION} end; end; procedure TEditor.ClipCut; begin if ClipCopy then DeleteSelect; end; procedure TEditor.ClipPaste; begin if (Clipboard <> nil) and (Clipboard <> @Self) then InsertFrom(Clipboard); end; procedure TEditor.ConvertEvent(var Event: TEvent); var ShiftState: Byte absolute $40:$17; Key: Word; begin if Event.What = evKeyDown then begin if (ShiftState and $03 <> 0) and (Event.ScanCode >= $47) and (Event.ScanCode <= $51) then Event.CharCode := #0; Key := Event.KeyCode; if KeyState <> 0 then begin if (Lo(Key) >= $01) and (Lo(Key) <= $1A) then Inc(Key, $40); if (Lo(Key) >= $61) and (Lo(Key) <= $7A) then Dec(Key, $20); end; Key := ScanKeyMap(KeyMap[KeyState], Key); KeyState := 0; if Key <> 0 then if Hi(Key) = $FF then begin KeyState := Lo(Key); ClearEvent(Event); end else begin Event.What := evCommand; Event.Command := Key; end; end; end; function TEditor.CursorVisible: Boolean; begin CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y div SCY); end; procedure TEditor.DeleteRange(StartPtr, EndPtr: Word; DelSelect: Boolean); begin if HasSelection and DelSelect then DeleteSelect else begin SetSelect(StartPtr, EndPtr, True); DeleteSelect; end; end; procedure TEditor.DeleteSelect; var OPos : TLongPoint; SPos : TLongPoint; EPos : TLongPoint; OSS,OSE : Word; SS,SE : Word; begin {$IFDEF USE_UNDO} if not(IsClipBoard) AND (UndoFile<>nil) AND not(UndoMode) then begin OSS := OSelStart; OSE := OSelEnd; SS := SelStart; SE := SelEnd; OPos := CurPos; SetCurPtr(SelStart,0); SPos := CurPos; SetCurPtr(SelEnd,0); EPos := CurPos; UndoFile^.InsertText(@Self,SPos,EPos); if (OPos.X<>SPos.X) OR (OPos.Y<>SPos.Y) then begin GoToPos(OPos); SelStart := SS; SelEnd := SE; end else begin SetSelect(SS,SE,True); end; OSelStart := OSS; OSelEnd := OSE; end; {$ENDIF USE_UNDO} InsertText(nil, 0, False); end; procedure TEditor.DeleteBlock; begin DeleteSelect; end; procedure TEditor.DoneBuffer; begin if Buffer <> nil then begin FreeMem(Buffer, BufSize); Buffer := nil; end; end; procedure TEditor.DoSearchReplace; var I: Word; C: TPoint; begin repeat I := cmCancel; if not Search(FindStr, EditorFlags) then begin if EditorFlags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then EditorDialog(edSearchFailed, nil) end else if EditorFlags and efDoReplace <> 0 then begin I := cmYes; if EditorFlags and efPromptOnReplace <> 0 then begin MakeGlobal(Cursor, C); I := EditorDialog(edReplacePrompt, Pointer(C)); end; if I = cmYes then begin Lock; InsertText(@ReplaceStr[1], Length(ReplaceStr), False); TrackCursor(False); Unlock; end; end; until (I = cmCancel) or (EditorFlags and efReplaceAll = 0); end; {$IFNDEF SVISION} procedure TEditor.DoUpdate; begin if UpdateFlags <> 0 then begin if CursorVisible then SetCursor(CurPos.X - Delta.X, CurPos.Y - Delta.Y); if UpdateFlags and ufView <> 0 then DrawView else if UpdateFlags and ufLine <> 0 then DrawLines((CurPos.Y - Delta.Y), 1, LineStart(CurPtr)); if HScrollBar <> nil then HScrollBar^.SetParams(Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1); if VScrollBar <> nil then VScrollBar^.SetParams(Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1); if Indicator <> nil then Indicator^.SetValue(CurPos, Modified); if State and sfActive <> 0 then UpdateCommands; UpdateFlags := 0; end; end; {$ELSE} procedure TEditor.DoUpdate; var R : TRect; P : TLongPoint; OSM : Word; begin if UpdateFlags <> 0 then begin if (UpdateFlags and ufScroll <> 0) AND (UpdateFlags and ufBlock = 0) AND (abs(ScrollNum)<(Size.Y div SCY)-1) then DoScroll else if (UpdateFlags and ufScroll <> 0) and (ScrollNum <> 0) {AND (UpdateFlags and ufBlock = 0)} then begin OSM := OSelectMode; OSelectMode := 0; P := CurPos; Dec(P.Y,ScrollNum); ScrollNum := 0; GotoPos(P); OSelectMode := OSM; end; ScrollNum := 0; if CursorVisible then SetCursor((CurPos.X - Delta.X)*SCX,(CurPos.Y - Delta.Y)*SCY); if (UpdateFlags and ufView <> 0) or (UpdateFlags and ufBlock <> 0) then DrawView else if UpdateFlags and ufLine <> 0 then begin R.Assign(0,(CurPos.Y-Delta.Y)*SCY,Size.X,(CurPos.Y-Delta.Y+1)*SCY); DrawLines((CurPos.Y - Delta.Y)*SCY, SCY, LineStart(CurPtr)); end; if HScrollBar <> nil then HScrollBar^.SetParams(Delta.X, 0, Limit.X - Size.X div SCX, (Size.X div SCX) div 2, 1); if VScrollBar <> nil then VScrollBar^.SetParams(Delta.Y, 0, Limit.Y - Size.Y div SCY, (Size.Y div SCY) - 1, 1); if Indicator <> nil then Indicator^.SetValue(CurPos, Modified); if State and sfActive <> 0 then UpdateCommands; UpdateFlags := 0; end; end; {$ENDIF SVISION} {$IFDEF SVISION} procedure TEditor.DoScroll; var R : TRect; DY : Integer; OPos,P : TLongPoint; SV : TsView absolute Self; CursorOn : Boolean; procedure DrawProc(var R1 : TRect); far; begin OPos := CurPos; if (ScrollNum > 0) then begin Inc(R1.B.Y,DY); GoToPos(Delta); end else begin Inc(R1.A.Y,DY); P:=Delta; Inc(P.Y,(Size.Y div SCY)); Inc(P.Y,ScrollNum); GoToPos(P); end; CopyImage(ActivePage, R1.A.X, R1.A.Y - DY, R1.B.X-1, R1.B.Y-DY-1, ActivePage, R1.A.X, R1.A.Y); end; var OSM : Word; begin OSM := OSelectMode; OSelectMode := 0; CursorOn := State and sfCursorVis <> 0; if CursorOn then HideCursor; HideMouse; DY := ScrollNum * SCY; GetExtent(R); if (ScrollNum > 0) then R.A.Y := R.A.Y + SCY * ScrollNum else R.B.Y := R.A.Y + ((Size.Y div SCY) + ScrollNum) * SCY; SV.DrawFigure(R,@DrawProc); DrawLines((CurPos.Y - Delta.Y)*SCY, abs(DY), LineStart(CurPtr)); GetExtent(R); R.A.Y := R.B.Y - (Size.Y - (Size.Y div SCY) * SCY); SV.DrawRect(R,True,Lo(GetColor($0301))); if (OPos.Y >= Delta.Y) and (OPos.Y < Delta.Y + Size.Y div SCY) then GoToPos(OPos); UpdateFlags := ufScroll; ShowMouse; if CursorOn then ShowCursor; OSelectMode := OSM; end; function TEditor.CheckKeys(Key : Word) : Word; assembler; asm PUSH CX XOR CX,CX @@LP: MOV AH,1 INT 16H JE @@1 CMP AX,Key JNE @@1 MOV AH,0 INT 16H INC CX JMP @@LP @@1: MOV AX,CX POP CX end; {$ENDIF SVISION} {$IFNDEF SVISION} procedure TEditor.Draw; begin if edDrawLine <> Delta.Y then begin DrawPtr := LineMove(DrawPtr, Delta.Y - edDrawLine); edDrawLine := Delta.Y; end; DrawLines(0, Size.Y, DrawPtr); end; {$ELSE} procedure TEditor.Draw; var R : Trect; SV : TsView absolute Self; begin if edDrawLine <> Delta.Y then begin DrawPtr := LineMove(DrawPtr, Delta.Y - edDrawLine); edDrawLine := Delta.Y; end; DrawLines(0, Size.Y, DrawPtr); GetExtent(R); R.A.Y := R.B.Y - (Size.Y - (Size.Y div SCY) * SCY); SV.DrawRect(R,True,Lo(GetColor($0301))); end; {$ENDIF SVISION} procedure TEditor.DrawLines(Y, Count: Integer; LinePtr: Word); var Color: Word; {$IFDEF SVISION} bkColor : Word; SV : TsView absolute Self; B : array [0..MaxLineLength-1] of Word; SzX : Word; S : String; P : TPoint; R : TRect; S1,S2,S3 : String; C1,C2,C3 : Byte; B1,B2,B3 : Byte; procedure BufferToStr(var Buf; var S1, S2, S3: String; var C1, C2, C3 : Byte; var B1, B2, B3 : Byte; Len: Word); near;{assembler;} var C : Byte; B : array [0..(MaxLineLength-1)*2] of Byte absolute Buf; i : Word; L : Byte; begin C := B[1]; L := 0; S1 := ''; S2 := ''; S3 := ''; for i:=0 to Len*2 do begin if (C <> B[i+1]) then begin C1 := C; if (C1 = Lo(Color)) then B1:=Lo(bkColor) else B1:=Hi(bkColor); C := B[i+1]; break; end; Inc(i); Inc(L); S1[L] := Char(B[i-1]); end; S1[0] := Char(L); L := 0; if (i < Len*2) then for i:=i to Len*2 do begin if (C <> B[i+1]) then begin C2 := C; if (C2 = Lo(Color)) then B2:=Lo(bkColor) else B2:=Hi(bkColor); C := B[i+1]; break; end; Inc(i); Inc(L); S2[L] := Char(B[i-1]); end; S2[0] := Char(L); L := 0; if (i < Len*2) then for i:=i to Len*2 do begin if (C <> B[i+1]) then begin C3 := C; if (C3 = Lo(Color)) then B3:=Lo(bkColor) else B3:=Hi(bkColor); C := B[i+1]; break; end; Inc(i); Inc(L); S3[L] := Char(B[i-1]); end; S3[0] := Char(L); end; {asm PUSH DS LDS SI,Buf LES DI,S1 CLD MOV CX,Len INC DI XOR BL,BL MOV C,0 @@1: LODSB CMP C,0 JE @@2 CMP C,AL JNE @@3 @@2: INC BL LODSB STOSB LOOP @@1 @@3: LES DI,S1 MOV AL,BL STOSB POP DS end;} {$ELSE} B: array[0..MaxLineLength - 1] of Word; {$ENDIF} begin {$IFDEF SVISION} SzX := Size.X div SCX + 1; P.X := 0; P.Y := Y; Color := GetColor($0402); bkColor:= GetColor($0301); {$ELSE} Color := GetColor($0201); {$ENDIF} while Count {$IFNDEF SVISION} >0 {$ELSE} >=SCY {$ENDIF} do begin {$IFNDEF SVISION} FormatLine(B, LinePtr, Delta.X + Size.X, Color); WriteBuf(0, Y, Size.X, 1, B[Delta.X]); LinePtr := NextLine(LinePtr); Inc(Y); Dec(Count); {$ELSE} FormatLine(B, LinePtr, Delta.X+SzX, Color); BufferToStr(B[Delta.X],S1,S2,S3,C1,C2,C3,B1,B2,B3,SzX); R.A.X := P.X; R.A.Y := P.Y; R.B := R.A; Inc(R.B.X,Size.X); Inc(R.B.Y,SCY); SV.DrawSysStr(R,S1,False,C1,B1); if (S2<>'') then begin Inc(R.A.X,Length(S1)*SCX); Inc(R.B.X,Length(S1)*SCX); SV.DrawSysStr(R,S2,False,C2,B2); end; if (S3<>'') then begin Inc(R.A.X,Length(S2)*SCX); Inc(R.B.X,Length(S2)*SCX); SV.DrawSysStr(R,S3,False,C3,B3); end; LinePtr := NextLine(LinePtr); Inc(P.Y,SCY); Dec(Count,SCY); {$ENDIF} end; end; procedure TEditor.Find; var FindRec: TFindDialogRec; begin with FindRec do begin Find := FindStr; Options := EditorFlags; if EditorDialog(edFind, @FindRec) <> cmCancel then begin FindStr := Find; EditorFlags := Options and not efDoReplace; DoSearchReplace; end; end; end; procedure TEditor.FormatLine(var DrawBuf; LinePtr: Word; Width: Integer; Colors: Word); assembler; asm {!!! - Изменена для работы с "нормальными" блоками } PUSH DS LDS BX,Self LES DI,DrawBuf MOV SI,LinePtr XOR DX,DX CLD MOV AH,Colors.Byte[0] MOV CX,DS:[BX].TEditor.CurPtr CMP CX,DS:[BX].TEditor.SelStart JA @@100 CALL @@10 JMP @@200 @@100: MOV CX,DS:[BX].TEditor.SelStart CALL @@10 MOV AH,Colors.Byte[1] MOV CX,DS:[BX].TEditor.CurPtr CMP CX,DS:[BX].TEditor.SelEnd JA @@300 CALL @@10 ADD SI,DS:[BX].TEditor.GapLen JMP @@400 @@300: MOV CX,DS:[BX].TEditor.SelEnd CALL @@10 MOV AH,Colors.Byte[0] MOV CX,DS:[BX].TEditor.CurPtr CALL @@10 ADD SI,DS:[BX].TEditor.GapLen JMP @@500 @@200: ADD SI,DS:[BX].TEditor.GapLen MOV CX,DS:[BX].TEditor.SelStart ADD CX,DS:[BX].TEditor.GapLen CALL @@10 @@400: MOV AH,Colors.Byte[1] MOV CX,DS:[BX].TEditor.SelEnd ADD CX,DS:[BX].TEditor.GapLen CALL @@10 @@500: MOV AH,Colors.Byte[0] MOV CX,DS:[BX].TEditor.BufSize CALL @@10 JMP @@31 @@10: SUB CX,SI JA @@11 RETN @@11: LDS BX,DS:[BX].TEditor.Buffer ADD SI,BX MOV BX,Width @@12: LODSB CMP AL,' ' JB @@20 { $IFNDEF SVISION} @@13: STOSW (*{$ELSE} @@13: STOSB {$ENDIF}*) INC DX @@14: CMP DX,BX JAE @@30 LOOP @@12 LDS BX,Self SUB SI,DS:[BX].TEditor.Buffer.Word[0] RETN @@20: CMP AL,0DH JE @@30 CMP AL,09H JNE @@13 MOV AL,' ' { $IFNDEF SVISION} @@21: STOSW (*{$ELSE} @@21: STOSB {$ENDIF}*) INC DX TEST DL,7 JNE @@21 JMP @@14 @@30: POP CX {$IFNDEF SVISION} @@31: MOV AL,' ' {$ELSE} @@31: MOV AL,00 {$ENDIF} MOV CX,Width SUB CX,DX JBE @@32 REP STOSW @@32: POP DS end; function TEditor.GetMousePtr(Mouse: TPoint): Word; begin MakeLocal(Mouse, Mouse); Mouse.X:=Mouse.X div SCX; Mouse.Y:=Mouse.Y div SCY; Mouse.X := Max(0, Min(Mouse.X, Size.X div SCX - 1)); Mouse.Y := Max(0, Min(Mouse.Y, Size.Y div SCY - 1)); GetMousePtr := CharPtr(LineMove(DrawPtr, Mouse.Y + Delta.Y - edDrawLine), Mouse.X + Delta.X); end; function TEditor.GetPalette:Views.PPalette; const P: String[Length(CEditor)] = CEditor; begin GetPalette := @P; end; function TEditor.ThisWord(P: Word): Word; Begin If (P > 0) then While (P > 0) and (BufChar(PrevChar(P)) in WordChars) do P := PrevChar(P); ThisWord:=P; end; function TEditor.GetThisWord(P: Word): String; Var AThisWord : String; Begin AThisWord:=''; P:=ThisWord(P); While (P < BufLen) and (BufChar(P) in WordChars) do Begin AThisWord:=AThisWord+BufChar(P); P := NextChar(P); end; GetThisWord:=AThisWord; end; function TEditor.GoToBlockStart : Boolean; begin GoToBlockStart := True; SetCurPtr(SelStart,0); end; function TEditor.GoToBlockEnd : Boolean; begin GoToBlockEnd := True; SetCurPtr(SelEnd,0); end; procedure TEditor.GoToPos(P:TLongPoint); var i : LongInt; Lim : LongInt; begin if (P.X=CurPos.X) AND (P.Y=CurPos.Y) then Exit; {$IFDEF SVISION} Inc(LockCount); {$ENDIF} if P.Y <> CurPos.Y then begin Lim := P.Y - CurPos.Y; for i:=1 To abs(Lim) do SetCurPtr(LineMove(CurPtr,Lim div abs(Lim)),0); end; SetCurPtr(LineStart(CurPtr),0); if (P.X<=CharPos(CurPtr,LineEnd(CurPtr))) then for i:=1 To P.X do SetCurPtr(NextChar(CurPtr),0); {$IFDEF SVISION} Dec(LockCount); {$ENDIF} end; procedure TEditor.HandleEvent(var Event: TEvent); var ShiftState : Byte absolute $40:$17; CenterCursor: Boolean; SelectMode : Byte; i : Integer; NewPtr : Word; D : TLongPoint; Mouse : TPoint; {$IFDEF SVISION} ODelta : TLongPoint; SV : TsView absolute Self; {$ENDIF} procedure CheckScrollBar(P: PLongScrollBar; var D: {$IFNDEF SVISION} LongInt {$ELSE} Integer {$ENDIF}); {$IFDEF SVISION} var ODelta : TLongPoint; {$ENDIF} begin if (Event.InfoPtr = P) and (P^.Value <> D) then begin {$IFDEF SVISION} ODelta := Delta; {$ENDIF} D := P^.Value; {$IFDEF SVISION} if (ODelta.Y<>Delta.Y) then Message(@Self,evCommand,cmSetScroll,Pointer(ODelta.Y-Delta.Y)) else Update(ufView); {$ELSE} Update(ufView); {$ENDIF} end; end; begin {$IFDEF SVISION} ScrollNum := 0; SCY := SV.LinkedFont^.CharHeight; {$ENDIF} inherited HandleEvent(Event); ConvertEvent(Event); CenterCursor := not CursorVisible; SelectMode := 0; if Selecting or (ShiftState and $03 <> 0) then SelectMode := smExtend; {$IFDEF SVISION} if (SelectMode = smExtend) then UpdateFlags := ufView or ufBlock else if (OvSelectMode = smExtend) OR (OvSelectMode = smDrag) then UpdateFlags := ufView or ufBlock; OvSelectMode := SelectMode; {$ENDIF} case Event.What of evMouseDown: begin if Event.Double then SelectMode := SelectMode or smDouble; repeat Lock; if Event.What = evMouseAuto then begin MakeLocal(Event.Where, Mouse); D := Delta; if Mouse.X < 0 then Dec(D.X); if Mouse.X >= Size.X then Inc(D.X); if Mouse.Y < 0 then Dec(D.Y); if Mouse.Y >= Size.Y then Inc(D.Y); ScrollTo(D.X, D.Y); end; SetCurPtr(GetMousePtr(Event.Where), SelectMode); SelectMode := SelectMode or smExtend; UpdateFlags := ufView {$IFDEF SVISION} {or ufBlock} {$ENDIF}; {$IFDEF SVISION} OvSelectMode := smDrag; {$ENDIF} Unlock; until not MouseEvent(Event, evMouseMove + evMouseAuto); end; evKeyDown: case Event.CharCode of #32..#255: begin Lock; if Overwrite {and not HasSelection} and (CurPtr <> LineEnd(CurPtr)) then begin DeleteRange(CurPtr,CurPtr+1,False); end; {SelEnd := NextChar(CurPtr)}; If (Event.CharCode in [#32]) and (CurPtr >= LineStart(CurPtr)+TheSetter._R.StrLen-1) then NewLine else InsertText(@Event.CharCode, 1, False); TrackCursor(False); Unlock; end; else Exit; end; evCommand: case Event.Command of cmFind: Find; cmReplace: Replace; cmSearchAgain: DoSearchReplace; else begin Lock; case Event.Command of cmTab: Tab; cmCut: ClipCut; cmCopy: ClipCopy; cmPaste: ClipPaste; cmUndo: Undo; cmClear: DeleteSelect; cmCharLeft: {$IFNDEF SVISION} SetCurPtr(PrevChar(CurPtr), SelectMode); {$ELSE} for i:= 1 to CheckKeys(kbLeft)+1 do begin SetCurPtr(PrevChar(CurPtr), SelectMode); end; {$ENDIF SVISION} cmCharRight:{$IFNDEF SVISION} SetCurPtr(NextChar(CurPtr), SelectMode); {$ELSE} for i:= 1 to CheckKeys(kbRight)+1 do begin SetCurPtr(NextChar(CurPtr), SelectMode); end; {$ENDIF} cmWordLeft: SetCurPtr(PrevWord(CurPtr), SelectMode); cmWordRight: SetCurPtr(NextWord(CurPtr), SelectMode); cmLineStart: SetCurPtr(LineStart(CurPtr), SelectMode); cmLineEnd: SetCurPtr(LineEnd(CurPtr), SelectMode); cmLineUp: {$IFNDEF SVISION} SetCurPtr(LineMove(CurPtr, -1), SelectMode); {$ELSE} begin ScrollNum := VertScroll * (CheckKeys(kbUp)+1); if (ScrollNum > (CurPos.Y)) then ScrollNum := CurPos.Y; SetCurPtr(LineMove(CurPtr, -ScrollNum), SelectMode); end; {$ENDIF} cmLineDown:{$IFNDEF SVISION} SetCurPtr(LineMove(CurPtr, 1), SelectMode); {$ELSE} begin ScrollNum := -VertScroll * (CheckKeys(kbDown)+1); if (-ScrollNum > (Limit.Y-CurPos.Y)) then ScrollNum := CurPos.Y - Limit.Y; SetCurPtr(LineMove(CurPtr, -ScrollNum), SelectMode); end; {$ENDIF} cmPageUp: {$IFNDEF SVISION} SetCurPtr(LineMove(CurPtr, -(Size.Y div SCY - 1)), SelectMode); {$ELSE} SetCurPtr(LineMove(CurPtr, -(Size.Y div SCY - 1)*(CheckKeys(kbPgUp)+1)), SelectMode); {$ENDIF} cmPageDown:{$IFNDEF SVISION} SetCurPtr(LineMove(CurPtr, (Size.Y div SCY - 1)), SelectMode); {$ELSE} SetCurPtr(LineMove(CurPtr, (Size.Y div SCY - 1)*(CheckKeys(kbPgDn)+1)), SelectMode); {$ENDIF} cmTextStart: SetCurPtr(0, SelectMode); cmTextEnd: SetCurPtr(BufLen, SelectMode); cmNewLine: NewLine; cmBackSpace: DeleteRange(PrevChar(CurPtr), CurPtr, False); cmDelChar: DeleteRange(CurPtr, NextChar(CurPtr), False); cmDelWord: DeleteRange(CurPtr, NextWord(CurPtr), False); cmDelStart: DeleteRange(LineStart(CurPtr), CurPtr, False); cmDelEnd: DeleteRange(CurPtr, LineEnd(CurPtr), False); cmDelLine: DeleteRange(LineStart(CurPtr), NextLine(CurPtr), False); cmInsMode: ToggleInsMode; cmStartSelect: StartSelect(CurPtr); cmHideSelect: HideSelect; cmIndentMode: TheSetter._R.AutoIndent := not TheSetter._R.AutoIndent; {$IFDEF SVISION} cmSetScroll : begin ScrollNum := Integer(Event.InfoPtr); if (ScrollNum <> 0) then UpdateFlags := (UpdateFlags and ufBlock) or ufView or ufScroll; UnLock; ClearEvent(Event); Exit; end; {$ENDIF} else Unlock; Exit; end; {$IFDEF SVISION} ODelta := Delta; TrackCursor(False); if (ScrollNum <> 0) AND (ODelta.Y<>Delta.Y) then begin Dec(LockCount); Message(@Self,evCommand,cmSetScroll,Pointer(ScrollNum)); ClearEvent(Event); Exit; end; {$ELSE} TrackCursor(False); {$ENDIF SVISION} Unlock; end; end; evBroadcast: case Event.Command of cmScrollBarChanged: if (Event.InfoPtr = HScrollBar) or (Event.InfoPtr = VScrollBar) then begin CheckScrollBar(HScrollBar, Delta.X); CheckScrollBar(VScrollBar, Delta.Y); end else Exit; else Exit; end; end; ClearEvent(Event); end; function TEditor.HasSelection: Boolean; begin HasSelection := SelStart <> SelEnd; end; procedure TEditor.HideSelect; begin Selecting := False; SetSelect(CurPtr, CurPtr, False); {$IFDEF SVISION} UpdateFlags := ufView or ufBlock; {$ENDIF SVISION} end; procedure TEditor.InitBuffer; begin Buffer := MemAlloc(BufSize); end; function TEditor.InsertBuffer(var P: PEditBuffer; Offset, Length: Word; AllowUndo, SelectText: Boolean): Boolean; var SelLen, DelLen, SelLines, Lines: Word; NewSize,Dum: Longint; OCurPos : TLongPoint; begin OCurPos := CurPos; InsertBuffer := True; Selecting := False; SelLen := SelEnd - SelStart; if (SelLen = 0) and (Length = 0) then Exit; DelLen := 0; if (SelLen > 0) then DelLen := SelLen; NewSize := Longint(BufLen - SelLen + DelLen) + Length; if (NewSize > $FFF0) then NewSize := $FFF1; if (NewSize > BufSize) then if not SetBufSize(NewSize) then begin EditorDialog(edOutOfMemory, nil); InsertBuffer := False; SelEnd := SelStart; Exit; end; if (SelLen > 0) then SelLines := CountLines(Buffer^[BufPtr(SelStart)], SelLen) else SelLines := 0; if (CurPtr = SelEnd) AND (SelLen > 0) then begin CurPtr := SelStart; Dec(CurPos.Y, SelLines); end; if Delta.Y > CurPos.Y then begin Dec(Delta.Y, SelLines); if Delta.Y < CurPos.Y then Delta.Y := CurPos.Y; end; if Length > 0 then Move(P^[Offset], Buffer^[CurPtr], Length); Lines := CountLines(Buffer^[CurPtr], Length); Inc(CurPtr, Length); Inc(CurPos.Y, Lines); edDrawLine := CurPos.Y; DrawPtr := LineStart(CurPtr); CurPos.X := CharPos(DrawPtr, CurPtr); if not SelectText then SelStart := CurPtr; SelEnd := CurPtr; Dum:=Length; Dum:=Dum-SelLen; Inc(BufLen,Dum); Dec(GapLen,Dum); Dum:=Lines; Dum:=Dum-SelLines; Inc(Limit.Y,Dum); Delta.Y := MaxLong(0, MinLong(Delta.Y, Limit.Y - Size.Y div SCY)); if not(IsClipboard) then Modified := True; {$IFDEF USE_UNDO} if (UndoFile<>nil) AND not(IsClipBoard) AND not(UndoMode) then UndoFile^.DeleteRange(OCurPos,CurPos); {$ENDIF USE_UNDO} SetBufSize(BufLen); if (SelLines = 0) and (Lines = 0) then Update(ufLine) else Update(ufView); end; function TEditor.InsertFrom(Editor: PEditor): Boolean; begin InsertFrom := InsertBuffer(Editor^.Buffer, Editor^.BufPtr(Editor^.SelStart), Editor^.SelEnd - Editor^.SelStart, False, IsClipboard); end; function TEditor.InsertText(Text: Pointer; Length: Word; SelectText: Boolean): Boolean; begin InsertText:=InsertBuffer(PEditBuffer(Text), 0, Length, False, SelectText); end; function TEditor.IsClipboard: Boolean; begin IsClipboard := (Clipboard = @Self); end; function TEditor.LineEnd(P: Word): Word; assembler; asm PUSH DS LDS SI,Self LES BX,DS:[SI].TEditor.Buffer MOV DI,P MOV AL,0DH CLD MOV CX,DS:[SI].TEditor.CurPtr SUB CX,DI JBE @@1 ADD DI,BX REPNE SCASB JE @@2 MOV DI,DS:[SI].TEditor.CurPtr @@1: MOV CX,DS:[SI].TEditor.BufLen SUB CX,DI JCXZ @@4 ADD BX,DS:[SI].TEditor.GapLen ADD DI,BX REPNE SCASB JNE @@3 @@2: DEC DI @@3: SUB DI,BX @@4: MOV AX,DI POP DS end; function TEditor.LineMove(P: Word; Count: Integer): Word; var Pos: Integer; I: Word; begin I := P; P := LineStart(P); Pos := CharPos(P, I); while Count <> 0 do begin I := P; if Count < 0 then begin P := PrevLine(P); Inc(Count); end else begin P := NextLine(P); Dec(Count); end; end; if P <> I then P := CharPtr(P, Pos); LineMove := P; end; function TEditor.LineStart(P: Word): Word; assembler; asm PUSH DS LDS SI,Self LES BX,DS:[SI].TEditor.Buffer MOV DI,P MOV AL,0DH STD MOV CX,DI SUB CX,DS:[SI].TEditor.CurPtr JBE @@1 ADD BX,DS:[SI].TEditor.GapLen ADD DI,BX DEC DI REPNE SCASB JE @@2 SUB BX,DS:[SI].TEditor.GapLen MOV DI,DS:[SI].TEditor.CurPtr @@1: MOV CX,DI JCXZ @@4 ADD DI,BX DEC DI REPNE SCASB JNE @@3 @@2: INC DI INC DI SUB DI,BX CMP DI,DS:[SI].TEditor.CurPtr JE @@4 CMP DI,DS:[SI].TEditor.BufLen JE @@4 CMP ES:[BX+DI].Byte,0AH JNE @@4 INC DI JMP @@4 @@3: XOR DI,DI @@4: MOV AX,DI POP DS end; procedure TEditor.Lock; begin Inc(LockCount); end; procedure TEditor.NewLine; const CrLf: array[1..2] of Char = #13#10; InChar : Char =' '; var I,B,ILen: Word; begin B := LineStart(CurPtr); InsertText(@CrLf, 2, False); if TheSetter._R.AutoIndent then If TheSetter._R.IndentLen<0 data-blogger-escaped-:="B;" data-blogger-escaped-and="" data-blogger-escaped-begin="" data-blogger-escaped-curptr="" data-blogger-escaped-do="" data-blogger-escaped-else="" data-blogger-escaped-end="" data-blogger-escaped-false="" data-blogger-escaped-i="" data-blogger-escaped-if="" data-blogger-escaped-inc="" data-blogger-escaped-inserttext="" data-blogger-escaped-or="" data-blogger-escaped-then="" data-blogger-escaped-thesetter._r.indentlen="" data-blogger-escaped-uffer="" data-blogger-escaped-while="">0 then For i:=0 to TheSetter._R.IndentLen-1 do InsertText(@InChar,1, False); end; function TEditor.NextChar(P: Word): Word; assembler; asm PUSH DS LDS SI,Self MOV DI,P CMP DI,DS:[SI].TEditor.BufLen JE @@3 INC DI CMP DI,DS:[SI].TEditor.BufLen JE @@3 LES BX,DS:[SI].TEditor.Buffer CMP DI,DS:[SI].TEditor.CurPtr JB @@1 ADD BX,DS:[SI].TEditor.GapLen @@1: CMP ES:[BX+DI-1].Word,0A0DH JNE @@2 INC DI @@2: {!!!} @@3: CMP DI,DS:[SI].TEditor.BufSize JB @@4 MOV DI,DS:[SI].TEditor.BufSize DEC DI @@4: MOV AX,DI POP DS end; function TEditor.NextLine(P: Word): Word; begin NextLine := NextChar(LineEnd(P)); end; function TEditor.NextWord(P: Word): Word; begin while (P < BufLen) and (BufChar(P) in WordChars) do P := NextChar(P); while (P < BufLen) and not (BufChar(P) in WordChars) do P := NextChar(P); NextWord := P; end; function TEditor.PrevChar(P: Word): Word; assembler; asm PUSH DS LDS SI,Self MOV DI,P OR DI,DI JE @@3 DEC DI JE @@3 LES BX,DS:[SI].TEditor.Buffer CMP DI,DS:[SI].TEditor.CurPtr JB @@1 ADD BX,DS:[SI].TEditor.GapLen @@1: CMP ES:[BX+DI-1].Word,0A0DH JNE @@2 DEC DI @@2: {!!!} @@3: MOV AX,DI POP DS end; function TEditor.PrevLine(P: Word): Word; begin PrevLine := LineStart(PrevChar(P)); end; function TEditor.PrevWord(P: Word): Word; begin while (P > 0) and not (BufChar(PrevChar(P)) in WordChars) do P := PrevChar(P); while (P > 0) and (BufChar(PrevChar(P)) in WordChars) do P := PrevChar(P); PrevWord := P; end; procedure TEditor.Replace; var ReplaceRec: TReplaceDialogRec; begin with ReplaceRec do begin Find := FindStr; Replace := ReplaceStr; Options := EditorFlags; if EditorDialog(edReplace, @ReplaceRec) <> cmCancel then begin FindStr := Find; ReplaceStr := Replace; EditorFlags := Options or efDoReplace; DoSearchReplace; end; end; end; procedure TEditor.ScrollTo(X, Y: LongInt); begin X := MaxLong(0, MinLong(X, Limit.X - Size.X div SCX)); Y := MaxLong(0, MinLong(Y, Limit.Y - Size.Y div SCY)); {!!!} if (X <> Delta.X) or (Y <> Delta.Y) then begin Delta.X := X; Delta.Y := Y; Update(ufView); end; end; function TEditor.Search(const FindStr: String; Opts: Word): Boolean; var I, Pos: Word; begin Search := False; Pos := CurPtr; repeat if Opts and efCaseSensitive <> 0 then I := Scan(Buffer^[BufPtr(Pos)], BufLen - Pos, FindStr,0) else I := IScan(Buffer^[BufPtr(Pos)], BufLen - Pos, FindStr); if (I <> sfSearchFailed) then begin Inc(I, Pos); if (Opts and efWholeWordsOnly = 0) or not (((I <> 0) and (BufChar(I - 1) in WordChars)) or ((I + Length(FindStr) <> BufLen) and (BufChar(I + Length(FindStr)) in WordChars))) then begin Lock; SetCurPtr(I,0); StartSelect(CurPtr); EndSelect(CurPtr + Length(FindStr)); Selecting := False; {$IFDEF SVISION} OvSelectMode := smExtend; {$ENDIF} TrackCursor(not CursorVisible); Unlock; Search := True; Exit; end else Pos := I + 1; end; until I = sfSearchFailed; end; procedure TEditor.SetBufLen(Length: Word); begin BufLen := Length; GapLen := BufSize - Length; SelStart := 0; SelEnd := 0; CurPtr := 0; CurPos.X := 0; CurPos.Y := 0; Delta.X := 0; Delta.Y := 0; Limit.X := MaxLineLength; Limit.Y := CountLines(Buffer^[GapLen], BufLen) + 1; edDrawLine := 0; DrawPtr := 0; Modified := False; Update(ufView); end; function TEditor.SetBufSize(NewSize: Word): Boolean; begin SetBufSize := NewSize <= BufSize; end; procedure TEditor.SetCmdState(Command: Word; Enable: Boolean); var S: TCommandSet; begin S := [Command]; if Enable and (State and sfActive <> 0) then EnableCommands(S) else DisableCommands(S); end; procedure TEditor.SetCurPtr(P: Word; SelectMode: Byte); var Anchor: Word; begin if SelectMode and smExtend = 0 then Anchor := P else if CurPtr = SelStart then Anchor := SelEnd else Anchor := SelStart; if P < Anchor then begin if SelectMode and smDouble <> 0 then begin P:=PrevLine(NextLine(P)); Anchor:=NextLine(PrevLine(Anchor)); end; SetSelect(P, Anchor, True); end else begin if SelectMode and smDouble <> 0 then begin P:=NextLine(P); Anchor:=PrevLine(NextLine(Anchor)); end; SetSelect(Anchor, P, False); end; end; procedure TEditor.SetSelect(NewStart, NewEnd: Word; CurStart: Boolean); var Flags: Byte; P, L: Word; begin if CurStart then P := NewStart else P := NewEnd; Flags := ufUpdate; {$IFNDEF SVISION} if (NewStart <> SelStart) or (NewEnd <> SelEnd) then if (NewStart <> NewEnd) or (SelStart <> SelEnd) then Flags := ufView; {$ENDIF} if P <> CurPtr then begin if P > CurPtr then begin L := P - CurPtr; Move(Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L); Inc(CurPos.Y, CountLines(Buffer^[CurPtr], L)); CurPtr := P; end else begin L := CurPtr - P; CurPtr := P; Dec(CurPos.Y, CountLines(Buffer^[CurPtr], L)); Move(Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L); end; edDrawLine := CurPos.Y; DrawPtr := LineStart(P); CurPos.X := CharPos(DrawPtr, P); SetBufSize(BufLen); end; SelStart := NewStart; SelEnd := NewEnd; Update(Flags); end; procedure TEditor.SetState(AState: Word; Enable: Boolean); begin inherited SetState(AState, Enable); case AState of sfActive: begin if HScrollBar <> nil then HScrollBar^.SetState(sfVisible, Enable); if VScrollBar <> nil then VScrollBar^.SetState(sfVisible, Enable); if Indicator <> nil then Indicator^.SetState(sfVisible, Enable); {$IFDEF USE_UNDO} if Enable AND (UndoFile <> nil) then UndoFile^.Clear; {$ENDIF USE_UNDO} UpdateCommands; end; sfExposed: if Enable then Unlock; end; end; Procedure TEditor.SplitWord(Const FullWord : String; Var SplitPos:Word); Var I : Byte; Len : Byte; Function GlasnPresent(Const Slog : String) : Boolean; Var I : Byte; Begin GlasnPresent:=False; For I:=1 to Length(Slog) do If Slog[I] in Glasn then Begin GlasnPresent:=True; Break; end; end; Function ValidSlog(Const Slog : String;SlogNum : Byte) : Boolean; Begin If (Length(Slog)>1) and GlasnPresent(Slog) and ((SlogNum=1) or Not (Slog[1] in Znaks)) then ValidSlog:=True else ValidSlog:=False; end; Begin if TheSetter._R.MaySplit then begin Len := Length(FullWord); While SplitPos>1 do Begin If ValidSlog(Copy(FullWord,1,SplitPos),1) and ValidSlog(Copy(FullWord,SplitPos+1,Len),2) and ((FullWord[SplitPos] in Glasn+Znaks) or Not (FullWord[SplitPos+1] in Glasn)) then Exit else Dec(SplitPos); end; SplitPos:=0; end else SplitPos := 0; end; Function TEditor.GetIndent(P:Word) : Integer; Var I : Integer; Begin P:=LineStart(P); I:=0; if (BufChar(P)=#13) then I:=-1 else While (P<BufLen) AND (BufChar(P)=#32) do Begin Inc(I); { Inc(P);} P:=NextChar(P); end; GetIndent:=I; end; Function TEditor.NextSpace(P : Word) : Word; const SP : Char = #32; Begin Repeat P:=NextChar(P); if BufChar(P)=#9 then begin DeleteRange(P,NextChar(P),False); InsertText(@SP,1,False); end; until (BufChar(P)=#32) or (P+1 >= BufLen); NextSpace:=P; end; function TEditor.ParagraphToLine(cm : Integer; Ind : Integer) : Boolean; Var P : Word; OP : TLongPoint; Cnt : LongInt; SCnt : String; Begin Cnt := 0; SCnt := ''; CtrlBreakHit := False; ParagraphToLine := True; OP := CurPos; P := LineStart(CurPtr); {!!!} if ((cm = cmFormatInt) AND (GetIndent(P)<>TheSetter._R.FirstLineIndent)) then Ind:=GetIndent(P); If (BufChar(LineStart(CurPtr)) = #32) then If (NextWord(P)<=LineEnd(CurPtr)) then P:=NextWord(P) else Begin SetCurPtr(LineStart(NextLine(P)),0); EXIT; end; Repeat Inc(Cnt); Str(Cnt,SCnt); SCnt := 'Просмотрено: ' + SCnt + ' строк.'; DecStatusCount; SetNewStatus(SCnt); While (NextSpace(P)<LineEnd(P)) do Begin P:=NextSpace(P); SetCurPtr(P,0); If (BufChar(NextChar(P))=#32) then Begin While (P<BufLen) AND (BufChar(NextChar(P))=#32) do P:=NextChar(P); DeleteRange(CurPtr,P,False); end; P:=CurPtr; end; If (P >= BufLen) then exit; {!!!} If (Ind = -1) then Ind:=GetIndent(NextLine(P)); If (Ind >=0) AND ((cm = cmFormatInt) AND (GetIndent(NextLine(P))=Ind)) XOR ((cm = cmFormatNew) AND (GetIndent(NextLine(P))=Ind)) XOR ((cm = cmFormat) AND (GetIndent(NextLine(P))=TheSetter._R.IndentLen)) then Begin {!!!} SetCurPtr(LineEnd(P),0); P:=NextLine(P); If P >= BufLen then exit; P:=LineStart(P); While (P<BufLen) AND (BufChar(P)=#32) do P:=NextChar(P); DeleteRange(CurPtr,P,False); P:=PrevChar(CurPtr); If (BufChar(P)=CarrySign) and (BufChar(PrevChar(P)) in WordChars) and (BufChar(NextChar(P)) in WordChars) then DeleteRange(P,NextChar(P),False) else If (BufChar(P)<>#32) then Begin SetCurPtr(NextChar(P),0); InsertText(@SpaceCh,1,False); end; end else Begin Break; end; until CtrlBreakHit {и не конец файла}; if CtrlBreakHit then begin CtrlBreakHit := False; ParagraphToLine := False; end; GoToPos(OP); CtrlBreakHit := False; end; Procedure TEditor.LineToParagraph; var Cnt : LongInt; SCnt : String; Begin Cnt := 0; SCnt := ''; While (LineEnd(CurPtr)-LineStart(CurPtr)>TheSetter._R.StrLen) do begin Inc(Cnt); Str(Cnt,SCnt); SCnt := 'Отформатировано: ' + SCnt + ' строк.'; DecStatusCount; SetNewStatus(SCnt); Splitstr; end; end; procedure TEditor.FormatParagraph(cm : Integer); var LS : Word; Ind: Integer; S : String; i : integer; Begin SetNewStatus('Форматирование абзаца...'); StartTransaction; Ind := -1; if (cm = cmFormatNew) then begin LS := LineStart(CurPtr); Ind := GetIndent(CurPtr); if (Ind>0) then DeleteRange(LS,LS+Ind,False); if (TheSetter._R.FirstLineIndent > 0) then begin S := ''; for i:=1 to TheSetter._R.FirstLineIndent do S := S + #32; SetCurPtr(LineStart(CurPtr),0); InsertText(@S[1],Length(S),False); SetCurPtr(LineStart(CurPtr),0); end; end; if ParagraphToLine(cm,-1) then LineToParagraph; SetCurPtr(NextLine(CurPtr),0); StopTransaction; SetOldStatus; end; function TEditor.CorrectSpecial(P, Len : Word) : Integer; begin CorrectSpecial := 0; end; Procedure TEditor.SplitStr; Var SpWord : String; SplitNum : Word; DecSpNum : Integer; SaveCurPtr : Word; P : Word; IncrCh : Integer; SLen : Word; Begin IncrCh:=0; DecSpNum:=0; SaveCurPtr:=CurPtr; SLen := TheSetter._R.StrLen; SLen := SLen+CorrectSpecial(LineStart(CurPtr),SLen); P:=LineStart(CurPtr)+SLen; SpWord:=GetThisWord(P); If SpWord='' then While BufChar(PrevChar(P))=#32 do P:=PrevChar(P) else If (ThisWord(P)>=P-1) then Begin P:=ThisWord(P); While BufChar(PrevChar(P))=#32 do P:=PrevChar(P) end else Begin P:=ThisWord(P); SplitNum:=LineStart(P)+SLen-1; SplitNum:=SplitNum-P; SplitWord(SpWord,SplitNum); If SplitNum>0 then Begin SetCurPtr(P+SplitNum,0); InsertText(@CarrySign, 1, False); P:=CurPtr; end else While BufChar(PrevChar(P))=' ' do P:=PrevChar(P); end; if TheSetter._R.MaySmooth then begin IncrCh:=LineStart(CurPtr)+SLen-P; If (IncrCh>0) and (LineStart(P)<PrevWord(P)) and (LineStart(P)<PrevWord(PrevWord(P))) then Begin While IncrCh>0 do Begin While (LineStart(P)<PrevWord(PrevWord(P))) and (IncrCh>0) do Begin P:=PrevWord(P); SetCurPtr(P,0); InsertText(@SpaceCh, 1, False); Dec(IncrCh); end; P:=LineStart(P)+SLen-IncrCh; end; P:=LineStart(P)+SLen; end; end;{if MaySmooth ...} SetCurPtr(P,0); NewLine; P:=LineStart(CurPtr)+TheSetter._R.IndentLen; If BufChar(P)=#32 then DeleteRange(P,NextChar(P),False); end; procedure TEditor.StartSelect(P : Word); begin Selecting := True; SetSelect(P,SelEnd,True); {$IFDEF SVISION} UpdateFlags := UpdateFlags or ufBlock; {$ENDIF} end; procedure TEditor.EndSelect(P : Word); begin Selecting := True; SetSelect(SelStart,P,False); {$IFDEF SVISION} UpdateFlags := UpdateFlags or ufBlock; {$ENDIF} end; procedure TEditor.Store(var S: TStream); begin inherited Store(S); PutPeerViewPtr(S, HScrollBar); PutPeerViewPtr(S, VScrollBar); PutPeerViewPtr(S, Indicator); S.Write(BufSize, SizeOf(Word)); S.Write(SCY,SizeOf(SCY)); end; procedure TEditor.ToggleInsMode; begin Overwrite := not Overwrite; SetState(sfCursorIns, not GetState(sfCursorIns)); end; procedure TEditor.Tab; var i : Byte; S : String; Begin Lock; S := ''; for i := 1 to (TheSetter._R.TabLen-(CurPos.X mod TheSetter._R.TabLen)) do S := S + #32; if (Ord(S[0])<>0) then InsertText(@S[1],i,False); TrackCursor(not CursorVisible); UnLock; end; procedure TEditor.TrackCursor(Center: Boolean); begin if Center then ScrollTo(CurPos.X - Size.X div SCX + 1, CurPos.Y - (Size.Y div SCY) div 2) else ScrollTo(MaxLong(CurPos.X - Size.X div SCX + 1, MinLong(Delta.X, CurPos.X)), MaxLong(CurPos.Y - Size.Y div SCY + 1, MinLong(Delta.Y, CurPos.Y))); end; procedure TEditor.Undo; begin {$IFDEF USE_UNDO} SetNewStatus('Идет откат предыдущей операции...'); if UndoFile <> nil then begin UndoFile^.Undo(@Self); UpdateCommands; end; SetOldStatus; {$ENDIF USE_UNDO} end; procedure TEditor.Unlock; begin if LockCount > 0 then begin Dec(LockCount); if LockCount = 0 then DoUpdate; end; end; procedure TEditor.Update(AFlags: Byte); begin UpdateFlags := UpdateFlags or AFlags; if LockCount = 0 then DoUpdate; end; procedure TEditor.UpdateCommands; begin if not(IsClipboard) then begin SetCmdState(cmCut, HasSelection); SetCmdState(cmCopy, HasSelection); SetCmdState(cmPaste, (Clipboard <> nil) and (Clipboard^.HasSelection)); end; SetCmdState(cmClear, HasSelection); SetCmdState(cmPrint, True); SetCmdState(cmFind, True); SetCmdState(cmReplace, True); SetCmdState(cmSearchAgain, True); SetCmdState(cmSettings, True); SetCmdState(cmFormat, True); SetCmdState(cmFormatNew, True); SetCmdState(cmFormatInt, True); end; function TEditor.Valid(Command: Word): Boolean; begin Valid := IsValid; end; {$I DIALOG.INC} {$UNDEF FROM_EDITOR} end. {Editor}
Там кстати и про SuperVision упоминания есть.
А ещё была "штука" -"редактор шаблонных документов". До сих пор мной не повторённая.
Это когда часть текста - ReadOnly а часть - "поля для заполнения".
Типа "формы ввода".
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/OLD/LONGEDIT.PAS
Ну и "длинный буфер":
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/NEW/LONGBUF.PAS
Исходники иногда "рвут крышу" - типа "данные обращаются к View". Зато они сильно документированы. Я сейчас столько комментариев - не пишу. Даже удивительно, что уогда-то писал.
А вот тут:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLER.PAS
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLER.INC
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLEC.PAS
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/DOSEditors/wEditor/Editor/OE/ALTABLEC.INC
Ещё смешнее - реализация таблиц для Plain-Text редактора.
unit alTableR; interface uses OvcBase, alEditN, alPara, alUndo, alTableC, alEditCo, cChars; type TColumnArray = array [1..MaxColumnCount] of TTableColumn; {=========================================================================} type TTableRow = class(TParaNode) protected {---------------------------------------------------------------------} { добавленные поля } FColumnArray : TColumnArray; FColumnCount : Integer; FTableWidth : Integer; FLeftDelta : Integer; FTree : TParaList; protected {---------------------------------------------------------------------} { методы для работы со свойствами } function GetColumnWidth(i: Integer) : Integer; { - возвращает ширину i-й колонки } procedure SetColumnWidth(i: Integer; Value: Integer); { - устанавливает ширину i-й колонки } procedure SetLeftDelta(Value: Integer); { - устанавливает отступ таблицы } function GetColumn(i : Integer) : TTableColumn; { - возвращает i-ю колонку } procedure SetColumn(i: Integer; Value: TTableColumn); { - присваивает i-ю колонку } public {---------------------------------------------------------------------} { переопределенные методы } function NthLine(N : Integer; var Len : Word) : PChar; override; {-return a pointer to the Nth line of this paragraph; Len is its length} procedure Recalc; override; {-calculate the number of lines in this paragraph given the specified wrap column} function PosToLine(Pos : Integer; var Col : Integer) : Integer; override; {-given a position in the paragraph, return the line and Col} function PEQ(PN: TParaNode): Boolean; override; {-сравнивает параметры двух параграфов на идентичность} function GetHIndent(L : Integer) : Integer; override; {-} {---------------------------------------------------------------------} { переопределенные методы для записи/чтения строки таблицы } procedure StoreParas(OnWrite: TalEditorReadWriteEvent; var Res: LongInt); override; {-сохраняет параметры строки таблицы} constructor LoadParas(OnRead: TalEditorReadWriteEvent; var Res: LongInt); override; {-читает параметры строки таблицы} procedure StoreText(Editor: TOvcBase; OnWrite: TalEditorReadWriteEvent; var Res : LongInt); override; {-сохраняет текст параграфа} procedure LoadText(Editor: TOvcBase; OnRead: TalEditorReadWriteEvent; Count: LongInt; var Res: LongInt); override; {-читает текст параграфа} {---------------------------------------------------------------------} { добавленные методы } constructor Create(aTree: TParaList; aColumnCount, aLeftDelta, aTableWidth,aColumnWidth: Integer); virtual; {-создает новую строку таблицы не заполняя ее ячейками} constructor CreateSame(aTree: TParaList; TR: TTableRow); virtual; {-создает строку таблицы с параметрами как у TR} constructor CreateEmpty(aTree: TParaList; aColumnCount, aTableWidth: Integer); virtual; {-создает пустую строку таблицы заполнив ее ячейками} destructor Destroy; override; {-} function ScreenPosToTable(P : Integer; var TP: TTablePoint): TTableColumn; {-из позиции на экране находит позицию в таблице } function GlobalPosToTable(C: Integer; P : Integer) : Integer; { - из позиции на экране находит позицию в таблице } procedure CorrectScreenPos(var CurLine : LongInt; var CurCol : Integer; var LinePos : Integer); {-поправляет позицию на экране так чтобы она правильно попадала в ячейку таблицы } procedure MoveCaretToPP(C: Integer; Para: LongInt; var Pos: Integer); { - из позиции в таблице - делает позицию на экране } procedure MoveCaretTo(C: Integer; Line: LongInt; var Col: Integer); {-из позиции в таблице - делает позицию на экране } function GetHighlightBorder(BC, EC: Integer; var HBC, HEC: Integer) : Boolean; {-определяет границы колонок которыми ограничено выделение } procedure GetHighlightColumns(Left,Right: Integer; var LeftColumn, RightColumn: Integer); {-возвращает номера колонок выделенных в данной строке таблицы} procedure InsertColumn(C: Integer); {-вставляет новую колонку по номеру C} procedure PlaceColumn(C: Integer; TC: TTableColumn); {-вставляет новую колонку TC по номеру C} procedure DeleteColumn(C: Integer); {-удаляет колонку по номеру C} procedure SwapColumns(C1,C2: Integer); {-меняет колонки местами} {---------------------------------------------------------------------} { свойства } property Tree : TParaList read FTree write FTree; {-дерево параграфов-владелец данной строки таблицы} property Column [i : Integer] : TTableColumn read GetColumn write SetColumn; default; {- i-я ячеека } property ColumnWidth [i : Integer] : Integer read GetColumnWidth write SetColumnWidth; {-ширина i-й колонки } property ColumnCount : Integer read FColumnCount write FColumnCount; {-число колонок } property TableWidth : Integer read FTableWidth write FTableWidth; {-ширина таблицы } property LeftDelta : Integer read FLeftDelta write SetLeftDelta; {-левый отступ таблицы } end; { TTableRow } {=========================================================================} implementation uses alEdit, alParaT, MinMax; {$I altableR.inc } end.
Я уж и забыл, что "такое было".
Под каким-нибудь Lazarus'ом или Delphi1 это даже наверное соберётся.
Комментариев нет:
Отправить комментарий