mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
416 lines
13 KiB
ObjectPascal
416 lines
13 KiB
ObjectPascal
{-------------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: SynExportTeX.pas, released 2002-09-12.
|
|
|
|
The Original Code is partly based on the mwHTMLExport.pas file from the
|
|
mwEdit component suite by Martin Waldenburg and other developers, the Initial
|
|
Author of this file is Ascher Stefan.
|
|
Portions created by Ascher Stefan are Copyright 2002 Ascher Stefan.
|
|
Unicode translation by Maël Hörz.
|
|
All Rights Reserved.
|
|
|
|
Contributors to the SynEdit project are listed in the Contributors.txt file.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of the
|
|
GNU General Public License Version 2 or later (the "GPL"), in which case
|
|
the provisions of the GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms
|
|
of the GPL and not to allow others to use your version of this file
|
|
under the MPL, indicate your decision by deleting the provisions above and
|
|
replace them with the notice and other provisions required by the GPL.
|
|
If you do not delete the provisions above, a recipient may use your version
|
|
of this file under either the MPL or the GPL.
|
|
|
|
$Id: SynExportTeX.pas,v 1.8.2.5 2008/09/14 16:24:59 maelh Exp $
|
|
|
|
You may retrieve the latest version of this file at the SynEdit home page,
|
|
located at http://SynEdit.SourceForge.net
|
|
|
|
Known Issues:
|
|
- LaTeX 2e doesn't support Unicode, so this exporter doesn't either.
|
|
(There are solutions like the package utc.sty but still they don't allow mixing
|
|
of different languages like Arabic and Chinese.
|
|
We'll have to wait for LaTeX 3.)
|
|
-------------------------------------------------------------------------------}
|
|
|
|
{$IFNDEF QSYNEXPORTTEX}
|
|
unit SynExportTeX;
|
|
{$ENDIF}
|
|
|
|
{$I SynEdit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows,
|
|
Graphics,
|
|
SynEditExport,
|
|
SynEditHighlighter,
|
|
SynUnicode,
|
|
Classes;
|
|
|
|
type
|
|
TSynExporterTeX = class(TSynCustomExporter)
|
|
private
|
|
FMargin: Integer;
|
|
FLastAttri: TSynHighlighterAttributes;
|
|
function AttriToCommand(Attri: TSynHighlighterAttributes;
|
|
UniqueAttriName: string): string;
|
|
function AttriToCommandCallback(Highlighter: TSynCustomHighlighter;
|
|
Attri: TSynHighlighterAttributes; UniqueAttriName: string;
|
|
Params: array of Pointer): Boolean;
|
|
function CommandNameCallback(Highlighter: TSynCustomHighlighter;
|
|
Attri: TSynHighlighterAttributes; UniqueAttriName: string;
|
|
Params: array of Pointer): Boolean;
|
|
function GetCommandName(Highlighter: TSynCustomHighlighter;
|
|
Attri: TSynHighlighterAttributes): string;
|
|
function GetNewCommands: string;
|
|
function MakeValidName(Name: string): string;
|
|
protected
|
|
FCreateTeXFragment: Boolean;
|
|
FTabWidth: Integer;
|
|
FPageStyleEmpty: Boolean;
|
|
|
|
// overriding these abstract methods (though they are never called for this
|
|
// specific highlighter) to prevent abstract instance warnings
|
|
procedure FormatAfterLastAttribute; override;
|
|
procedure FormatAttributeDone(BackgroundChanged: Boolean;
|
|
ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
|
|
procedure FormatAttributeInit(BackgroundChanged: Boolean;
|
|
ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
|
|
procedure FormatBeforeFirstAttribute(BackgroundChanged: Boolean;
|
|
ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
|
|
|
|
procedure FormatNewLine; override;
|
|
procedure FormatToken(Token: UnicodeString); override;
|
|
function GetFooter: UnicodeString; override;
|
|
function GetFormatName: string; override;
|
|
function GetHeader: UnicodeString; override;
|
|
function ReplaceReservedChar(AChar: WideChar): UnicodeString; override;
|
|
procedure SetTokenAttribute(Attri: TSynHighlighterAttributes); override;
|
|
function UseBom: Boolean; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
function SupportedEncodings: TSynEncodings; override;
|
|
published
|
|
property Margin: Integer read FMargin write FMargin default 2;
|
|
property TabWidth: Integer read FTabWidth write FTabWidth default 2;
|
|
property Color;
|
|
property CreateTeXFragment: Boolean read FCreateTeXFragment
|
|
write FCreateTeXFragment default false;
|
|
property PageStyleEmpty: Boolean read FPageStyleEmpty write FPageStyleEmpty
|
|
default false;
|
|
property DefaultFilter;
|
|
property Encoding;
|
|
property Font;
|
|
property Highlighter;
|
|
property Title;
|
|
property UseBackground;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SynEditMiscProcs,
|
|
SynEditStrConst,
|
|
SysUtils;
|
|
|
|
|
|
// DotDecSepFormat always formats with a dot as decimal separator.
|
|
// This is necessary because LaTeX expects a dot, but VCL's Format is
|
|
// language-dependent, i.e. with another locale set, the separator can be
|
|
// different (for example a comma).
|
|
function DotDecSepFormat(const Format: string; const Args: array of const): string;
|
|
var
|
|
{$IFDEF UNICODE}
|
|
OldDecimalSeparator: WideChar;
|
|
{$ELSE}
|
|
OldDecimalSeparator: AnsiChar;
|
|
{$ENDIF}
|
|
begin
|
|
OldDecimalSeparator := {$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator;
|
|
{$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator := '.';
|
|
Result := SysUtils.Format(Format, Args);
|
|
{$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator;
|
|
end;
|
|
|
|
function ColorToTeX(AColor: TColor): string;
|
|
const
|
|
f = '%1.2g';
|
|
f2 = '%s,%s,%s';
|
|
var
|
|
RGBColor: LongWord;
|
|
RValue, GValue, BValue: string;
|
|
begin
|
|
RGBColor := ColorToRGB(AColor);
|
|
RValue := DotDecSepFormat(f, [GetRValue(RGBColor) / 255]);
|
|
GValue := DotDecSepFormat(f, [GetGValue(RGBColor) / 255]);
|
|
BValue := DotDecSepFormat(f, [GetBValue(RGBColor) / 255]);
|
|
Result := Format(f2, [RValue, GValue, BValue]);
|
|
end;
|
|
|
|
{ TSynExporterTeX }
|
|
|
|
constructor TSynExporterTeX.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FMargin := 2;
|
|
FTabWidth := 2;
|
|
FPageStyleEmpty := False;
|
|
FDefaultFilter := SYNS_FilterTeX;
|
|
FEncoding := seAnsi;
|
|
end;
|
|
|
|
function TSynExporterTeX.AttriToCommandCallback(
|
|
Highlighter: TSynCustomHighlighter; Attri: TSynHighlighterAttributes;
|
|
UniqueAttriName: string; Params: array of Pointer): Boolean;
|
|
var
|
|
Commands: ^string;
|
|
begin
|
|
Commands := Params[0];
|
|
Commands^ := Commands^ + AttriToCommand(Attri, UniqueAttriName) + SLineBreak;
|
|
Result := True; // we want all attributes => tell EnumHighlighterAttris to continue
|
|
end;
|
|
|
|
function TSynExporterTeX.AttriToCommand(Attri: TSynHighlighterAttributes;
|
|
UniqueAttriName: string): string;
|
|
const
|
|
NewCommand = '\newcommand{\%s}[1]{%s#1%s}';
|
|
SBold = '\textbf{';
|
|
SItalic = '\textit{';
|
|
SUnderline = '\uln{';
|
|
SColor = '\textcolor[rgb]{%s}{';
|
|
SBackColor = '\colorbox[rgb]{%s}{';
|
|
var
|
|
Formatting: string;
|
|
BracketCount: Integer;
|
|
begin
|
|
BracketCount := 0;
|
|
with Attri do
|
|
begin
|
|
if fsBold in Style then
|
|
begin
|
|
Formatting := Formatting + SBold;
|
|
Inc(BracketCount);
|
|
end;
|
|
if fsItalic in Style then
|
|
begin
|
|
Formatting := Formatting + SItalic;
|
|
Inc(BracketCount);
|
|
end;
|
|
if fsUnderline in Style then
|
|
begin
|
|
Formatting := Formatting + SUnderline;
|
|
Inc(BracketCount);
|
|
end;
|
|
if (Foreground <> clBlack) and (Foreground <> clNone) then
|
|
begin
|
|
Formatting := Formatting + Format(SColor, [ColorToTeX(Foreground)]);
|
|
Inc(BracketCount);
|
|
end;
|
|
if fUseBackground and (Background <> clNone) then
|
|
begin
|
|
Formatting := Formatting + Format(SBackColor, [ColorToTeX(Background)]);
|
|
Inc(BracketCount);
|
|
end;
|
|
Result := Format(NewCommand, [MakeValidName(UniqueAttriName), Formatting,
|
|
StringOfChar('}', BracketCount)])
|
|
end;
|
|
end;
|
|
|
|
function TSynExporterTeX.CommandNameCallback(
|
|
Highlighter: TSynCustomHighlighter; Attri: TSynHighlighterAttributes;
|
|
UniqueAttriName: string; Params: array of Pointer): Boolean;
|
|
var
|
|
AttriToFind: TSynHighlighterAttributes;
|
|
CommandName: ^string;
|
|
begin
|
|
AttriToFind := Params[0];
|
|
CommandName := Params[1];
|
|
|
|
if Attri = AttriToFind then
|
|
begin
|
|
CommandName^ := MakeValidName(UniqueAttriName);
|
|
Result := False; // found => inform EnumHighlighterAttris to stop searching
|
|
end
|
|
else
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TSynExporterTeX.FormatToken(Token: UnicodeString);
|
|
var
|
|
CommandName: string;
|
|
begin
|
|
CommandName := GetCommandName(Highlighter, FLastAttri);
|
|
AddData('\' + CommandName + '{' + Token + '}');
|
|
end;
|
|
|
|
procedure TSynExporterTeX.FormatNewLine;
|
|
begin
|
|
AddData('\\' + SLineBreak);
|
|
end;
|
|
|
|
// do nothing with these
|
|
procedure TSynExporterTeX.FormatAfterLastAttribute;
|
|
begin
|
|
end;
|
|
|
|
procedure TSynExporterTeX.FormatAttributeDone;
|
|
begin
|
|
end;
|
|
|
|
procedure TSynExporterTeX.FormatAttributeInit;
|
|
begin
|
|
end;
|
|
|
|
procedure TSynExporterTeX.FormatBeforeFirstAttribute;
|
|
begin
|
|
end;
|
|
|
|
function TSynExporterTeX.GetCommandName(Highlighter: TSynCustomHighlighter;
|
|
Attri: TSynHighlighterAttributes): string;
|
|
begin
|
|
EnumHighlighterAttris(Highlighter, False, CommandNameCallback, [Attri, @Result]);
|
|
end;
|
|
|
|
function TSynExporterTeX.GetFooter: UnicodeString;
|
|
begin
|
|
if not FCreateTeXFragment then
|
|
Result := SLineBreak + '\end{ttfamily}' + SLineBreak + '\end{document}'
|
|
else
|
|
Result := SLineBreak + '\end{ttfamily}';
|
|
end;
|
|
|
|
function TSynExporterTeX.GetFormatName: string;
|
|
begin
|
|
Result := SYNS_ExporterFormatTeX;
|
|
end;
|
|
|
|
function TSynExporterTeX.GetHeader: UnicodeString;
|
|
const
|
|
TeXHeader = '\documentclass[a4paper, %dpt]{article}' + SLineBreak +
|
|
'\usepackage[a4paper, margin=%dcm]{geometry}' + SLineBreak +
|
|
'\usepackage[T1]{fontenc}' + SLineBreak +
|
|
'\usepackage{color}' + SLineBreak +
|
|
'\usepackage{alltt}' + SLineBreak +
|
|
'\usepackage{times}' + SLineBreak +
|
|
'\usepackage{ulem}' + SLineBreak +
|
|
{$IFDEF WIN32}
|
|
// It is recommennded to use AnsiNew on Windows
|
|
'\usepackage[ansinew]{inputenc}' + SLineBreak +
|
|
{$ELSE}
|
|
// and Latin1 on UNIX Systems, see also DE FAQ 8.5.3
|
|
'\usepackage[latin1]{inputenc}' + SLineBreak +
|
|
{$ENDIF}
|
|
'%s' + SLineBreak; // New Commands
|
|
TeXHeader2 = '%% Generated by SynEdit TeX exporter' + SLineBreak + SLineBreak +
|
|
'\begin{document}';
|
|
EmptyPage = '\pagestyle{empty}';
|
|
TeXDocument = '\begin{ttfamily}' + SLineBreak +
|
|
'\noindent' + SLineBreak;
|
|
var
|
|
PageStyle: string;
|
|
begin
|
|
if not FCreateTeXFragment then
|
|
begin
|
|
if FPageStyleEmpty then
|
|
PageStyle := SLineBreak + EmptyPage
|
|
else
|
|
PageStyle := '';
|
|
Result := Format(TeXHeader + SLineBreak + SLineBreak,
|
|
[Font.Size, FMargin, GetNewCommands]);
|
|
Result := Result + '\title{' + Title + '}' + SLineBreak + TeXHeader2 +
|
|
SLineBreak + PageStyle;
|
|
end;
|
|
Result := Result + TeXDocument;
|
|
end;
|
|
|
|
function TSynExporterTeX.GetNewCommands: string;
|
|
const
|
|
FixedCommands = '%% Special Characters' + SLineBreak +
|
|
'\newcommand\SPC{\hspace*{0.6em}}' + SLineBreak +
|
|
'\newcommand\TAB{\hspace*{%sem}}' + SLineBreak +
|
|
'\newcommand\BS{\mbox{\char 92}}' + SLineBreak + // Backslash
|
|
'\newcommand\TLD{\mbox{\char 126}}' + SLineBreak + // ~
|
|
'\newcommand\CIR{\mbox{\char 94}}' + SLineBreak + // ^
|
|
'\newcommand\HYP{\mbox{\char 45}}' + SLineBreak + // a simple -
|
|
'\newcommand\QOT{\mbox{\char 34}}' + SLineBreak + // "
|
|
'\newcommand{\uln}[1]{\bgroup \markoverwith{\hbox{\_}}\ULon{{#1}}}' + SLineBreak +
|
|
'%% Highlighter Attributes' + SLineBreak;
|
|
f = '%1.1g';
|
|
var
|
|
tw: string;
|
|
Commands: string;
|
|
begin
|
|
tw := DotDecSepFormat(f, [FTabWidth * 0.6]);
|
|
Result := Format(FixedCommands, [tw]);
|
|
|
|
EnumHighlighterAttris(Highlighter, True, AttriToCommandCallback, [@Commands]);
|
|
Result := Result + Commands;
|
|
end;
|
|
|
|
function TSynExporterTeX.MakeValidName(Name: string): string;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := Name;
|
|
|
|
for i := Length(Result) downto 1 do
|
|
if CharInSet(Result[i], ['1'..'9']) then
|
|
Result[i] := Char(Ord('A') + Ord(Result[i]) - Ord('1'))
|
|
else if Result[i] = '0' then
|
|
Result[i] := 'Z'
|
|
else if not CharInSet(Result[i], ['a'..'z', 'A'..'Z']) then
|
|
Delete(Result, i, 1);
|
|
end;
|
|
|
|
function TSynExporterTeX.ReplaceReservedChar(AChar: WideChar): UnicodeString;
|
|
begin
|
|
case AChar of
|
|
'{': Result := '\{';
|
|
'}': Result := '\}';
|
|
'\': Result := '\BS ';
|
|
'~': Result := '\TLD ';
|
|
'^': Result := '\CIR ';
|
|
' ': Result := '\SPC ';
|
|
#9: Result := '\TAB ';
|
|
'-': Result := '\HYP ';
|
|
'"': Result := '\QOT ';
|
|
'@': Result := '$@$';
|
|
'$': Result := '\$';
|
|
'&': Result := '\&';
|
|
'<': Result := '$<$';
|
|
'>': Result := '$>$';
|
|
'_': Result := '\_';
|
|
'#': Result := '\#';
|
|
'%': Result := '\%';
|
|
else Result := '';
|
|
end;
|
|
end;
|
|
|
|
procedure TSynExporterTeX.SetTokenAttribute(Attri: TSynHighlighterAttributes);
|
|
begin
|
|
FLastAttri := Attri;
|
|
end;
|
|
|
|
function TSynExporterTeX.SupportedEncodings: TSynEncodings;
|
|
begin
|
|
Result := [seAnsi];
|
|
end;
|
|
|
|
function TSynExporterTeX.UseBom: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
end.
|
|
|