syneditwordwrap.pas

来自「一个mwEdit控件原码,比mwCuuEdit0.92a功能先进.」· PAS 代码 · 共 588 行 · 第 1/2 页

PAS
588
字号
    Inc( fLineCount, aCount ); // fLineCount must be updated before calling MoveLines()
    MoveLines( aIndex, aCount );
  end
  else
    Inc( fLineCount, aCount ); 
  // set offset to same as previous line (i.e. the line has 0 rows)
  if aIndex = 0 then
    vPrevOffset := 0
  else
    vPrevOffset := fLineOffsets[ aIndex -1 ];
  for cLine := aIndex to aIndex + aCount -1 do
    fLineOffsets[cLine] := vPrevOffset;
  // Rewrap.
  if (RowCount - fLineOffsets[aIndex]) * aCount > RowCount * 5 then
  begin
    // This rudimentary optimization-wannabe tries to decide whether it's worth to
    // use ReWrapLine() since this may move the tail rowlengths too many times.
    WrapLines;
    Result := RowCount - aIndex +1;
  end
  else begin
    Result := 0;
    for cLine := aIndex to aIndex + aCount -1 do
      Inc( Result, ReWrapLine(cLine) );
  end;
end;

function TSynWordWrapPlugin.LinesPutted(aIndex: integer; aCount: integer): integer;
var
  cLine: integer;
begin
  if fMaxRowLength = 0 then
  begin
    Result := 0;
    Exit;
  end;
  Assert( aIndex >= 0 );
  Assert( aCount >= 1 );
  Assert( aIndex + aCount <= LineCount );
  //
  if (RowCount - fLineOffsets[aIndex]) * aCount > RowCount * 5 then
  begin
    WrapLines;
    Result := RowCount - aIndex +1;
  end
  else begin
    Result := 0;
    for cLine := aIndex to aIndex + aCount -1 do
      Inc( Result, ReWrapLine(cLine) );
  end;
end;

procedure TSynWordWrapPlugin.MoveLines(aStart: TLineIndex; aMoveBy: integer);
var
  vMoveCount: integer;
begin
  Assert( aMoveBy <> 0 );
  Assert( aStart + aMoveBy >= 0 );
  Assert( aStart + aMoveBy < LineCount );
  vMoveCount := LineCount - aStart;
  if aMoveBy > 0 then
    Dec( vMoveCount, aMoveBy );
  Move( fLineOffsets[aStart], fLineOffsets[aStart + aMoveBy],
    vMoveCount * SizeOf(TRowIndex) );
end;

procedure TSynWordWrapPlugin.MoveRows(aStart: TRowIndex; aMoveBy: integer);
var
  vMoveCount: integer;
begin
  Assert( aMoveBy <> 0 );
  Assert( aStart + aMoveBy >= 0 );
  Assert( aStart + aMoveBy < RowCount );
  vMoveCount := RowCount - aStart;
  if aMoveBy > 0 then
    Dec( vMoveCount, aMoveBy );
  Move( fRowLengths[aStart], fRowLengths[aStart + aMoveBy],
    vMoveCount * SizeOf(TRowLength) );
end;

