瀏覽代碼

Syntax highlighting for generated code

Source commit: 63384395e3955017600d4574d8e41e0e0f54ac41
Martin Prikryl 9 年之前
父節點
當前提交
7e337a0dad
共有 6 個文件被更改,包括 253 次插入96 次删除
  1. 64 0
      source/core/Common.cpp
  2. 10 0
      source/core/Common.h
  3. 69 58
      source/core/SessionData.cpp
  4. 106 34
      source/forms/GenerateUrl.cpp
  5. 2 3
      source/forms/GenerateUrl.dfm
  6. 2 1
      source/forms/GenerateUrl.h

+ 64 - 0
source/core/Common.cpp

@@ -645,6 +645,7 @@ UnicodeString __fastcall ExpandFileNameCommand(const UnicodeString Command,
 //---------------------------------------------------------------------------
 UnicodeString __fastcall EscapeParam(const UnicodeString & Param)
 {
+  // Make sure this won't break RTF syntax
   return ReplaceStr(Param, L"\"", L"\"\"");
 }
 //---------------------------------------------------------------------------
@@ -2887,3 +2888,66 @@ bool __fastcall IsHttpUrl(const UnicodeString & S)
 {
   return SameText(S.SubString(1, 4), L"http");
 }
+//---------------------------------------------------------------------------
+const UnicodeString RtfPara = L"\\par\n";
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfColor(int Index)
+{
+  return FORMAT(L"\\cf%d", (Index));
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfText(const UnicodeString & Text)
+{
+  UnicodeString Result = Text;
+  int Index = 1;
+  while (Index <= Result.Length())
+  {
+    UnicodeString Replacement;
+    wchar_t Ch = Result[Index];
+    if ((Ch == L'\\') || (Ch == L'{') || (Ch == L'}'))
+    {
+      Replacement = FORMAT(L"\\%s", (Ch));
+    }
+    else if (Ch >= 0x0080)
+    {
+      Replacement = FORMAT(L"\\u%d?", (int(Ch)));
+    }
+
+    if (!Replacement.IsEmpty())
+    {
+      Result.Delete(Index, 1);
+      Result.Insert(Replacement, Index);
+      Index += Replacement.Length();
+    }
+    else
+    {
+      Index++;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfColorText(int Color, const UnicodeString & Text)
+{
+  return RtfColor(Color) + L" " + RtfText(Text) + RtfColor(0) + L" ";
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfColorItalicText(int Color, const UnicodeString & Text)
+{
+  return RtfColor(Color) + L"\\i " + RtfText(Text) + L"\\i0" + RtfColor(0) + L" ";
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfKeyword(const UnicodeString & Text)
+{
+  return RtfColorText(4, Text);
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfParameter(const UnicodeString & Text)
+{
+  return RtfColorText(5, Text);
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfString(const UnicodeString & Text)
+{
+  return RtfColorText(3, Text);
+}

+ 10 - 0
source/core/Common.h

@@ -199,6 +199,16 @@ MethodT __fastcall MakeMethod(void * Data, void * Code)
   return Method;
 }
 //---------------------------------------------------------------------------
+extern const UnicodeString RtfPara;
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfText(const UnicodeString & Text);
+UnicodeString __fastcall RtfColor(int Index);
+UnicodeString __fastcall RtfColorItalicText(int Color, const UnicodeString & Text);
+UnicodeString __fastcall RtfColorText(int Color, const UnicodeString & Text);
+UnicodeString __fastcall RtfKeyword(const UnicodeString & Text);
+UnicodeString __fastcall RtfParameter(const UnicodeString & Text);
+UnicodeString __fastcall RtfString(const UnicodeString & Text);
+//---------------------------------------------------------------------------
 #include "Global.h"
 //---------------------------------------------------------------------------
 template<class T>

+ 69 - 58
source/core/SessionData.cpp

@@ -2524,22 +2524,23 @@ UnicodeString __fastcall TSessionData::GenerateSessionUrl(unsigned int Flags)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Switch)
 {
-  Result += FORMAT(L" -%s", (Switch));
+  Result += RtfText(L" ") + RtfParameter(FORMAT(L"-%s", (Switch)));
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddSwitchValue(UnicodeString & Result, const UnicodeString & Name, const UnicodeString & Value)
 {
-  AddSwitch(Result, FORMAT(L"%s=%s", (Name, Value)));
+  AddSwitch(Result, Name);
+  Result += L"=" + Value;
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Name, const UnicodeString & Value)
 {
-  AddSwitchValue(Result, Name, FORMAT("\"%s\"", (EscapeParam(Value))));
+  AddSwitchValue(Result, Name, RtfString(FORMAT("\"%s\"", (EscapeParam(Value)))));
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Name, int Value)
 {
-  AddSwitchValue(Result, Name, IntToStr(Value));
+  AddSwitchValue(Result, Name, RtfText(IntToStr(Value)));
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::LookupLastFingerprint()
@@ -2560,6 +2561,16 @@ void __fastcall TSessionData::LookupLastFingerprint()
   }
 }
 //---------------------------------------------------------------------
+static UnicodeString __fastcall RtfCodeComment(const UnicodeString & Text)
+{
+  return RtfColorItalicText(1, Text);
+}
+//---------------------------------------------------------------------
+static UnicodeString __fastcall RtfClass(const UnicodeString & Text)
+{
+  return RtfColorText(2, Text);
+}
+//---------------------------------------------------------------------
 UnicodeString __fastcall TSessionData::GenerateOpenCommandArgs()
 {
   std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
@@ -2647,15 +2658,15 @@ void __fastcall TSessionData::AddAssemblyProperty(
   switch (Language)
   {
     case alCSharp:
-      PropertyCode = L"    %s = %s.%s,\n";
+      PropertyCode = RtfText(L"    %s = ") + RtfClass("%s") + RtfText(L".%s,") + RtfPara;
       break;
 
     case alVBNET:
-      PropertyCode = L"    .%s = %s.%s\n";
+      PropertyCode = RtfText(L"    .%s = ") + RtfClass("%s") + RtfText(L".%s") + RtfPara;
       break;
 
     case alPowerShell:
-      PropertyCode = L"$sessionOptions.%s = [WinSCP.%s]::%s\n";
+      PropertyCode = RtfText(L"$sessionOptions.%s = [WinSCP.") + RtfClass("%s") + RtfText(L"]::%s") + RtfPara;
       break;
   }
 
@@ -2690,7 +2701,7 @@ UnicodeString __fastcall TSessionData::AssemblyString(TAssemblyLanguage Language
       break;
   }
 
-  return S;
+  return RtfString(S);
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddAssemblyPropertyRaw(
@@ -2702,15 +2713,15 @@ void __fastcall TSessionData::AddAssemblyPropertyRaw(
   switch (Language)
   {
     case alCSharp:
-      PropertyCode = L"    %s = %s,\n";
+      PropertyCode = RtfText(L"    %s = %s,") + RtfPara;
       break;
 
     case alVBNET:
-      PropertyCode = L"    .%s = %s\n";
+      PropertyCode = RtfText(L"    .%s = %s") + RtfPara;
       break;
 
     case alPowerShell:
-      PropertyCode = L"$sessionOptions.%s = %s\n";
+      PropertyCode = RtfText(L"$sessionOptions.%s = %s") + RtfPara;
       break;
   }
 
@@ -2768,25 +2779,25 @@ UnicodeString __fastcall TSessionData::GenerateAssemblyCode(
   {
     case alCSharp:
       SessionOptionsPreamble =
-        L"// %s\n"
-         "SessionOptions sessionOptions = new SessionOptions\n"
-         "{\n";
+        RtfCodeComment(L"// %s") + RtfPara +
+        RtfClass(L"SessionOptions") + RtfText(L" sessionOptions = ") + RtfKeyword(L"new") + RtfText(" ") + RtfClass(L"SessionOptions") + RtfPara +
+        RtfText(L"{") + RtfPara;
       break;
 
     case alVBNET:
       SessionOptionsPreamble =
-        L"' %s\n"
-         "Dim mySessionOptions As New SessionOptions\n"
-         "With mySessionOptions\n";
+        RtfCodeComment(L"' %s") + RtfPara +
+        RtfKeyword(L"Dim") + RtfText(" mySessionOptions ") + RtfKeyword(L"As") + RtfText(L" ") + RtfKeyword(L"New") + RtfText(" ") + RtfClass(L"SessionOptions") + RtfPara +
+        RtfKeyword(L"With") + RtfText(" mySessionOptions") + RtfPara;
       break;
 
     case alPowerShell:
       SessionOptionsPreamble =
-        FORMAT(L"# %s\n", (LoadStr(CODE_PS_ADD_TYPE))) +
-        L"Add-Type -Path \"WinSCPnet.dll\"\n"
-         "\n"
-         "# %s\n"
-         "$sessionOptions = New-Object WinSCP.SessionOptions\n";
+        RtfCodeComment(FORMAT(L"# %s", (LoadStr(CODE_PS_ADD_TYPE)))) + RtfPara +
+        RtfKeyword(L"Add-Type") + RtfText(" -Path ") + AssemblyString(Language, "WinSCPnet.dll") + RtfPara +
+        RtfPara +
+        RtfCodeComment(L"# %s") + RtfPara +
+        RtfText(L"$sessionOptions = ") + RtfKeyword(L"New-Object") + RtfText(" WinSCP.") + RtfClass(L"SessionOptions") + RtfPara;
       break;
 
     default:
@@ -2930,7 +2941,7 @@ UnicodeString __fastcall TSessionData::GenerateAssemblyCode(
   switch (Language)
   {
     case alCSharp:
-      Result += L"};\n";
+      Result += RtfText(L"};") + RtfPara;
       break;
 
     case alVBNET:
@@ -2943,7 +2954,7 @@ UnicodeString __fastcall TSessionData::GenerateAssemblyCode(
 
   if (RawSettings->Count > 0)
   {
-    Result += L"\n";
+    Result += RtfPara;
 
     for (int Index = 0; Index < RawSettings->Count; Index++)
     {
@@ -2953,18 +2964,18 @@ UnicodeString __fastcall TSessionData::GenerateAssemblyCode(
       switch (Language)
       {
         case alCSharp:
-          SettingsCode = L"sessionOptions.AddRawSettings(\"%s\", %s);\n";
+          SettingsCode = RtfText(L"sessionOptions.AddRawSettings(%s, %s);") + RtfPara;
           break;
 
         case alVBNET:
-          SettingsCode = L"    .AddRawSettings(\"%s\", %s)\n";
+          SettingsCode = RtfText(L"    .AddRawSettings(%s, %s)") + RtfPara;
           break;
 
         case alPowerShell:
-          SettingsCode = L"$sessionOptions.AddRawSettings(\"%s\", %s)\n";
+          SettingsCode = RtfText(L"$sessionOptions.AddRawSettings(%s, %s)") + RtfPara;
           break;
       }
-      Result += FORMAT(SettingsCode, (Name, AssemblyString(Language, Value)));
+      Result += FORMAT(SettingsCode, (AssemblyString(Language, Name), AssemblyString(Language, Value)));
     }
   }
 
@@ -2974,44 +2985,44 @@ UnicodeString __fastcall TSessionData::GenerateAssemblyCode(
   {
     case alCSharp:
       SessionCode =
-        L"\n"
-         "using (Session session = new Session())\n"
-         "{\n"
-         "    // %s\n"
-         "    session.Open(sessionOptions);\n"
-         "\n"
-         "    // %s\n"
-         "}\n";
+        RtfPara +
+        RtfKeyword(L"using") + RtfText(" (") + RtfClass(L"Session") + RtfText(L" session = ") + RtfKeyword(L"new") + RtfText(" ") + RtfClass(L"Session") + RtfText(L"())") + RtfPara +
+        RtfText(L"{") + RtfPara +
+        RtfCodeComment(L"    // %s") + RtfPara +
+        RtfText(L"    session.Open(sessionOptions);") + RtfPara +
+        RtfPara +
+        RtfCodeComment(L"    // %s") + RtfPara +
+        RtfText(L"}") + RtfPara;
       break;
 
     case alVBNET:
       SessionCode =
-        L"End With\n"
-         "\n"
-         "Using mySession As Session = New Session\n"
-         "    ' %s\n"
-         "    mySession.Open(mySessionOptions)\n"
-         "\n"
-         "    ' %s\n"
-         "End Using\n";
+        RtfKeyword(L"End With") + RtfPara +
+        RtfPara +
+        RtfKeyword(L"Using") + RtfText(" mySession As ") + RtfClass(L"Session") + RtfText(L" = ") + RtfKeyword(L"New") + RtfText(" ") + RtfClass(L"Session") + RtfPara +
+        RtfCodeComment(L"    ' %s") + RtfPara +
+        RtfText(L"    mySession.Open(mySessionOptions)") + RtfPara +
+        RtfPara +
+        RtfCodeComment(L"    ' %s") + RtfPara +
+        RtfKeyword(L"End Using");
       break;
 
     case alPowerShell:
       SessionCode =
-        L"\n"
-         "$session = New-Object WinSCP.Session\n"
-         "\n"
-         "try\n"
-         "{\n"
-         "    # %s\n"
-         "    $session.Open($sessionOptions)\n"
-         "\n"
-         "    # %s\n"
-         "}\n"
-         "finally\n"
-         "{\n"
-         "    $session.Dispose()\n"
-         "}\n";
+        RtfPara +
+        RtfText(L"$session = ") + RtfKeyword(L"New-Object") + RtfText(" WinSCP.") + RtfClass(L"Session") + RtfPara +
+        RtfPara +
+        RtfKeyword(L"try") + RtfPara +
+        RtfText(L"{") + RtfPara +
+        RtfCodeComment(L"    # %s") + RtfPara +
+        RtfText(L"    $session.Open($sessionOptions)") + RtfPara +
+        RtfPara +
+        RtfCodeComment(L"    # %s") + RtfPara +
+        RtfText(L"}") + RtfPara +
+        RtfKeyword(L"finally") + RtfPara +
+        RtfText(L"{") + RtfPara +
+        RtfText(L"    $session.Dispose()") + RtfPara +
+        RtfText(L"}") + RtfPara;
       break;
   }
 

+ 106 - 34
source/forms/GenerateUrl.cpp

@@ -66,6 +66,16 @@ UnicodeString __fastcall TGenerateUrlDialog::GenerateUrl(UnicodeString Path)
   return Url;
 }
 //---------------------------------------------------------------------------
+static UnicodeString __fastcall RtfColorEntry(int Color)
+{
+  return FORMAT(L"\\red%d\\green%d\\blue%d;", ((Color & 0xFF0000) >> 16, (Color & 0x00FF00) >> 8, (Color & 0x0000FF) >> 0));
+}
+//---------------------------------------------------------------------
+static UnicodeString __fastcall RtfScriptComment(const UnicodeString & Text)
+{
+  return RtfColorItalicText(6, Text);
+}
+//---------------------------------------------------------------------------
 void __fastcall TGenerateUrlDialog::UpdateControls()
 {
   if (!FChanging)
@@ -124,6 +134,7 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
 
     bool WordWrap = false;
     bool FixedWidth = false;
+    FPlainResult = L"";
     if (OptionsPageControl->ActivePage == UrlSheet)
     {
       if (!IsFileUrl())
@@ -133,13 +144,19 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
         {
           Path += L"/";
         }
-        Result = GenerateUrl(Path);
+        FPlainResult = GenerateUrl(Path);
+        Result = RtfText(FPlainResult);
       }
       else
       {
         for (int Index = 0; Index < FPaths->Count; Index++)
         {
-          Result += GenerateUrl(FPaths->Strings[Index]) + L"\n";
+          UnicodeString Url = GenerateUrl(FPaths->Strings[Index]);
+          Result += RtfText(Url) + RtfPara;
+          FPlainResult +=
+            Url +
+            // What CopyToClipboard would have done could we pass in ResultMemo->Lines
+            ((FPaths->Count > 0) ? L"\n" : L"");
         }
       }
       WordWrap = true;
@@ -155,12 +172,12 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
       {
         Result =
           FORMAT(
-            L"open %s\n"
-             "\n"
-             "; %s\n"
-             "; %s\n"
-             "\n"
-             "exit\n",
+            RtfKeyword(L"open") + L" %s" + RtfPara +
+            RtfPara +
+            RtfScriptComment("; %s") + RtfPara +
+            RtfScriptComment("; %s") + RtfPara +
+            RtfPara +
+            RtfKeyword(L"exit") + RtfPara,
             (OpenCommand, CommandPlaceholder1, CommandPlaceholder2));
         WordWrap = false;
         FixedWidth = true;
@@ -170,33 +187,35 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
         UnicodeString ComExeName = ChangeFileExt(ExeName, L".com");
 
         Result =
-          FORMAT(
-            L"@echo off\n"
-             "\n"
-             "\"%s\" /log=%s.log /ini=nul /command ^\n"
-             "  \"open %s\" ^\n"
-             "  \"%s\" ^\n"
-             "  \"%s\" ^\n"
-             "  \"exit\"\n"
-             "\n"
-             "set WINSCP_RESULT=%%ERRORLEVEL%%\n"
-             "if %%WINSCP_RESULT%% equ 0 (\n"
-             "  echo Success\n"
-             ") else (\n"
-             "  echo Error\n"
-             ")\n"
-             "\n"
-             "exit /b %%WINSCP_RESULT%%\n",
-             (ComExeName, BaseExeName, EscapeParam(ReplaceStr(OpenCommand, L"%", L"%%")), CommandPlaceholder1, CommandPlaceholder2));
+          RtfScriptComment(L"@echo off") + RtfPara +
+          RtfPara +
+          RtfText(L"\"" + ComExeName + "\" ") + RtfParameter(L"/log") + RtfText(L"=" + BaseExeName + L".log ") + RtfParameter(L"/ini") + RtfText(L"=nul ") + RtfParameter(L"/command") + RtfText(L" ^") + RtfPara +
+          RtfText(L"  \"") + RtfKeyword(L"open") + RtfText(L" ") + EscapeParam(ReplaceStr(OpenCommand, L"%", L"%%")) + RtfText(L"\" ^") + RtfPara +
+          RtfText(L"  \"") + RtfScriptComment(CommandPlaceholder1) + RtfText(L"\" ^") + RtfPara +
+          RtfText(L"  \"") + RtfScriptComment(CommandPlaceholder2) + RtfText(L"\" ^") + RtfPara +
+          RtfText(L"  \"") + RtfKeyword(L"exit") + RtfText(L"\"") + RtfPara +
+          RtfPara +
+          RtfKeyword(L"set") + RtfText(L" WINSCP_RESULT=%ERRORLEVEL%") + RtfPara +
+          RtfKeyword(L"if") + RtfText(L" %WINSCP_RESULT% ") + RtfKeyword(L"equ") + RtfText(L" 0 (") + RtfPara +
+          RtfText(L"  ") + RtfKeyword(L"echo") + RtfText(L" Success") + RtfPara +
+          RtfText(L") ") + RtfKeyword(L"else") + RtfText(L" (") + RtfPara +
+          RtfText(L"  ") + RtfKeyword(L"echo") + RtfText(L" Error") + RtfPara +
+          RtfText(L")") + RtfPara +
+          RtfPara +
+          RtfKeyword(L"exit") + RtfText(L" /b %WINSCP_RESULT%") + RtfPara;
         WordWrap = false;
         FixedWidth = true;
       }
       else if (ScriptFormatCombo->ItemIndex == sfCommandLine)
       {
         Result =
-          FORMAT(
-            L"/log=%s.log /ini=nul /command \"open %s\" \"%s\" \"%s\" \"exit\"",
-            (BaseExeName, EscapeParam(OpenCommand), CommandPlaceholder1, CommandPlaceholder2));
+          RtfParameter(L"/log") + RtfText(L"=" + BaseExeName + L".log ") +
+          RtfParameter(L"/ini") + RtfText(L"=nul ") +
+          RtfParameter(L"/command") + RtfText(L" ") +
+            RtfText(L"\"") + RtfKeyword(L"open") + RtfText(L" ") + EscapeParam(OpenCommand) + RtfText(L"\" ") +
+            RtfText(L"\"") + RtfScriptComment(CommandPlaceholder1) + RtfText(L"\" ") +
+            RtfText(L"\"") + RtfScriptComment(CommandPlaceholder2) + RtfText(L"\" ") +
+            RtfText(L"\"") + RtfKeyword(L"exit") + RtfText(L"\"");
         WordWrap = true;
         FixedWidth = false;
       }
@@ -208,18 +227,44 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
       FixedWidth = true;
     }
 
-    ResultMemo->WordWrap = WordWrap;
-    ResultMemo->ScrollBars = WordWrap ? ssVertical : ssBoth;
-    ResultMemo->Lines->Text = Result;
-
     if (FixedWidth)
     {
       ResultMemo->Font->Name = CustomWinConfiguration->DefaultFixedWidthFontName;
+      ResultMemo->DefAttributes->Color = clWindowText;
     }
     else
     {
       ResultMemo->ParentFont = true;
     }
+
+    Result =
+      L"{\\rtf1\n"
+       "{\\colortbl ;" +
+       // The same RGB as on wiki
+       RtfColorEntry(0x008000) + // cde comment (green)
+       RtfColorEntry(0x008080) + // class (teal)
+       RtfColorEntry(0x800000) + // string (maroon)
+       RtfColorEntry(0x0000FF) + // keyword (blue)
+       RtfColorEntry(0x993333) + // command-line argument (reddish)
+       RtfColorEntry(0x808080) + // script command (gray)
+      L"}\n"
+       "{\\fonttbl{\\f0\\fnil\\fcharset0 " + ResultMemo->Font->Name + L";}}\n"
+       "\\f0\\fs" + IntToStr(ResultMemo->Font->Size * 2) + L" " +
+       Result +
+      L"}";
+
+    ResultMemo->WordWrap = WordWrap;
+    ResultMemo->ScrollBars = WordWrap ? ssVertical : ssBoth;
+
+    std::unique_ptr<TMemoryStream> Stream(new TMemoryStream());
+    UTF8String ResultUtf = Result;
+    Stream->Write(ResultUtf.c_str(), ResultUtf.Length());
+    Stream->Position = 0;
+
+    Stream->SaveToFile(L"b:\\rtf\\code.rtf");
+    Stream->Position = 0;
+
+    ResultMemo->Lines->LoadFromStream(Stream.get(), TEncoding::UTF8);
   }
 }
 //---------------------------------------------------------------------------
@@ -334,7 +379,34 @@ void __fastcall TGenerateUrlDialog::ControlChange(TObject * /*Sender*/)
 void __fastcall TGenerateUrlDialog::ClipboardButtonClick(TObject * /*Sender*/)
 {
   TInstantOperationVisualizer Visualizer;
-  CopyToClipboard(ResultMemo->Lines);
+  if (ResultMemo->WordWrap)
+  {
+    // Cannot read the text from ResultMemo->Lines as TRichEdit (as opposite to TMemo)
+    // breaks wrapped lines
+
+    if (!FPlainResult.IsEmpty())
+    {
+      CopyToClipboard(FPlainResult);
+    }
+    else
+    {
+      // We get here with command-line only,
+      // where we know to have a single line only
+      DebugAssert((OptionsPageControl->ActivePage == ScriptSheet) && (ScriptFormatCombo->ItemIndex == sfCommandLine));
+      UnicodeString Text;
+      for (int Index = 0; Index < ResultMemo->Lines->Count; Index++)
+      {
+        Text += ResultMemo->Lines->Strings[Index];
+      }
+      CopyToClipboard(Text);
+    }
+  }
+  else
+  {
+    // On the other hand, the FResult contains RTF markup
+    // in which case we want to use ResultMemo->Lines
+    CopyToClipboard(ResultMemo->Lines);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TGenerateUrlDialog::HelpButtonClick(TObject * /*Sender*/)

+ 2 - 3
source/forms/GenerateUrl.dfm

@@ -172,7 +172,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
     DesignSize = (
       468
       176)
-    object ResultMemo: TMemo
+    object ResultMemo: TRichEdit
       Left = 7
       Top = 15
       Width = 454
@@ -182,10 +182,9 @@ object GenerateUrlDialog: TGenerateUrlDialog
       BevelInner = bvNone
       BevelOuter = bvNone
       BorderStyle = bsNone
-      Lines.Strings = (
-        'ResultMemo')
       ScrollBars = ssVertical
       TabOrder = 0
+      Zoom = 100
     end
   end
   object CancelBtn: TButton

+ 2 - 1
source/forms/GenerateUrl.h

@@ -14,7 +14,7 @@ class TGenerateUrlDialog : public TForm
 {
 __published:
   TGroupBox *ResultGroup;
-  TMemo *ResultMemo;
+  TRichEdit *ResultMemo;
   TButton *CancelBtn;
   TButton *HelpButton;
   TButton *ClipboardButton;
@@ -43,6 +43,7 @@ private:
   TSessionData * FData;
   TStrings * FPaths;
   bool FChanging;
+  UnicodeString FPlainResult;
 
 protected:
   void __fastcall UpdateControls();