procedure TSynWordWrapPlugin.Reset;
begin
  Assert( Editor.CharsInWindow >= 0 );

  fMaxRowLength := Editor.CharsInWindow;
  fMinRowLength := Editor.CharsInWindow - (Editor.CharsInWindow div 3);
  fBreakChars :=  [#0..#255] - Editor.IdentChars;

  if fMinRowLength <= 0 then
    fMinRowLength := 1;

  WrapLines;
end;

function TSynWordWrapPlugin.ReWrapLine(aIndex: TLineIndex): integer;
// Returns RowCount delta (how many wrapped lines were added or removed by this change).
var
  vMaxNewRows: cardinal;
  vLine: string;
  vLineRowCount: integer; //numbers of rows parsed in this line
  vTempRowLengths: PRowLengthArray;
  vRowBegin: PChar;
  vLineEnd: PChar;
  vRowEnd: PChar;
  vRunner: PChar;
  vRowMinEnd: PChar;
  //
  vStartRow: integer; // first row of the line
  vOldNextRow: integer; // first row of the next line, before the change
  cLine: integer;
begin
  // ****** First parse the new string using an auxiliar array *****
  vLine := TSynEditStringList(Editor.Lines).ExpandedStrings[ aIndex ];
  // Pre-allocate a buffer for rowlengths
  vMaxNewRows := ( (Length(vLine) -1) div fMinRowLength ) + 1;
  vTempRowLengths := AllocMem( vMaxNewRows );
  try
    vLineRowCount := 0;
    vRowBegin := PChar( vLine );
    vRowEnd := vRowBegin + fMaxRowLength;
    vLineEnd := vRowBegin + Length(vLine);
    while vRowEnd < vLineEnd do
    begin
      //
      if vRowEnd^ in [#32,#9] then
      begin
        repeat
          Inc( vRowEnd );
        until not( vRowEnd^ in [#32,#9] );
      end
      else begin
        vRowMinEnd := vRowBegin + fMinRowLength;
        vRunner := vRowEnd -1;
        while vRunner > vRowMinEnd do
        begin
          if vRunner^ in fBreakChars then
          begin
            vRowEnd := vRunner +1;
            break;
          end;
          Dec( vRunner );
        end;
      end;
      // Check TRowLength overflow
      if vRowEnd - vRowBegin > High(TRowLength) then
      begin
        vRowEnd := vRowBegin + High(TRowLength);
        vRowMinEnd := vRowEnd - ( High(TRowLength) mod Editor.TabWidth );
        while (vRowEnd^ = #9) and (vRowEnd > vRowMinEnd) do
          Dec( vRowEnd );
      end;
      // Finally store the rowlength
      vTempRowLengths[ vLineRowCount ] := vRowEnd - vRowBegin;
      //
      Inc( vLineRowCount );
      vRowBegin := vRowEnd;
      Inc( vRowEnd, fMaxRowLength );
    end;
    vTempRowLengths[ vLineRowCount ] := vLineEnd - vRowBegin;
    Inc( vLineRowCount );

    // ****** Then updates the main arrays ******
    if aIndex = 0 then
      vStartRow := 0
    else
      vStartRow := fLineOffsets[ aIndex -1 ];
    vOldNextRow := fLineOffsets[aIndex];
    Result := vLineRowCount - (vOldNextRow - vStartRow);
    if Result <> 0 then
    begin
      // MoveRows depends on RowCount, so we need some special processing...
      if Result > 0 then
      begin
        // ...if growing, update offsets (and thus RowCount) before rowlengths
        GrowRows( RowCount + Result );
        for cLine := aIndex to LineCount -1 do
          Inc( fLineOffsets[cLine], Result );
        if vOldNextRow < RowCount - Result then
          MoveRows( vOldNextRow, Result );
      end
      else begin
        // ...if shrinking, update offsets after rowlengths
        if vOldNextRow < RowCount then
          MoveRows( vOldNextRow, Result );
        for cLine := aIndex to LineCount -1 do
          Inc( fLineOffsets[cLine], Result );
      end;
    end;
    Move( vTempRowLengths[0], fRowLengths[vStartRow], vLineRowCount * SizeOf(TRowLength) );
  finally
    FreeMem( vTempRowLengths );
  end;
end;

procedure TSynWordWrapPlugin.WrapLines;
var
  cRow: integer;
  cLine: integer;
  vLine: string;
  vMaxNewRows: integer;
  vRowBegin: PChar;
  vLineEnd: PChar;
  vRowEnd: PChar;
  vRunner: PChar;
  vRowMinEnd: PChar;
begin
  if (Editor.Lines.Count = 0) or (fMaxRowLength <= 0) then
  begin
    SetEmpty;
    Exit;
  end;

  GrowLines( Editor.Lines.Count );
  GrowRows( Editor.Lines.Count );
  //
  cRow := 0;
  for cLine := 0 to Editor.Lines.Count -1 do
  begin
    vLine := TSynEditStringList(Editor.Lines).ExpandedStrings[ cLine ];
    //
    vMaxNewRows := ( (Length(vLine) -1) div fMinRowLength ) + 1;
    GrowRows( cRow + vMaxNewRows );
    //
    vRowBegin := PChar( vLine );
    vRowEnd := vRowBegin + fMaxRowLength;
    vLineEnd := vRowBegin + Length(vLine);
    while vRowEnd < vLineEnd do
    begin
      //
      if vRowEnd^ in [#32,#9] then
      begin
        repeat
          Inc( vRowEnd );
        until not( vRowEnd^ in [#32,#9] );
      end
      else begin
        vRowMinEnd := vRowBegin + fMinRowLength;
        vRunner := vRowEnd -1;
        while vRunner > vRowMinEnd do
        begin
          if vRunner^ in fBreakChars then
          begin
            vRowEnd := vRunner +1;
            break;
          end;
          Dec( vRunner );
        end;
      end;
      //
      if vRowEnd - vRowBegin > High(TRowLength) then
      begin
        vRowEnd := vRowBegin + High(TRowLength);
        vRowMinEnd := vRowEnd - ( High(TRowLength) mod Editor.TabWidth );
        while (vRowEnd^ = #9) and (vRowEnd > vRowMinEnd) do
          Dec( vRowEnd );
      end;
      fRowLengths[ cRow ] := vRowEnd - vRowBegin;
      //
      Inc( cRow );
      vRowBegin := vRowEnd;
      Inc( vRowEnd, fMaxRowLength );
    end;
    fRowLengths[ cRow ] := vLineEnd - vRowBegin;
    Inc( cRow );
    fLineOffsets[ cLine ] := cRow;
  end;
  fLineCount := Editor.Lines.Count;
end;

function TSynWordWrapPlugin.RowCount: integer;
begin
  if LineCount > 0 then
    Result := fLineOffsets[ LineCount -1 ]
  else
    Result := 0;
end;

procedure TSynWordWrapPlugin.SetEmpty;
begin
  fLineCount := 0;
  // free unsused memory
  TrimArrays;
end;

procedure TSynWordWrapPlugin.TrimArrays;
begin
  ReallocMem( fLineOffsets, LineCount );
  fLineCapacity := LineCount;
  ReallocMem( fRowLengths, RowCount );
  fRowCapacity := RowCount;
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?