diff --git a/FileMonitor.cs b/FileMonitor.cs index b9f01bb..04410ee 100644 --- a/FileMonitor.cs +++ b/FileMonitor.cs @@ -1,50 +1,45 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Threading; using System.IO; - +using System.Threading; namespace MEditor { - public class FileMonitor { - private int TimeoutMillis = 2000; + private readonly int TimeoutMillis = 2000; - System.IO.FileSystemWatcher fsw = new System.IO.FileSystemWatcher(); - System.Threading.Timer m_timer = null; - List files = new List(); - FileSystemEventHandler fswHandler = null; + private readonly List files = new List(); + private readonly FileSystemEventHandler fswHandler; + private readonly Timer m_timer; + private FileSystemWatcher fsw = new FileSystemWatcher(); public FileMonitor(FileSystemEventHandler watchHandler) { - m_timer = new System.Threading.Timer(new TimerCallback(OnTimer), null, Timeout.Infinite, Timeout.Infinite); + m_timer = new Timer(OnTimer, null, Timeout.Infinite, Timeout.Infinite); fswHandler = watchHandler; - } public FileMonitor(FileSystemEventHandler watchHandler, int timerInterval) { - m_timer = new System.Threading.Timer(new TimerCallback(OnTimer), null, Timeout.Infinite, Timeout.Infinite); + m_timer = new Timer(OnTimer, null, Timeout.Infinite, Timeout.Infinite); TimeoutMillis = timerInterval; fswHandler = watchHandler; - } - public void Add(string dir,string filter) + public void Add(string dir, string filter) { - System.IO.FileSystemWatcher fsw = new System.IO.FileSystemWatcher(dir, filter); - fsw.NotifyFilter = System.IO.NotifyFilters.LastWrite; - fsw.Changed += new FileSystemEventHandler(OnFileChanged); + var fsw = new FileSystemWatcher(dir, filter); + fsw.NotifyFilter = NotifyFilters.LastWrite; + fsw.Changed += OnFileChanged; fsw.EnableRaisingEvents = true; } public void OnFileChanged(object sender, FileSystemEventArgs e) { //MessageBox.Show("Created", "Create triggered"); - Mutex mutex = new Mutex(false, "FSW"); + var mutex = new Mutex(false, "FSW"); mutex.WaitOne(); if (!files.Contains(e.FullPath)) { @@ -57,9 +52,9 @@ public void OnFileChanged(object sender, FileSystemEventArgs e) private void OnTimer(object state) { - List backup = new List(); + var backup = new List(); - Mutex mutex = new Mutex(false, "FSW"); + var mutex = new Mutex(false, "FSW"); mutex.WaitOne(); backup.AddRange(files); files.Clear(); @@ -70,7 +65,6 @@ private void OnTimer(object state) { fswHandler(this, new FileSystemEventArgs(WatcherChangeTypes.Changed, string.Empty, file)); } - } } -} +} \ No newline at end of file diff --git a/FileTypeRegister.cs b/FileTypeRegister.cs index 8106d3c..c074acd 100644 --- a/FileTypeRegister.cs +++ b/FileTypeRegister.cs @@ -1,190 +1,194 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.Win32; -namespace MEditor -{ - public class FileTypeRegInfo - { - /// - /// 目标类型文件的扩展名 - /// - public string ExtendName; //".xcf" - - /// - /// 目标文件类型说明 - /// - public string Description; //"XCodeFactory项目文件" - - /// - /// 目标类型文件关联的图标 - /// - public string IcoPath; - - /// - /// 打开目标类型文件的应用程序 - /// - public string ExePath; - - public FileTypeRegInfo() - { - } - - public FileTypeRegInfo(string extendName) - { - this.ExtendName = extendName; - } - } - /// - /// FileTypeRegister 用于注册自定义的文件类型。 - /// zhuweisky 2005.08.31 - /// - public class FileTypeRegister - { - #region RegisterFileType - /// - /// RegisterFileType 使文件类型与对应的图标及应用程序关联起来。 - /// - public static bool Register(FileTypeRegInfo regInfo) - { - if (CheckIfRegistered(regInfo.ExtendName)) - { - return true; - } - try - { - string relationName = regInfo.ExtendName.Substring(1, regInfo.ExtendName.Length - 1).ToUpper() + "_FileType"; - - RegistryKey fileTypeKey = Registry.ClassesRoot.CreateSubKey(regInfo.ExtendName); - fileTypeKey.SetValue("", relationName); - fileTypeKey.Close(); - - RegistryKey relationKey = Registry.ClassesRoot.CreateSubKey(relationName); - relationKey.SetValue("", regInfo.Description); - - RegistryKey iconKey = relationKey.CreateSubKey("DefaultIcon"); - iconKey.SetValue("", regInfo.IcoPath); - - RegistryKey shellKey = relationKey.CreateSubKey("Shell"); - RegistryKey openKey = shellKey.CreateSubKey("Open"); - RegistryKey commandKey = openKey.CreateSubKey("Command"); - commandKey.SetValue("", regInfo.ExePath + " %1"); - - relationKey.Close(); - return true; - } - catch{ - return false; - } - } - - /// - /// RegisterFileType 使文件类型与对应的图标及应用程序关联起来。 - /// - public static bool UnRegister(string extendName) - { - if (!CheckIfRegistered(extendName)) - { - return true; - } - - string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType"; - try - { - Registry.ClassesRoot.DeleteSubKeyTree(extendName); - Registry.ClassesRoot.DeleteSubKeyTree(relationName); - return true; - } - catch(Exception e) - { - //System.Windows.Forms.MessageBox.Show(e.Message); - return false; - } - } - - - /// - /// GetFileTypeRegInfo 得到指定文件类型关联信息 - /// - public static FileTypeRegInfo GetRegInfo(string extendName) - { - if (!CheckIfRegistered(extendName)) - { - return null; - } - - FileTypeRegInfo regInfo = new FileTypeRegInfo(extendName); - try - { - string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType"; - RegistryKey relationKey = Registry.ClassesRoot.OpenSubKey(relationName); - regInfo.Description = relationKey.GetValue("").ToString(); - - RegistryKey iconKey = relationKey.OpenSubKey("DefaultIcon"); - regInfo.IcoPath = iconKey.GetValue("").ToString(); - - RegistryKey shellKey = relationKey.OpenSubKey("Shell"); - RegistryKey openKey = shellKey.OpenSubKey("Open"); - RegistryKey commandKey = openKey.OpenSubKey("Command"); - string temp = commandKey.GetValue("").ToString(); - regInfo.ExePath = temp.Substring(0, temp.Length - 3); - - return regInfo; - } - catch - { - return null; - } - } - - /// - /// UpdateFileTypeRegInfo 更新指定文件类型关联信息 - /// - public static bool UpdateRegInfo(FileTypeRegInfo regInfo) - { - if (!CheckIfRegistered(regInfo.ExtendName)) - { - return false; - } - - try - { - string extendName = regInfo.ExtendName; - string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType"; - RegistryKey relationKey = Registry.ClassesRoot.OpenSubKey(relationName, true); - relationKey.SetValue("", regInfo.Description); - - RegistryKey iconKey = relationKey.OpenSubKey("DefaultIcon", true); - iconKey.SetValue("", regInfo.IcoPath); - - RegistryKey shellKey = relationKey.OpenSubKey("Shell"); - RegistryKey openKey = shellKey.OpenSubKey("Open"); - RegistryKey commandKey = openKey.OpenSubKey("Command", true); - commandKey.SetValue("", regInfo.ExePath + " %1"); - - relationKey.Close(); - - return true; - } - catch - { - return false; - } - } - - /// - /// FileTypeRegistered 指定文件类型是否已经注册 - /// - public static bool CheckIfRegistered(string extendName) - { - RegistryKey softwareKey = Registry.ClassesRoot.OpenSubKey(extendName); - if (softwareKey != null) - { - return true; - } - - return false; - } - #endregion - } +using System; +using Microsoft.Win32; + +namespace MEditor +{ + public class FileTypeRegInfo + { + /// + /// 目标文件类型说明 + /// + public string Description; //"XCodeFactory项目文件" + + /// + /// 打开目标类型文件的应用程序 + /// + public string ExePath; + + /// + /// 目标类型文件的扩展名 + /// + public string ExtendName; //".xcf" + + /// + /// 目标类型文件关联的图标 + /// + public string IcoPath; + + public FileTypeRegInfo() + { + } + + public FileTypeRegInfo(string extendName) + { + ExtendName = extendName; + } + } + + /// + /// FileTypeRegister 用于注册自定义的文件类型。 + /// zhuweisky 2005.08.31 + /// + public class FileTypeRegister + { + #region RegisterFileType + + /// + /// RegisterFileType 使文件类型与对应的图标及应用程序关联起来。 + /// + public static bool Register(FileTypeRegInfo regInfo) + { + if (CheckIfRegistered(regInfo.ExtendName)) + { + return true; + } + try + { + string relationName = regInfo.ExtendName.Substring(1, regInfo.ExtendName.Length - 1).ToUpper() + + "_FileType"; + + RegistryKey fileTypeKey = Registry.ClassesRoot.CreateSubKey(regInfo.ExtendName); + fileTypeKey.SetValue("", relationName); + fileTypeKey.Close(); + + RegistryKey relationKey = Registry.ClassesRoot.CreateSubKey(relationName); + relationKey.SetValue("", regInfo.Description); + + RegistryKey iconKey = relationKey.CreateSubKey("DefaultIcon"); + iconKey.SetValue("", regInfo.IcoPath); + + RegistryKey shellKey = relationKey.CreateSubKey("Shell"); + RegistryKey openKey = shellKey.CreateSubKey("Open"); + RegistryKey commandKey = openKey.CreateSubKey("Command"); + commandKey.SetValue("", regInfo.ExePath + " %1"); + + relationKey.Close(); + return true; + } + catch + { + return false; + } + } + + /// + /// RegisterFileType 使文件类型与对应的图标及应用程序关联起来。 + /// + public static bool UnRegister(string extendName) + { + if (!CheckIfRegistered(extendName)) + { + return true; + } + + string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType"; + try + { + Registry.ClassesRoot.DeleteSubKeyTree(extendName); + Registry.ClassesRoot.DeleteSubKeyTree(relationName); + return true; + } + catch (Exception e) + { + //System.Windows.Forms.MessageBox.Show(e.Message); + return false; + } + } + + + /// + /// GetFileTypeRegInfo 得到指定文件类型关联信息 + /// + public static FileTypeRegInfo GetRegInfo(string extendName) + { + if (!CheckIfRegistered(extendName)) + { + return null; + } + + var regInfo = new FileTypeRegInfo(extendName); + try + { + string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType"; + RegistryKey relationKey = Registry.ClassesRoot.OpenSubKey(relationName); + regInfo.Description = relationKey.GetValue("").ToString(); + + RegistryKey iconKey = relationKey.OpenSubKey("DefaultIcon"); + regInfo.IcoPath = iconKey.GetValue("").ToString(); + + RegistryKey shellKey = relationKey.OpenSubKey("Shell"); + RegistryKey openKey = shellKey.OpenSubKey("Open"); + RegistryKey commandKey = openKey.OpenSubKey("Command"); + string temp = commandKey.GetValue("").ToString(); + regInfo.ExePath = temp.Substring(0, temp.Length - 3); + + return regInfo; + } + catch + { + return null; + } + } + + /// + /// UpdateFileTypeRegInfo 更新指定文件类型关联信息 + /// + public static bool UpdateRegInfo(FileTypeRegInfo regInfo) + { + if (!CheckIfRegistered(regInfo.ExtendName)) + { + return false; + } + + try + { + string extendName = regInfo.ExtendName; + string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType"; + RegistryKey relationKey = Registry.ClassesRoot.OpenSubKey(relationName, true); + relationKey.SetValue("", regInfo.Description); + + RegistryKey iconKey = relationKey.OpenSubKey("DefaultIcon", true); + iconKey.SetValue("", regInfo.IcoPath); + + RegistryKey shellKey = relationKey.OpenSubKey("Shell"); + RegistryKey openKey = shellKey.OpenSubKey("Open"); + RegistryKey commandKey = openKey.OpenSubKey("Command", true); + commandKey.SetValue("", regInfo.ExePath + " %1"); + + relationKey.Close(); + + return true; + } + catch + { + return false; + } + } + + /// + /// FileTypeRegistered 指定文件类型是否已经注册 + /// + public static bool CheckIfRegistered(string extendName) + { + RegistryKey softwareKey = Registry.ClassesRoot.OpenSubKey(extendName); + if (softwareKey != null) + { + return true; + } + + return false; + } + + #endregion + } } \ No newline at end of file diff --git a/GoTo.cs b/GoTo.cs index 66a3ed5..10d4eb7 100644 --- a/GoTo.cs +++ b/GoTo.cs @@ -1,58 +1,51 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; using System.Windows.Forms; - using ICSharpCode.AvalonEdit; namespace MEditor { - [System.ComponentModel.DesignerCategory("form")] - public partial class GoToLineDialog : Form - { - public int LineNumber - { - get - { - int line = 0; - Int32.TryParse(lnbox.Text, out line); - return line; - } - } - - //Instance of the control passed via 2nd Constructor - private TextEditor RichTextBoxControl; - - //Secondary Constructor (Used) - - public GoToLineDialog(TextEditor RTB) - { - RichTextBoxControl = RTB; - InitializeComponent(); - } - - - - void Go(object sender, EventArgs e) - { - if (LineNumber > 0 && LineNumber <= RichTextBoxControl.Document.LineCount) - { - RichTextBoxControl.ScrollToLine(LineNumber); - this.DialogResult = DialogResult.OK; - - } - else - MessageBox.Show("MEditor不能转到指定行。", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - this.Close(); - } - - private void button1_Click(object sender, EventArgs e) - { - this.DialogResult = DialogResult.OK; - this.Close(); - } - } -} + [DesignerCategory("form")] + public partial class GoToLineDialog : Form + { + //Instance of the control passed via 2nd Constructor + private readonly TextEditor RichTextBoxControl; + + //Secondary Constructor (Used) + + public GoToLineDialog(TextEditor RTB) + { + RichTextBoxControl = RTB; + InitializeComponent(); + } + + public int LineNumber + { + get + { + int line = 0; + Int32.TryParse(lnbox.Text, out line); + return line; + } + } + + + private void Go(object sender, EventArgs e) + { + if (LineNumber > 0 && LineNumber <= RichTextBoxControl.Document.LineCount) + { + RichTextBoxControl.ScrollToLine(LineNumber); + DialogResult = DialogResult.OK; + } + else + MessageBox.Show("MEditor不能转到指定行。", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + Close(); + } + + private void button1_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + } +} \ No newline at end of file diff --git a/MDEditor.csproj b/MDEditor.csproj index 82fcc78..f3c7fa5 100644 --- a/MDEditor.csproj +++ b/MDEditor.csproj @@ -32,8 +32,18 @@ TRACE prompt 4 + x86 + + False + libs\Awesomium.Core.dll + + + False + libs\Awesomium.Windows.Controls.dll + + False libs\ICSharpCode.AvalonEdit.dll @@ -98,8 +108,6 @@ - - @@ -112,6 +120,13 @@ True True + + + Form + + + TestSundown.cs + frmMain.cs @@ -127,6 +142,9 @@ Resources.resx True + + TestSundown.cs + @@ -148,7 +166,20 @@ + + + + Always + + + + + Always + + + Always + frmCss.cs Designer diff --git a/MDEditor.csproj.DotSettings b/MDEditor.csproj.DotSettings new file mode 100644 index 0000000..b35dc7e --- /dev/null +++ b/MDEditor.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/MEditor.sln b/MEditor.sln index 51a9382..600235e 100644 --- a/MEditor.sln +++ b/MEditor.sln @@ -1,19 +1,40 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -# SharpDevelop 4.2.1.8805 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MDEditor", "MDEditor.csproj", "{8210A400-6151-45D5-B344-57934E4292F9}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SundownLib", "..\SundownLib\SundownLib.vcxproj", "{4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8210A400-6151-45D5-B344-57934E4292F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8210A400-6151-45D5-B344-57934E4292F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8210A400-6151-45D5-B344-57934E4292F9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8210A400-6151-45D5-B344-57934E4292F9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8210A400-6151-45D5-B344-57934E4292F9}.Debug|Win32.ActiveCfg = Debug|Any CPU {8210A400-6151-45D5-B344-57934E4292F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {8210A400-6151-45D5-B344-57934E4292F9}.Release|Any CPU.Build.0 = Release|Any CPU + {8210A400-6151-45D5-B344-57934E4292F9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8210A400-6151-45D5-B344-57934E4292F9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8210A400-6151-45D5-B344-57934E4292F9}.Release|Win32.ActiveCfg = Release|Any CPU + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Debug|Win32.Build.0 = Debug|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Release|Any CPU.ActiveCfg = Release|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Release|Mixed Platforms.Build.0 = Release|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Release|Win32.ActiveCfg = Release|Win32 + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MEditor.suo b/MEditor.suo index f43efb5..51de83e 100644 Binary files a/MEditor.suo and b/MEditor.suo differ diff --git a/MRUManager.cs b/MRUManager.cs index cf55606..b566811 100644 --- a/MRUManager.cs +++ b/MRUManager.cs @@ -81,8 +81,8 @@ MRU list is kept in namespace MRU { /// - /// Interface which should be implemented by owner form - /// to use MRUManager. + /// Interface which should be implemented by owner form + /// to use MRUManager. /// public interface IMRUClient { @@ -90,8 +90,8 @@ public interface IMRUClient } /// - /// MRU manager - manages Most Recently Used Files list - /// for Windows Form application. + /// MRU manager - manages Most Recently Used Files list + /// for Windows Form application. /// public class MRUManager { @@ -141,9 +141,8 @@ public MRUManager() #region Public Properties /// - /// Maximum length of displayed file name in menu (default is 40). - /// - /// Set this property to change default value (optional). + /// Maximum length of displayed file name in menu (default is 40). + /// Set this property to change default value (optional). /// public int MaxDisplayNameLength { @@ -159,9 +158,8 @@ public int MaxDisplayNameLength } /// - /// Maximum length of MRU list (default is 10). - /// - /// Set this property to change default value (optional). + /// Maximum length of MRU list (default is 10). + /// Set this property to change default value (optional). /// public int MaxMRULength { @@ -179,13 +177,11 @@ public int MaxMRULength } /// - /// Set current directory. - /// - /// Default value is program current directory which is set when - /// Initialize function is called. - /// - /// Set this property to change default value (optional) - /// after call to Initialize. + /// Set current directory. + /// Default value is program current directory which is set when + /// Initialize function is called. + /// Set this property to change default value (optional) + /// after call to Initialize. /// public string CurrentDir { @@ -199,7 +195,7 @@ public string CurrentDir #region Public Functions /// - /// Initialization. Call this function in form Load handler. + /// Initialization. Call this function in form Load handler. /// /// Owner form /// Recent Files menu item @@ -218,7 +214,7 @@ public void Initialize(Form owner, ToolStripMenuItem mruPar, ToolStripMenuItem m // keep reference to MRU menu item menuItemMRU = mruItem; - menuItemParent = mruPar; + menuItemParent = mruPar; // keep Registry path adding MRU key to it registryPath = regPath; @@ -242,9 +238,9 @@ public void Initialize(Form owner, ToolStripMenuItem mruPar, ToolStripMenuItem m } /// - /// Add file name to MRU list. - /// Call this function when file is opened successfully. - /// If file already exists in the list, it is moved to the first place. + /// Add file name to MRU list. + /// Call this function when file is opened successfully. + /// If file already exists in the list, it is moved to the first place. /// /// File Name public void Add(string file) @@ -261,8 +257,8 @@ public void Add(string file) } /// - /// Remove file name from MRU list. - /// Call this function when File - Open operation failed. + /// Remove file name from MRU list. + /// Call this function when File - Open operation failed. /// /// File Name public void Remove(string file) @@ -289,7 +285,7 @@ public void Remove(string file) #region Event Handlers /// - /// Update MRU list when MRU menu item parent is opened + /// Update MRU list when MRU menu item parent is opened /// /// /// @@ -324,7 +320,7 @@ private void OnMRUParentPopup(object sender, EventArgs e) } /// - /// MRU menu item is clicked - call owner's OpenMRUFile function + /// MRU menu item is clicked - call owner's OpenMRUFile function /// /// /// @@ -351,7 +347,7 @@ private void OnMRUClicked(object sender, EventArgs e) } /// - /// Save MRU list in Registry when owner form is closing + /// Save MRU list in Registry when owner form is closing /// /// /// @@ -389,8 +385,8 @@ private void OnOwnerClosing(object sender, CancelEventArgs e) #region Private Functions /// - /// Load MRU list from Registry. - /// Called from Initialize. + /// Load MRU list from Registry. + /// Called from Initialize. /// private void LoadMRU() { @@ -426,7 +422,7 @@ private void LoadMRU() } /// - /// Get display file name from full name. + /// Get display file name from full name. /// /// Full file name /// Short display name @@ -442,12 +438,10 @@ private string GetDisplayName(string fullName) } /// - /// Truncate a path to fit within a certain number of characters - /// by replacing path components with ellipses. - /// - /// This solution is provided by CodeProject and GotDotNet C# expert - /// Richard Deeming. - /// + /// Truncate a path to fit within a certain number of characters + /// by replacing path components with ellipses. + /// This solution is provided by CodeProject and GotDotNet C# expert + /// Richard Deeming. /// /// Long file name /// Maximum length diff --git a/MarkdownEditor.cs b/MarkdownEditor.cs index 380b891..b282707 100644 --- a/MarkdownEditor.cs +++ b/MarkdownEditor.cs @@ -1,317 +1,206 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using System.Windows.Forms.Integration; -using System.Windows.Input; - +using Awesomium.Core; +using Awesomium.Windows.Forms; using ICSharpCode.AvalonEdit; +using DragDropEffects = System.Windows.DragDropEffects; +using DragEventArgs = System.Windows.DragEventArgs; namespace MEditor { - public class MarkdownEditor - { - - private WebBrowser _previewBrowser; - - - private bool alreadyUpdate = false; - private bool _isOpen = false; - - public bool AlreadyUpdate - { - get { return alreadyUpdate; } - set { alreadyUpdate = value; } - } - - private string _file = ""; - - public string FileName - { - get { return _file; } - set { _file = value; } - } - private frmMain _thisForm; - - private TextEditor _markdownRtb; - // private RichTextBox _htmlRtb; - - private TabPage _markdownPage; - - public TabPage MarkdownPage - { - get { return _markdownPage; } - set { _markdownPage = value; } - } - public MarkdownEditor(frmMain thisform, TabPage page,WebBrowser preview) - { - this._markdownPage = page; - this._thisForm = thisform; - this._previewBrowser=preview; - - createRTB(ref _markdownRtb); - _markdownRtb.TextChanged += new EventHandler(_markdownRtb_TextChanged); - ElementHost elementHost = new ElementHost(); - elementHost.Child=_markdownRtb; - elementHost.Dock=DockStyle.Fill; - page.Controls.Add(elementHost); - - - } - - private void createRTB(ref TextEditor htmlRtb) - { - htmlRtb = new TextEditor(); - //_htmlRtb.BackColor = bg ; - //_htmlRtb.ForeColor =fore; -// htmlRtb.WordWrap = false; - htmlRtb.AllowDrop = false; -// htmlRtb.ScrollBars = RichTextBoxScrollBars.Both; - //htmlRtb.Dock = DockStyle.Fill; - - htmlRtb.TabIndex = 0; - -// htmlRtb.AcceptsTab = true; -// htmlRtb.BulletIndent = 4; -// htmlRtb.DetectUrls = false; - -// htmlRtb.ZoomFactor = 1.0f; -// -// htmlRtb.EnableAutoDragDrop = false; -// htmlRtb.HideSelection = true; - - int lef = 60;// (int)getfontWeight(4, font); -// htmlRtb.SelectionTabs = new int[] { lef, lef * 2, lef * 3, lef * 3, lef * 4 }; - //htmlRtb.TabIndent=4; - - - htmlRtb.AllowDrop = true; - //htmlRtb.KeyDown+=new System.Windows.Input.KeyEventHandler(htmlRtb_KeyDown); - htmlRtb.TextChanged+= _markdownRtb_TextChanged; - - htmlRtb.DragEnter += new System.Windows.DragEventHandler(htmlRtb_DragEnter); - htmlRtb.Drop += new System.Windows.DragEventHandler(htmlRtb_DragDrop); - - - - } - - void htmlRtb_DragDrop(object sender, System.Windows.DragEventArgs e) - { - Array arrayFileName = (Array)e.Data.GetData(DataFormats.FileDrop); - - string strFileName = arrayFileName.GetValue(0).ToString(); - - - string[] data = (string[])e.Data.GetData(DataFormats.FileDrop); - _thisForm.openfiles(data); - - } - - void htmlRtb_DragEnter(object sender, System.Windows.DragEventArgs e) - { - - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - e.Effects = System.Windows.DragDropEffects.Link; - } - else - { - e.Effects = System.Windows.DragDropEffects.None; - } - - } - - void htmlRtb_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) - { - TextEditor rtb = ((TextEditor)sender); - if (e.KeyStates == Keyboard.GetKeyStates(Key.V) && Keyboard.Modifiers == ModifierKeys.Control) - { - rtb.Paste(); - e.Handled = true; - return; - } - - if (e.KeyStates == Keyboard.GetKeyStates(Key.Tab)) - return; - - if (e.KeyStates == Keyboard.GetKeyStates(Key.LeftShift)) - { - //如果特择了多行,则每行前加入一个\t - string text = rtb.SelectedText; - - int st = rtb.SelectionStart; - int st1 = rtb.Text.LastIndexOf("\n", st); - st1 = st1 > -1 ? st1 : 0; - int olen = rtb.SelectionLength; - int len = st - st1 + rtb.SelectionLength; - rtb.SelectionStart = st1; - rtb.SelectionLength = len; - text = rtb.SelectedText; - - text = text.Replace("\n\t", "\n"); - - rtb.SelectedText = text; - rtb.SelectionStart = st + 1; - len=olen + text.Length - len - 1; - if(len>0) - rtb.SelectionLength = len; - } - else - { - //如果特择了多行,则每行前加入一个\t - string text = rtb.SelectedText; - if (text.IndexOf("\n") != -1) - { - int st = rtb.SelectionStart; - if (st > 0) - { - int st1 = rtb.Text.LastIndexOf("\n", st); - st1 = st1 > -1 ? st1 : 0; - int olen = rtb.SelectionLength; - int len = st - st1 + rtb.SelectionLength; - rtb.SelectionStart = st1; - rtb.SelectionLength = len; - text = rtb.SelectedText; - //text = rtb.Text.Substring(st1, len ); - - text = text.Replace("\n", "\n\t"); - rtb.SelectedText = text; - rtb.SelectionStart = st + 1; - rtb.SelectionLength = olen + text.Length - len - 1; - } - - } - else - { - //rtb.SelectedText = " "; - return; - } - } - - e.Handled = true; - } - - public TextEditor GetTextBox() - { - return _markdownRtb; - } - - void _markdownRtb_TextChanged(object sender, EventArgs e) - { - - //_previewBrowser.DocumentText=Utils.ConvertTextToHTML(_markdownRtb.Text); - invokeScript("loadMarkdown", Utils.ConvertTextToHTML(_markdownRtb.Text)); - } - - public string GetMarkdown() - { - return _markdownRtb.Text; - } - - - - public void invokeScript(string scriptName, string html) - { - - try - { - this._previewBrowser.Document.InvokeScript(scriptName, new string[] { html }); - } - catch (COMException) - { - string text = Utils.AppendValidHTMLTags(html, "", true); - this._previewBrowser.DocumentText=text; - } - - } - - - - - public bool Openfile(string file) - { - string text = Utils.AppendValidHTMLTags(Utils.ConvertTextToHTML(_markdownRtb.Text), file, true); - - _previewBrowser.DocumentText=text; - if (string.IsNullOrEmpty(file)) - { - - return true; - } - - _file = file; - if (!File.Exists(file)) - return true; - try - { - _isOpen = true; - StreamReader sr = new StreamReader(file, Encoding.UTF8); - this._markdownRtb.Text = sr.ReadToEnd(); - sr.Close(); - sr.Dispose(); - - - _isOpen = false; - - return true; - } - catch - { - return false; - } - } - - public void Save(string file) - { - this._file = file; - Save(); - } - - public void Save() - { - if (string.IsNullOrEmpty(_file)) - return; - - StreamWriter sw = new StreamWriter(_file,false, Encoding.UTF8); - sw.Write(this._markdownRtb.Text); - //this._markdownRtb.SaveFile(sw, RichTextBoxStreamType.PlainText); - sw.Close(); - sw.Dispose(); - alreadyUpdate = false; - - FileInfo fileInfo = new FileInfo(FileName); - - _markdownPage.Text = fileInfo.Name; - _markdownPage.ToolTipText = FileName; - } - - public void SetStyle(Color bg, Color fore, Font font, bool wordWrap,int tabWidth) - { - _isOpen = true; - TextEditor rtb = GetTextBox(); - -// if (rtb.BackColor != bg) -// rtb.BackColor = bg; -// if (rtb.ForeColor != fore) -// rtb.ForeColor = fore; -// if (rtb.Font != font) -// rtb.Font = font; - - if (rtb.WordWrap != wordWrap) - rtb.WordWrap = wordWrap; - - _isOpen = false; - } - - private float getfontWeight(int width,Font font) - { - Graphics g = _thisForm.CreateGraphics(); - SizeF sizeF = g.MeasureString("A",font ); - return sizeF.Width * width; - } - } + public class MarkdownEditor + { + private readonly TextEditor _markdownRtb; + private readonly WebControl _previewBrowser; + + private readonly FrmMain _thisForm; + private string _file = ""; + + private JSObject window; + private bool _isOpen; + private TabPage _markdownPage; + private bool alreadyUpdate; + + public MarkdownEditor(FrmMain thisform, TabPage page, WebControl preview) + { + _markdownPage = page; + _thisForm = thisform; + _previewBrowser = preview; + + createRTB(ref _markdownRtb); + _markdownRtb.TextChanged += _markdownRtb_TextChanged; + var elementHost = new ElementHost(); + elementHost.Child = _markdownRtb; + elementHost.Dock = DockStyle.Fill; + page.Controls.Add(elementHost); + + } + + public bool AlreadyUpdate + { + get { return alreadyUpdate; } + set { alreadyUpdate = value; } + } + + public string FileName + { + get { return _file; } + set { _file = value; } + } + + public TabPage MarkdownPage + { + get { return _markdownPage; } + set { _markdownPage = value; } + } + + private void createRTB(ref TextEditor htmlRtb) + { + htmlRtb = new TextEditor(); + + htmlRtb.AllowDrop = false; + + htmlRtb.TabIndex = 0; + + htmlRtb.AllowDrop = true; + htmlRtb.TextChanged += _markdownRtb_TextChanged; + + htmlRtb.DragEnter += htmlRtb_DragEnter; + htmlRtb.Drop += htmlRtb_DragDrop; + } + + private void htmlRtb_DragDrop(object sender, DragEventArgs e) + { + var arrayFileName = (Array)e.Data.GetData(DataFormats.FileDrop); + + string strFileName = arrayFileName.GetValue(0).ToString(); + + + var data = (string[])e.Data.GetData(DataFormats.FileDrop); + _thisForm.openfiles(data); + } + + private void htmlRtb_DragEnter(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + e.Effects = DragDropEffects.Link; + } + else + { + e.Effects = DragDropEffects.None; + } + } + + public TextEditor GetTextBox() + { + return _markdownRtb; + } + + private void _markdownRtb_TextChanged(object sender, EventArgs e) + { + invokeScript("loadMarkdown", Utils.ConvertTextToHTML(_markdownRtb.Text)); + } + + public string GetMarkdown() + { + return _markdownRtb.Text; + } + + + public void invokeScript(string scriptName, string html) + { + + try + { + window = this._previewBrowser.ExecuteJavascriptWithResult("window"); + if (window == null) + { + return; + } + window.Invoke(scriptName, new JSValue[] { html }); + } + catch (Exception) + { + + } + } + + + public bool Openfile(string file) + { + string text = Utils.AppendValidHTMLTags(Utils.ConvertTextToHTML(_markdownRtb.Text), file, true); + + _previewBrowser.LoadHTML(text); + if (string.IsNullOrEmpty(file)) + { + return true; + } + + _file = file; + if (!File.Exists(file)) + return true; + try + { + _isOpen = true; + var sr = new StreamReader(file, Encoding.UTF8); + _markdownRtb.Text = sr.ReadToEnd(); + sr.Close(); + sr.Dispose(); + + + _isOpen = false; + + return true; + } + catch + { + return false; + } + } + + public void Save(string file) + { + _file = file; + Save(); + } + + public void Save() + { + if (string.IsNullOrEmpty(_file)) + return; + + var sw = new StreamWriter(_file, false, Encoding.UTF8); + sw.Write(_markdownRtb.Text); + //this._markdownRtb.SaveFile(sw, RichTextBoxStreamType.PlainText); + sw.Close(); + sw.Dispose(); + alreadyUpdate = false; + + var fileInfo = new FileInfo(FileName); + + _markdownPage.Text = fileInfo.Name; + _markdownPage.ToolTipText = FileName; + } + + public void SetStyle(Color bg, Color fore, Font font, bool wordWrap, int tabWidth) + { + _isOpen = true; + TextEditor rtb = GetTextBox(); + + + + if (rtb.WordWrap != wordWrap) + rtb.WordWrap = wordWrap; + + _isOpen = false; + } + + + } } \ No newline at end of file diff --git a/MarkdownEditorManager.cs b/MarkdownEditorManager.cs index 5efdb53..1f42dbd 100644 --- a/MarkdownEditorManager.cs +++ b/MarkdownEditorManager.cs @@ -1,47 +1,49 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; - +using Awesomium.Windows.Forms; using ICSharpCode.AvalonEdit; using MRU; namespace MEditor { - public class MarkdownEditorManager - { - private WebBrowser _previewBrowser; - private static string _myExtName=".md"; - private string myExtName = "Markdown文件|*" + _myExtName + "|所有文件|*.*"; - - private frmMain _thisForm; - private TabControl _tabparent; - - private int _fileInd = 0; - private int noName = 0; - - SortedList _editors = new SortedList(); - private SortedList _thisModify = new SortedList(); - - private string _workSpace; - //private int maxDisplayLength = 10; - - private static Color BGColor = System.Drawing.SystemColors.Window; - private static Color FOREColor = System.Drawing.SystemColors.WindowText; - private static Font FONT=new Font("微软雅黑",12); - - //private Color _bgColor = Color.FromArgb(0x20,0x20,0x20); - //private Color _foreColor = Color.FromArgb(0xf2,0xf0,0xdf); - - private Color _bgColor = Color.FromArgb(0x4a,0x52,0x5a);//20,0x20,0x20; - private Color _foreColor = Color.FromArgb(0xff,0xff,0xff); //0xf2,0xf0,0xdf - private Font _font = new Font("微软雅黑", 12); - - #region defaultCss - private string _defcss = @" + public class MarkdownEditorManager + { + private static string _myExtName = ".md"; + //private int maxDisplayLength = 10; + + private static Color BGColor = SystemColors.Window; + private static Color FOREColor = SystemColors.WindowText; + private static Font FONT = new Font("微软雅黑", 12); + private readonly SortedList _editors = new SortedList(); + private readonly WebControl _previewBrowser; + private readonly TabControl _tabparent; + private readonly FrmMain _thisForm; + private readonly SortedList _thisModify = new SortedList(); + private readonly MRUManager mruManager; + private readonly string myExtName = "Markdown文件|*" + _myExtName + "|所有文件|*.*"; + + //private Color _bgColor = Color.FromArgb(0x20,0x20,0x20); + //private Color _foreColor = Color.FromArgb(0xf2,0xf0,0xdf); + + private Color _bgColor = Color.FromArgb(0x4a, 0x52, 0x5a); //20,0x20,0x20; + private int _fileInd; + private Font _font = new Font("微软雅黑", 12); + private Color _foreColor = Color.FromArgb(0xff, 0xff, 0xff); //0xf2,0xf0,0xdf + + private int _tabWidth = 4; + private bool _wordWrap; + private string _workSpace; + private int noName; + + #region defaultCss + + private string _defcss = @" body,td,th {font-family:""微软雅黑"", Verdana, ""Bitstream Vera Sans"", sans-serif; } body { margin-top: 0; @@ -233,371 +235,370 @@ dd p { } th,td{padding:5px;border: 1px solid #CCC;} "; - #endregion - - private bool _wordWrap = false; - private int _tabWidth = 4; - - private MRUManager mruManager; - - public MarkdownEditorManager(frmMain thisform, TabControl tabparent, MRUManager mru,WebBrowser preview) - { - this._tabparent = tabparent; - this._thisForm = thisform; - _workSpace = Application.StartupPath; - _previewBrowser=preview; - - mruManager = mru; - } - - public bool Open(string file) - { - if (string.IsNullOrEmpty(file)) - { - file =Application.StartupPath+"\\未命名" + (noName++).ToString() + ".md"; - } - else - { - foreach (MarkdownEditor me in _editors.Values) - { - if (me.FileName == file) - { - _tabparent.SelectedTab = me.MarkdownPage; - return true; - } - } - } - - - return openfile_(file); - } - - public bool RefrushOpen(string file) - { - if (_thisModify.ContainsKey(file)) - { - _thisModify.Remove(file); - return false; - } - foreach (MarkdownEditor me in _editors.Values) - { - if (me.FileName == file) - { - string noti = ""; - if (me.AlreadyUpdate) noti = "(重新打开,当前修改将丢失)"; - - if (MessageBox.Show(file + "在被其他软件已经修改,你需要重新打开吗"+noti+"?", "警告", MessageBoxButtons.YesNo) == DialogResult.No) - return false; - - bool rel = me.Openfile(file); - if (rel) - { - _tabparent.SelectedTab = me.MarkdownPage; - } - - return rel; - - } - } - - return false; - } - - - private bool openfile_(string file) - { - TabPage markPage = new TabPage(GetDisplayName(file)); - markPage.ToolTipText = file; - _tabparent.TabPages.Add(markPage); - markPage.Tag = _fileInd; - - MarkdownEditor meditor = new MarkdownEditor(_thisForm, markPage,_previewBrowser); - _editors.Add(_fileInd, meditor); - _fileInd++; - meditor.SetStyle(_bgColor, _foreColor, _font, _wordWrap, _tabWidth); - bool rel = meditor.Openfile(file); - if (rel) - { - _tabparent.SelectedTab = markPage; - } - - return rel; - } - - public MarkdownEditor GetCurrEditor() - { - if (_tabparent.SelectedTab == null) - return null; - - int ind=int.Parse(_tabparent.SelectedTab.Tag.ToString()); - if (_editors.ContainsKey(ind)) - return _editors[ind]; - else - return null; - } - - public TextEditor GetTextBox() - { - MarkdownEditor meditor = GetCurrEditor(); - if (meditor == null) - return null; - - return meditor.GetTextBox(); - } - - public void SaveAll() - { - foreach (int ind in _editors.Keys) - { - save(_editors[ind]); - } - } - - public bool CloseAll() - { - foreach (int ind in new List(_editors.Keys)) - { - if (_editors.ContainsKey(ind)) - { - if (!close(_editors[ind])) - return false; - } - } - return true; - } - - public void Save() - { - MarkdownEditor meditor = GetCurrEditor(); - if (meditor == null) - return; - - save(meditor); - } - - private bool save(MarkdownEditor meditor) - { - if (string.IsNullOrEmpty(meditor.FileName) || meditor.FileName.IndexOf("未命名")!=-1) - { - return saveas(meditor); - - } - meditor.Save(); - if (!_thisModify.ContainsKey(meditor.FileName)) - { - _thisModify.Add(meditor.FileName, true); - } - mruManager.Add(meditor.FileName); // when file is successfully opened - return true; - } - public bool SaveAs() - { - MarkdownEditor meditor = GetCurrEditor(); - if (meditor == null) - return true; - return saveas(meditor); - } - - private bool saveas(MarkdownEditor meditor) - { - SaveFileDialog fileone = new SaveFileDialog(); - fileone.Filter = myExtName; - fileone.FilterIndex = 1; - if (fileone.ShowDialog() == DialogResult.OK) - { - try - { - if (_thisModify.ContainsKey(meditor.FileName)) - { - _thisModify.Remove(meditor.FileName); - } - meditor.Save(fileone.FileName); - mruManager.Add(meditor.FileName); // when file is successfully opened - if (!_thisModify.ContainsKey(meditor.FileName)) - { - _thisModify.Add(meditor.FileName, true); - } - return true; - } - catch (ArgumentException) - { - MessageBox.Show("保存不成功"); - return false; - } - } - else - { - return false; - } - } - - public void openDir() - { - MarkdownEditor meditor = GetCurrEditor(); - if (meditor == null) - return; - - System.IO.FileInfo fi = new FileInfo(meditor.FileName); - - System.Diagnostics.Process.Start("explorer.exe", fi.Directory.ToString()); - - } - - public bool Close() - { - MarkdownEditor meditor = GetCurrEditor(); - if (meditor == null) - return true; - - return close(meditor); - } - - private bool close(MarkdownEditor meditor) - { - if (meditor.AlreadyUpdate) - { - DialogResult dr= MessageBox.Show("修改还没有保存,需要保存吗?", "提示", MessageBoxButtons.YesNoCancel) ; - if(dr==DialogResult.Cancel) - return false; - - if (dr== DialogResult.Yes) - { - if (!save(meditor)) - return false; - } - } - - int ind=TabSelectRec.GetLast(); - ind = TabSelectRec.GetLast(); - if (ind > -1 && ind<_tabparent.TabCount) - _tabparent.SelectedIndex = ind; - - _editors.Remove((int)meditor.MarkdownPage.Tag); - _tabparent.TabPages.Remove(meditor.MarkdownPage); - - return true; - } - - - [DllImport("shlwapi.dll", CharSet = CharSet.Auto)] - private static extern bool PathCompactPathEx( - StringBuilder pszOut, - string pszPath, - int cchMax, - int reserved); - - - /// - /// Get display file name from full name. - /// - /// Full file name - /// Short display name - private string GetDisplayName(string fullName) - { - // if file is in current directory, show only file name - FileInfo fileInfo = new FileInfo(fullName); - return fileInfo.Name; - - //if (fileInfo.DirectoryName == _workSpace) - // return GetShortDisplayName(fileInfo.Name, maxDisplayLength); - - //return GetShortDisplayName(fullName, maxDisplayLength); - } - - /// - /// Truncate a path to fit within a certain number of characters - /// by replacing path components with ellipses. - /// - /// This solution is provided by CodeProject and GotDotNet C# expert - /// Richard Deeming. - /// - /// - /// Long file name - /// Maximum length - /// Truncated file name - private string GetShortDisplayName(string longName, int maxLen) - { - StringBuilder pszOut = new StringBuilder(maxLen + maxLen + 2); // for safety - - if (PathCompactPathEx(pszOut, longName, maxLen, 0)) - { - return pszOut.ToString(); - } - else - { - return longName; - } - } - - private string convertColor(Color co) - { - return "#"+co.R.ToString("X2") + co.G.ToString("X2") + co.B.ToString("X2"); - } - public string GetHTMLStyle(string cont) - { - string htmlformat = "
"+cont+"
"; - - return htmlformat; - } - - public MarkdownEditor SetStyle() - { - MarkdownEditor m = GetCurrEditor(); - if (m == null) - return null; - - m.SetStyle(_bgColor, _foreColor, _font, _wordWrap, _tabWidth); - - return m; - } - - public void SetStyle(RichTextBox rtb) - { - if (rtb.BackColor != _bgColor) - rtb.BackColor = _bgColor; - if (rtb.ForeColor != _foreColor) - rtb.ForeColor = _foreColor; - if (rtb.Font != _font) - rtb.Font = _font; - if (rtb.WordWrap != _wordWrap) - rtb.WordWrap = _wordWrap; - } - - public void SetBackColor(Color co) - { - if(_bgColor==co) - return; - - _bgColor = co; - SetStyle(); - } - - public void SetForeColor(Color co) - { - if (_foreColor == co) - return; - - _foreColor = co; - SetStyle(); - } - - public void SetFont(Font font) - { - if (_font == font) - return; - _font = font; - SetStyle(); - } - public void SetWordWrap(bool wordWarp) - { - if (_wordWrap == wordWarp) - return; - _wordWrap = wordWarp; - SetStyle(); - } - public void SetCss(string css) - { - _defcss = css; - } - } -} + + #endregion + + public MarkdownEditorManager(FrmMain thisform, TabControl tabparent, MRUManager mru, WebControl preview) + { + _tabparent = tabparent; + _thisForm = thisform; + _workSpace = Application.StartupPath; + _previewBrowser = preview; + + mruManager = mru; + } + + public bool Open(string file) + { + if (string.IsNullOrEmpty(file)) + { + file = Application.StartupPath + "\\未命名" + (noName++).ToString() + ".md"; + } + else + { + foreach (MarkdownEditor me in _editors.Values) + { + if (me.FileName == file) + { + _tabparent.SelectedTab = me.MarkdownPage; + return true; + } + } + } + + + return openfile_(file); + } + + public bool RefrushOpen(string file) + { + if (_thisModify.ContainsKey(file)) + { + _thisModify.Remove(file); + return false; + } + foreach (MarkdownEditor me in _editors.Values) + { + if (me.FileName == file) + { + string noti = ""; + if (me.AlreadyUpdate) noti = "(重新打开,当前修改将丢失)"; + + if (MessageBox.Show(file + "在被其他软件已经修改,你需要重新打开吗" + noti + "?", "警告", MessageBoxButtons.YesNo) == + DialogResult.No) + return false; + + bool rel = me.Openfile(file); + if (rel) + { + _tabparent.SelectedTab = me.MarkdownPage; + } + + return rel; + } + } + + return false; + } + + + private bool openfile_(string file) + { + var markPage = new TabPage(GetDisplayName(file)); + markPage.ToolTipText = file; + _tabparent.TabPages.Add(markPage); + markPage.Tag = _fileInd; + + var meditor = new MarkdownEditor(_thisForm, markPage, _previewBrowser); + _editors.Add(_fileInd, meditor); + _fileInd++; + meditor.SetStyle(_bgColor, _foreColor, _font, _wordWrap, _tabWidth); + bool rel = meditor.Openfile(file); + if (rel) + { + _tabparent.SelectedTab = markPage; + } + + return rel; + } + + public MarkdownEditor GetCurrEditor() + { + if (_tabparent.SelectedTab == null) + return null; + + int ind = int.Parse(_tabparent.SelectedTab.Tag.ToString()); + if (_editors.ContainsKey(ind)) + return _editors[ind]; + else + return null; + } + + public TextEditor GetTextBox() + { + MarkdownEditor meditor = GetCurrEditor(); + if (meditor == null) + return null; + + return meditor.GetTextBox(); + } + + public void SaveAll() + { + foreach (int ind in _editors.Keys) + { + save(_editors[ind]); + } + } + + public bool CloseAll() + { + foreach (int ind in new List(_editors.Keys)) + { + if (_editors.ContainsKey(ind)) + { + if (!close(_editors[ind])) + return false; + } + } + return true; + } + + public void Save() + { + MarkdownEditor meditor = GetCurrEditor(); + if (meditor == null) + return; + + save(meditor); + } + + private bool save(MarkdownEditor meditor) + { + if (string.IsNullOrEmpty(meditor.FileName) || meditor.FileName.IndexOf("未命名") != -1) + { + return saveas(meditor); + } + meditor.Save(); + if (!_thisModify.ContainsKey(meditor.FileName)) + { + _thisModify.Add(meditor.FileName, true); + } + mruManager.Add(meditor.FileName); // when file is successfully opened + return true; + } + + public bool SaveAs() + { + MarkdownEditor meditor = GetCurrEditor(); + if (meditor == null) + return true; + return saveas(meditor); + } + + private bool saveas(MarkdownEditor meditor) + { + var fileone = new SaveFileDialog(); + fileone.Filter = myExtName; + fileone.FilterIndex = 1; + if (fileone.ShowDialog() == DialogResult.OK) + { + try + { + if (_thisModify.ContainsKey(meditor.FileName)) + { + _thisModify.Remove(meditor.FileName); + } + meditor.Save(fileone.FileName); + mruManager.Add(meditor.FileName); // when file is successfully opened + if (!_thisModify.ContainsKey(meditor.FileName)) + { + _thisModify.Add(meditor.FileName, true); + } + return true; + } + catch (ArgumentException) + { + MessageBox.Show("保存不成功"); + return false; + } + } + else + { + return false; + } + } + + public void openDir() + { + MarkdownEditor meditor = GetCurrEditor(); + if (meditor == null) + return; + + var fi = new FileInfo(meditor.FileName); + + Process.Start("explorer.exe", fi.Directory.ToString()); + } + + public bool Close() + { + MarkdownEditor meditor = GetCurrEditor(); + if (meditor == null) + return true; + + return close(meditor); + } + + private bool close(MarkdownEditor meditor) + { + if (meditor.AlreadyUpdate) + { + DialogResult dr = MessageBox.Show("修改还没有保存,需要保存吗?", "提示", MessageBoxButtons.YesNoCancel); + if (dr == DialogResult.Cancel) + return false; + + if (dr == DialogResult.Yes) + { + if (!save(meditor)) + return false; + } + } + + int ind = TabSelectRec.GetLast(); + ind = TabSelectRec.GetLast(); + if (ind > -1 && ind < _tabparent.TabCount) + _tabparent.SelectedIndex = ind; + + _editors.Remove((int)meditor.MarkdownPage.Tag); + _tabparent.TabPages.Remove(meditor.MarkdownPage); + + return true; + } + + + [DllImport("shlwapi.dll", CharSet = CharSet.Auto)] + private static extern bool PathCompactPathEx( + StringBuilder pszOut, + string pszPath, + int cchMax, + int reserved); + + + /// + /// Get display file name from full name. + /// + /// Full file name + /// Short display name + private string GetDisplayName(string fullName) + { + // if file is in current directory, show only file name + var fileInfo = new FileInfo(fullName); + return fileInfo.Name; + + //if (fileInfo.DirectoryName == _workSpace) + // return GetShortDisplayName(fileInfo.Name, maxDisplayLength); + + //return GetShortDisplayName(fullName, maxDisplayLength); + } + + /// + /// Truncate a path to fit within a certain number of characters + /// by replacing path components with ellipses. + /// This solution is provided by CodeProject and GotDotNet C# expert + /// Richard Deeming. + /// + /// Long file name + /// Maximum length + /// Truncated file name + private string GetShortDisplayName(string longName, int maxLen) + { + var pszOut = new StringBuilder(maxLen + maxLen + 2); // for safety + + if (PathCompactPathEx(pszOut, longName, maxLen, 0)) + { + return pszOut.ToString(); + } + else + { + return longName; + } + } + + private string convertColor(Color co) + { + return "#" + co.R.ToString("X2") + co.G.ToString("X2") + co.B.ToString("X2"); + } + + public string GetHTMLStyle(string cont) + { + string htmlformat = + "
" + cont + + "
"; + + return htmlformat; + } + + public MarkdownEditor SetStyle() + { + MarkdownEditor m = GetCurrEditor(); + if (m == null) + return null; + + m.SetStyle(_bgColor, _foreColor, _font, _wordWrap, _tabWidth); + + return m; + } + + public void SetStyle(RichTextBox rtb) + { + if (rtb.BackColor != _bgColor) + rtb.BackColor = _bgColor; + if (rtb.ForeColor != _foreColor) + rtb.ForeColor = _foreColor; + if (rtb.Font != _font) + rtb.Font = _font; + if (rtb.WordWrap != _wordWrap) + rtb.WordWrap = _wordWrap; + } + + public void SetBackColor(Color co) + { + if (_bgColor == co) + return; + + _bgColor = co; + SetStyle(); + } + + public void SetForeColor(Color co) + { + if (_foreColor == co) + return; + + _foreColor = co; + SetStyle(); + } + + public void SetFont(Font font) + { + if (_font == font) + return; + _font = font; + SetStyle(); + } + + public void SetWordWrap(bool wordWarp) + { + if (_wordWrap == wordWarp) + return; + _wordWrap = wordWarp; + SetStyle(); + } + + public void SetCss(string css) + { + _defcss = css; + } + } +} \ No newline at end of file diff --git a/MarkdownSharp/Escapes.cs b/MarkdownSharp/Escapes.cs deleted file mode 100644 index 85c5336..0000000 --- a/MarkdownSharp/Escapes.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace MarkdownSharp -{ - internal static class Escapes - { - private const string _escapeCharacters = @"\`*_{}[]()>#+-.!"; - private static readonly KeyValuePair[] _escapeTable; - private static readonly Regex _hashFinder; - - static Escapes() - { - _escapeTable = new KeyValuePair[_escapeCharacters.Length]; - string pattern = ""; - for (int i = 0; i < _escapeCharacters.Length; ++i) - { - char c = _escapeCharacters[i]; - string hash = c.ToString().GetHashCode().ToString(); - _escapeTable[i] = new KeyValuePair(c, hash); - - if (pattern != "") pattern += "|(" + hash + ")"; - else pattern += "(" + hash + ")"; - } - _hashFinder = new Regex(pattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture); - } - - /// - /// Gets the escape code for a single character - /// - public static string get(char c) - { - foreach(var pair in _escapeTable) - if (pair.Key == c) - return pair.Value; - throw new IndexOutOfRangeException("The requested character can not be escaped"); - } - - /// - /// Gets the character that a hash refers to - /// - private static char getInverse(string s) - { - foreach (var pair in _escapeTable) - if (pair.Value == s) - return pair.Key; - throw new IndexOutOfRangeException("The requested hash can not be found"); - } - - /// - /// Encodes any escaped characters such as \`, \*, \[ etc - /// - public static string BackslashEscapes(string text) - { - int len = text.Length, first = 0, i = 0; - var sb = new StringBuilder(len); - while (i < len) - { - if (text[i] == '\\' && i + 1 < len && Contains(_escapeCharacters, text[i + 1])) - { - sb.Append(text, first, i - first); - sb.Append(get(text[++i])); - first = ++i; - } - else ++i; - } - if (first == 0) return text; - sb.Append(text, first, i - first); - return sb.ToString(); - } - - /// - /// Encodes Bold [ * ] and Italic [ _ ] characters - /// - public static string BoldItalic(string text) - { - int len = text.Length, first = 0, i = 0; - var sb = new StringBuilder(len); - while (i < len) - { - if ('*' == text[i]) - { - sb.Append(text, first, i - first); - sb.Append(get('*')); - first = ++i; - } - else if ('_' == text[i]) - { - sb.Append(text, first, i - first); - sb.Append(get('_')); - first = ++i; - } - else ++i; - } - if (first == 0) return text; - sb.Append(text, first, i - first); - return sb.ToString(); - } - - /// - /// Encodes all chars of the second parameter. - /// - public static string Escape(string text, string escapes) - { - int len = text.Length, first = 0, i = 0; - var sb = new StringBuilder(len); - while (i < len) - { - if (Contains(escapes, text[i])) - { - sb.Append(text, first, i - first); - sb.Append(get(text[i])); - first = ++i; - } - else ++i; - } - if (first == 0) return text; - sb.Append(text, first, i - first); - return sb.ToString(); - } - - /// - /// encodes problem characters in URLs, such as - /// * _ and optionally ' () [] : - /// this is to avoid problems with markup later - /// - public static string ProblemUrlChars(string url) - { - url = url.Replace("*", "%2A"); - url = url.Replace("_", "%5F"); - url = url.Replace("'", "%27"); - url = url.Replace("(", "%28"); - url = url.Replace(")", "%29"); - url = url.Replace("[", "%5B"); - url = url.Replace("]", "%5D"); - if (url.Length > 7 && Contains(url.Substring(7), ':')) - { - // replace any colons in the body of the URL that are NOT followed by 2 or more numbers - url = url.Substring(0, 7) + Regex.Replace(url.Substring(7), @":(?!\d{2,})", "%3A"); - } - - return url; - } - - private static bool Contains(string s, char c) - { - int len = s.Length; - for (int i = 0; i < len; ++i) - if (s[i] == c) - return true; - return false; - } - - /// - /// swap back in all the special characters we've hidden - /// - public static string Unescape(string text) - { - return _hashFinder.Replace(text, match => getInverse(match.Value).ToString()); - } - } -} \ No newline at end of file diff --git a/MarkdownSharp/Markdown.cs b/MarkdownSharp/Markdown.cs deleted file mode 100644 index 03e0834..0000000 --- a/MarkdownSharp/Markdown.cs +++ /dev/null @@ -1,1725 +0,0 @@ -/* - * MarkdownSharp - * ------------- - * a C# Markdown processor - * - * Markdown is a text-to-HTML conversion tool for web writers - * Copyright (c) 2004 John Gruber - * http://daringfireball.net/projects/markdown/ - * - * Markdown.NET - * Copyright (c) 2004-2009 Milan Negovan - * http://www.aspnetresources.com - * http://aspnetresources.com/blog/markdown_announced.aspx - * - * MarkdownSharp - * Copyright (c) 2009-2010 Jeff Atwood - * http://stackoverflow.com - * http://www.codinghorror.com/blog/ - * http://code.google.com/p/markdownsharp/ - * - * History: Milan ported the Markdown processor to C#. He granted license to me so I can open source it - * and let the community contribute to and improve MarkdownSharp. - * - */ - -#region Copyright and license - -/* - -Copyright (c) 2009 - 2010 Jeff Atwood - -http://www.opensource.org/licenses/mit-license.php - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -Copyright (c) 2003-2004 John Gruber - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name "Markdown" nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as -is" and any express or implied warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a -particular purpose are disclaimed. In no event shall the copyright owner -or contributors be liable for any direct, indirect, incidental, special, -exemplary, or consequential damages (including, but not limited to, -procurement of substitute goods or services; loss of use, data, or -profits; or business interruption) however caused and on any theory of -liability, whether in contract, strict liability, or tort (including -negligence or otherwise) arising in any way out of the use of this -software, even if advised of the possibility of such damage. -*/ - -#endregion - -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Text; -using System.Text.RegularExpressions; - -namespace MarkdownSharp -{ - - public class MarkdownOptions - { - /// - /// when true, (most) bare plain URLs are auto-hyperlinked - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool AutoHyperlink { get; set; } - /// - /// when true, RETURN becomes a literal newline - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool AutoNewlines { get; set; } - /// - /// use ">" for HTML output, or " />" for XHTML output - /// - public string EmptyElementSuffix { get; set; } - /// - /// when true, problematic URL characters like [, ], (, and so forth will be encoded - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool EncodeProblemUrlCharacters { get; set; } - /// - /// when false, email addresses will never be auto-linked - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool LinkEmails { get; set; } - /// - /// when true, bold and italic require non-word characters on either side - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool StrictBoldItalic { get; set; } - } - - - /// - /// Markdown is a text-to-HTML conversion tool for web writers. - /// Markdown allows you to write using an easy-to-read, easy-to-write plain text format, - /// then convert it to structurally valid XHTML (or HTML). - /// - public class Markdown - { - private const string _version = "1.13"; - - #region Constructors and Options - - /// - /// Create a new Markdown instance using default options - /// - public Markdown() : this(false) - { - } - - /// - /// Create a new Markdown instance and optionally load options from a configuration - /// file. There they should be stored in the appSettings section, available options are: - /// - /// Markdown.StrictBoldItalic (true/false) - /// Markdown.EmptyElementSuffix (">" or " />" without the quotes) - /// Markdown.LinkEmails (true/false) - /// Markdown.AutoNewLines (true/false) - /// Markdown.AutoHyperlink (true/false) - /// Markdown.EncodeProblemUrlCharacters (true/false) - /// - /// - public Markdown(bool loadOptionsFromConfigFile) - { - if (!loadOptionsFromConfigFile) return; - - var settings = ConfigurationManager.AppSettings; - foreach (string key in settings.Keys) - { - switch (key) - { - case "Markdown.AutoHyperlink": - _autoHyperlink = Convert.ToBoolean(settings[key]); - break; - case "Markdown.AutoNewlines": - _autoNewlines = Convert.ToBoolean(settings[key]); - break; - case "Markdown.EmptyElementSuffix": - _emptyElementSuffix = settings[key]; - break; - case "Markdown.EncodeProblemUrlCharacters": - _encodeProblemUrlCharacters = Convert.ToBoolean(settings[key]); - break; - case "Markdown.LinkEmails": - _linkEmails = Convert.ToBoolean(settings[key]); - break; - case "Markdown.StrictBoldItalic": - _strictBoldItalic = Convert.ToBoolean(settings[key]); - break; - } - } - } - - /// - /// Create a new Markdown instance and set the options from the MarkdownOptions object. - /// - public Markdown(MarkdownOptions options) - { - _autoHyperlink = options.AutoHyperlink; - _autoNewlines = options.AutoNewlines; - _emptyElementSuffix = options.EmptyElementSuffix; - _encodeProblemUrlCharacters = options.EncodeProblemUrlCharacters; - _linkEmails = options.LinkEmails; - _strictBoldItalic = options.StrictBoldItalic; - } - - - /// - /// use ">" for HTML output, or " />" for XHTML output - /// - public string EmptyElementSuffix - { - get { return _emptyElementSuffix; } - set { _emptyElementSuffix = value; } - } - private string _emptyElementSuffix = " />"; - - /// - /// when false, email addresses will never be auto-linked - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool LinkEmails - { - get { return _linkEmails; } - set { _linkEmails = value; } - } - private bool _linkEmails = true; - - /// - /// when true, bold and italic require non-word characters on either side - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool StrictBoldItalic - { - get { return _strictBoldItalic; } - set { _strictBoldItalic = value; } - } - private bool _strictBoldItalic = false; - - /// - /// when true, RETURN becomes a literal newline - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool AutoNewLines - { - get { return _autoNewlines; } - set { _autoNewlines = value; } - } - private bool _autoNewlines = false; - - /// - /// when true, (most) bare plain URLs are auto-hyperlinked - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool AutoHyperlink - { - get { return _autoHyperlink; } - set { _autoHyperlink = value; } - } - private bool _autoHyperlink = false; - - /// - /// when true, problematic URL characters like [, ], (, and so forth will be encoded - /// WARNING: this is a significant deviation from the markdown spec - /// - public bool EncodeProblemUrlCharacters - { - get { return _encodeProblemUrlCharacters; } - set { _encodeProblemUrlCharacters = value; } - } - private bool _encodeProblemUrlCharacters = false; - - #endregion - - private enum TokenType { Text, Tag } - - private struct Token - { - public Token(TokenType type, string value) - { - this.Type = type; - this.Value = value; - } - public TokenType Type; - public string Value; - } - - /// - /// maximum nested depth of [] and () supported by the transform; implementation detail - /// - private const int _nestDepth = 6; - - /// - /// Tabs are automatically converted to spaces as part of the transform - /// this constant determines how "wide" those tabs become in spaces - /// - private const int _tabWidth = 4; - - private const string _markerUL = @"[*+-]"; - private const string _markerOL = @"\d+[.]"; - - private static readonly Dictionary _escapeTable; - private static readonly Dictionary _invertedEscapeTable; - private static readonly Dictionary _backslashEscapeTable; - - private readonly Dictionary _urls = new Dictionary(); - private readonly Dictionary _titles = new Dictionary(); - private readonly Dictionary _htmlBlocks = new Dictionary(); - - private int _listLevel; - - /// - /// In the static constuctor we'll initialize what stays the same across all transforms. - /// - static Markdown() - { - // Table of hash values for escaped characters: - _escapeTable = new Dictionary(); - _invertedEscapeTable = new Dictionary(); - // Table of hash value for backslash escaped characters: - _backslashEscapeTable = new Dictionary(); - - string backslashPattern = ""; - - foreach (char c in @"\`*_{}[]()>#+-.!") - { - string key = c.ToString(); - string hash = GetHashKey(key); - _escapeTable.Add(key, hash); - _invertedEscapeTable.Add(hash, key); - _backslashEscapeTable.Add(@"\" + key, hash); - backslashPattern += Regex.Escape(@"\" + key) + "|"; - } - - _backslashEscapes = new Regex(backslashPattern.Substring(0, backslashPattern.Length - 1), RegexOptions.Compiled); - } - - /// - /// current version of MarkdownSharp; - /// see http://code.google.com/p/markdownsharp/ for the latest code or to contribute - /// - public string Version - { - get { return _version; } - } - - /// - /// Transforms the provided Markdown-formatted text to HTML; - /// see http://en.wikipedia.org/wiki/Markdown - /// - /// - /// The order in which other subs are called here is - /// essential. Link and image substitutions need to happen before - /// EscapeSpecialChars(), so that any *'s or _'s in the a - /// and img tags get encoded. - /// - public string Transform(string text) - { - if (String.IsNullOrEmpty(text)) return ""; - - Setup(); - - text = Normalize(text); - - text = HashHTMLBlocks(text); - text = StripLinkDefinitions(text); - text = RunBlockGamut(text); - text = Unescape(text); - - Cleanup(); - - return text + "\n"; - } - - - /// - /// Perform transformations that form block-level tags like paragraphs, headers, and list items. - /// - private string RunBlockGamut(string text) - { - text = DoHeaders(text); - text = DoHorizontalRules(text); - text = DoLists(text); - text = DoCodeBlocks(text); - text = DoBlockQuotes(text); - - // We already ran HashHTMLBlocks() before, in Markdown(), but that - // was to escape raw HTML in the original Markdown source. This time, - // we're escaping the markup we've just created, so that we don't wrap - //

tags around block-level tags. - text = HashHTMLBlocks(text); - - text = FormParagraphs(text); - - return text; - } - - - ///

- /// Perform transformations that occur *within* block-level tags like paragraphs, headers, and list items. - /// - private string RunSpanGamut(string text) - { - text = DoCodeSpans(text); - text = EscapeSpecialCharsWithinTagAttributes(text); - text = EscapeBackslashes(text); - - // Images must come first, because ![foo][f] looks like an anchor. - text = DoImages(text); - text = DoAnchors(text); - - // Must come after DoAnchors(), because you can use < and > - // delimiters in inline links like [this](). - text = DoAutoLinks(text); - - text = EncodeAmpsAndAngles(text); - text = DoItalicsAndBold(text); - text = DoHardBreaks(text); - - return text; - } - - private static Regex _newlinesLeadingTrailing = new Regex(@"^\n+|\n+\z", RegexOptions.Compiled); - private static Regex _newlinesMultiple = new Regex(@"\n{2,}", RegexOptions.Compiled); - private static Regex _leadingWhitespace = new Regex(@"^[ ]*", RegexOptions.Compiled); - - /// - /// splits on two or more newlines, to form "paragraphs"; - /// each paragraph is then unhashed (if it is a hash) or wrapped in HTML p tag - /// - private string FormParagraphs(string text) - { - // split on two or more newlines - string[] grafs = _newlinesMultiple.Split(_newlinesLeadingTrailing.Replace(text, "")); - - for (int i = 0; i < grafs.Length; i++) - { - if (grafs[i].StartsWith("\x1A")) - { - // unhashify HTML blocks - grafs[i] = _htmlBlocks[grafs[i]]; - } - else - { - // do span level processing inside the block, then wrap result in

tags - grafs[i] = _leadingWhitespace.Replace(RunSpanGamut(grafs[i]), "

") + "

"; - } - } - - return string.Join("\n\n", grafs); - } - - - private void Setup() - { - // Clear the global hashes. If we don't clear these, you get conflicts - // from other articles when generating a page which contains more than - // one article (e.g. an index page that shows the N most recent - // articles): - _urls.Clear(); - _titles.Clear(); - _htmlBlocks.Clear(); - _listLevel = 0; - } - - private void Cleanup() - { - Setup(); - } - - private static string _nestedBracketsPattern; - - /// - /// Reusable pattern to match balanced [brackets]. See Friedl's - /// "Mastering Regular Expressions", 2nd Ed., pp. 328-331. - /// - private static string GetNestedBracketsPattern() - { - // in other words [this] and [this[also]] and [this[also[too]]] - // up to _nestDepth - if (_nestedBracketsPattern == null) - _nestedBracketsPattern = - RepeatString(@" - (?> # Atomic matching - [^\[\]]+ # Anything other than brackets - | - \[ - ", _nestDepth) + RepeatString( - @" \] - )*" - , _nestDepth); - return _nestedBracketsPattern; - } - - private static string _nestedParensPattern; - - /// - /// Reusable pattern to match balanced (parens). See Friedl's - /// "Mastering Regular Expressions", 2nd Ed., pp. 328-331. - /// - private static string GetNestedParensPattern() - { - // in other words (this) and (this(also)) and (this(also(too))) - // up to _nestDepth - if (_nestedParensPattern == null) - _nestedParensPattern = - RepeatString(@" - (?> # Atomic matching - [^()\s]+ # Anything other than parens or whitespace - | - \( - ", _nestDepth) + RepeatString( - @" \) - )*" - , _nestDepth); - return _nestedParensPattern; - } - - private static Regex _linkDef = new Regex(string.Format(@" - ^[ ]{{0,{0}}}\[(.+)\]: # id = $1 - [ ]* - \n? # maybe *one* newline - [ ]* - ? # url = $2 - [ ]* - \n? # maybe one newline - [ ]* - (?: - (?<=\s) # lookbehind for whitespace - [""(] - (.+?) # title = $3 - ["")] - [ ]* - )? # title is optional - (?:\n+|\Z)", _tabWidth - 1), RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - /// - /// Strips link definitions from text, stores the URLs and titles in hash references. - /// - /// - /// ^[id]: url "optional title" - /// - private string StripLinkDefinitions(string text) - { - return _linkDef.Replace(text, new MatchEvaluator(LinkEvaluator)); - } - - private string LinkEvaluator(Match match) - { - string linkID = match.Groups[1].Value.ToLowerInvariant(); - _urls[linkID] = EncodeAmpsAndAngles(match.Groups[2].Value); - - if (match.Groups[3] != null && match.Groups[3].Length > 0) - _titles[linkID] = match.Groups[3].Value.Replace("\"", """); - - return ""; - } - - // compiling this monster regex results in worse performance. trust me. - private static Regex _blocksHtml = new Regex(GetBlockPattern(), RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); - - - /// - /// derived pretty much verbatim from PHP Markdown - /// - private static string GetBlockPattern() - { - - // Hashify HTML blocks: - // We only want to do this for block-level HTML tags, such as headers, - // lists, and tables. That's because we still want to wrap

s around - // "paragraphs" that are wrapped in non-block-level tags, such as anchors, - // phrase emphasis, and spans. The list of tags we're looking for is - // hard-coded: - // - // * List "a" is made of tags which can be both inline or block-level. - // These will be treated block-level when the start tag is alone on - // its line, otherwise they're not matched here and will be taken as - // inline later. - // * List "b" is made of tags which are always block-level; - // - string blockTagsA = "ins|del"; - string blockTagsB = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|script|noscript|form|fieldset|iframe|math"; - - // Regular expression for the content of a block tag. - string attr = @" - (?> # optional tag attributes - \s # starts with whitespace - (?> - [^>""/]+ # text outside quotes - | - /+(?!>) # slash not followed by > - | - ""[^""]*"" # text inside double quotes (tolerate >) - | - '[^']*' # text inside single quotes (tolerate >) - )* - )? - "; - - string content = RepeatString(@" - (?> - [^<]+ # content without tag - | - <\2 # nested opening tag - " + attr + @" # attributes - (?> - /> - | - >", _nestDepth) + // end of opening tag - ".*?" + // last level nested tag content - RepeatString(@" - # closing nested tag - ) - | - <(?!/\2\s*> # other tags with a different name - ) - )*", _nestDepth); - - string content2 = content.Replace(@"\2", @"\3"); - - // First, look for nested blocks, e.g.: - //

- //
- // tags for inner block must be indented. - //
- //
- // - // The outermost tags must start at the left margin for this to match, and - // the inner nested divs must be indented. - // We need to do this before the next, more liberal match, because the next - // match will start at the first `
` and stop at the first `
`. - string pattern = @" - (?> - (?> - (?<=\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - - # Match from `\n` to `\n`, handling nested tags - # in between. - - [ ]{0,$less_than_tab} - <($block_tags_b_re) # start tag = $2 - $attr> # attributes followed by > and \n - $content # content, support nesting - # the matching end tag - [ ]* # trailing spaces - (?=\n+|\Z) # followed by a newline or end of document - - | # Special version for tags of group a. - - [ ]{0,$less_than_tab} - <($block_tags_a_re) # start tag = $3 - $attr>[ ]*\n # attributes followed by > - $content2 # content, support nesting - # the matching end tag - [ ]* # trailing spaces - (?=\n+|\Z) # followed by a newline or end of document - - | # Special case just for
. It was easier to make a special - # case than to make the other regex more complicated. - - [ ]{0,$less_than_tab} - <(hr) # start tag = $2 - $attr # attributes - /?> # the matching end tag - [ ]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - - | # Special case for standalone HTML comments: - - [ ]{0,$less_than_tab} - (?s: - - ) - [ ]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - - | # PHP and ASP-style processor instructions ( - ) - [ ]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - - ) - )"; - - pattern = pattern.Replace("$less_than_tab", (_tabWidth - 1).ToString()); - pattern = pattern.Replace("$block_tags_b_re", blockTagsB); - pattern = pattern.Replace("$block_tags_a_re", blockTagsA); - pattern = pattern.Replace("$attr", attr); - pattern = pattern.Replace("$content2", content2); - pattern = pattern.Replace("$content", content); - - return pattern; - } - - /// - /// replaces any block-level HTML blocks with hash entries - /// - private string HashHTMLBlocks(string text) - { - return _blocksHtml.Replace(text, new MatchEvaluator(HtmlEvaluator)); - } - - private string HtmlEvaluator(Match match) - { - string text = match.Groups[1].Value; - string key = GetHashKey(text); - _htmlBlocks[key] = text; - - return string.Concat("\n\n", key, "\n\n"); - } - - private static string GetHashKey(string s) - { - return "\x1A" + Math.Abs(s.GetHashCode()).ToString() + "\x1A"; - } - - private static Regex _htmlTokens = new Regex(@" - ()| # match - (<\?.*?\?>)| # match " + - RepeatString(@" - (<[A-Za-z\/!$](?:[^<>]|", _nestDepth) + RepeatString(@")*>)", _nestDepth) + - " # match and ", - RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - /// - /// returns an array of HTML tokens comprising the input string. Each token is - /// either a tag (possibly with nested, tags contained therein, such - /// as <a href="<MTFoo>">, or a run of text between tags. Each element of the - /// array is a two-element array; the first is either 'tag' or 'text'; the second is - /// the actual value. - /// - private List TokenizeHTML(string text) - { - int pos = 0; - int tagStart = 0; - var tokens = new List(); - - // this regex is derived from the _tokenize() subroutine in Brad Choate's MTRegex plugin. - // http://www.bradchoate.com/past/mtregex.php - foreach (Match m in _htmlTokens.Matches(text)) - { - tagStart = m.Index; - - if (pos < tagStart) - tokens.Add(new Token(TokenType.Text, text.Substring(pos, tagStart - pos))); - - tokens.Add(new Token(TokenType.Tag, m.Value)); - pos = tagStart + m.Length; - } - - if (pos < text.Length) - tokens.Add(new Token(TokenType.Text, text.Substring(pos, text.Length - pos))); - - return tokens; - } - - - private static Regex _anchorRef = new Regex(string.Format(@" - ( # wrap whole match in $1 - \[ - ({0}) # link text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - )", GetNestedBracketsPattern()), RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - private static Regex _anchorInline = new Regex(string.Format(@" - ( # wrap whole match in $1 - \[ - ({0}) # link text = $2 - \] - \( # literal paren - [ ]* - ({1}) # href = $3 - [ ]* - ( # $4 - (['""]) # quote char = $5 - (.*?) # title = $6 - \5 # matching quote - [ ]* # ignore any spaces between closing quote and ) - )? # title is optional - \) - )", GetNestedBracketsPattern(), GetNestedParensPattern()), - RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - private static Regex _anchorRefShortcut = new Regex(@" - ( # wrap whole match in $1 - \[ - ([^\[\]]+) # link text = $2; can't contain [ or ] - \] - )", RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - /// - /// Turn Markdown link shortcuts into HTML anchor tags - /// - /// - /// [link text](url "title") - /// [link text][id] - /// [id] - /// - private string DoAnchors(string text) - { - // First, handle reference-style links: [link text] [id] - text = _anchorRef.Replace(text, new MatchEvaluator(AnchorRefEvaluator)); - - // Next, inline-style links: [link text](url "optional title") or [link text](url "optional title") - text = _anchorInline.Replace(text, new MatchEvaluator(AnchorInlineEvaluator)); - - // Last, handle reference-style shortcuts: [link text] - // These must come last in case you've also got [link test][1] - // or [link test](/foo) - text = _anchorRefShortcut.Replace(text, new MatchEvaluator(AnchorRefShortcutEvaluator)); - return text; - } - - private string AnchorRefEvaluator(Match match) - { - string wholeMatch = match.Groups[1].Value; - string linkText = match.Groups[2].Value; - string linkID = match.Groups[3].Value.ToLowerInvariant(); - - string result; - - // for shortcut links like [this][]. - if (linkID == "") - linkID = linkText.ToLowerInvariant(); - - if (_urls.ContainsKey(linkID)) - { - string url = _urls[linkID]; - - url = EncodeProblemUrlChars(url); - url = EscapeBoldItalic(url); - result = ""; - } - else - result = wholeMatch; - - return result; - } - - private string AnchorRefShortcutEvaluator(Match match) - { - string wholeMatch = match.Groups[1].Value; - string linkText = match.Groups[2].Value; - string linkID = Regex.Replace(linkText.ToLowerInvariant(), @"[ ]*\n[ ]*", " "); // lower case and remove newlines / extra spaces - - string result; - - if (_urls.ContainsKey(linkID)) - { - string url = _urls[linkID]; - - url = EncodeProblemUrlChars(url); - url = EscapeBoldItalic(url); - result = ""; - } - else - result = wholeMatch; - - return result; - } - - - private string AnchorInlineEvaluator(Match match) - { - string linkText = match.Groups[2].Value; - string url = match.Groups[3].Value; - string title = match.Groups[6].Value; - string result; - - url = EncodeProblemUrlChars(url); - url = EscapeBoldItalic(url); - if (url.StartsWith("<") && url.EndsWith(">")) - url = url.Substring(1, url.Length - 2); // remove <>'s surrounding URL, if present - - result = string.Format("{0}", linkText); - return result; - } - - private static Regex _imagesRef = new Regex(@" - ( # wrap whole match in $1 - !\[ - (.*?) # alt text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - - )", RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled); - - private static Regex _imagesInline = new Regex(String.Format(@" - ( # wrap whole match in $1 - !\[ - (.*?) # alt text = $2 - \] - \s? # one optional whitespace character - \( # literal paren - [ ]* - ({0}) # href = $3 - [ ]* - ( # $4 - (['""]) # quote char = $5 - (.*?) # title = $6 - \5 # matching quote - [ ]* - )? # title is optional - \) - )", GetNestedParensPattern()), - RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled); - - /// - /// Turn Markdown image shortcuts into HTML img tags. - /// - /// - /// ![alt text][id] - /// ![alt text](url "optional title") - /// - private string DoImages(string text) - { - // First, handle reference-style labeled images: ![alt text][id] - text = _imagesRef.Replace(text, new MatchEvaluator(ImageReferenceEvaluator)); - - // Next, handle inline images: ![alt text](url "optional title") - // Don't forget: encode * and _ - text = _imagesInline.Replace(text, new MatchEvaluator(ImageInlineEvaluator)); - - return text; - } - - private string ImageReferenceEvaluator(Match match) - { - string wholeMatch = match.Groups[1].Value; - string altText = match.Groups[2].Value; - string linkID = match.Groups[3].Value.ToLowerInvariant(); - string result; - - // for shortcut links like ![this][]. - if (linkID == "") - linkID = altText.ToLowerInvariant(); - - altText = altText.Replace("\"", """); - - if (_urls.ContainsKey(linkID)) - { - string url = _urls[linkID]; - url = EncodeProblemUrlChars(url); - url = EscapeBoldItalic(url); - result = string.Format("\"{1}\"",")) - url = url.Substring(1, url.Length - 2); // Remove <>'s surrounding URL, if present - url = EncodeProblemUrlChars(url); - url = EscapeBoldItalic(url); - - result = string.Format("\"{1}\"", - /// Turn Markdown headers into HTML header tags - /// - /// - /// Header 1 - /// ======== - /// - /// Header 2 - /// -------- - /// - /// # Header 1 - /// ## Header 2 - /// ## Header 2 with closing hashes ## - /// ... - /// ###### Header 6 - /// - private string DoHeaders(string text) - { - text = _headerSetext.Replace(text, new MatchEvaluator(SetextHeaderEvaluator)); - text = _headerAtx.Replace(text, new MatchEvaluator(AtxHeaderEvaluator)); - return text; - } - - private string SetextHeaderEvaluator(Match match) - { - string header = match.Groups[1].Value; - int level = match.Groups[2].Value.StartsWith("=") ? 1 : 2; - return string.Format("{0}\n\n", RunSpanGamut(header), level); - } - - private string AtxHeaderEvaluator(Match match) - { - string header = match.Groups[2].Value; - int level = match.Groups[1].Value.Length; - return string.Format("{0}\n\n", RunSpanGamut(header), level); - } - - - private static Regex _horizontalRules = new Regex(@" - ^[ ]{0,3} # Leading space - ([-*_]) # $1: First marker - (?> # Repeated marker group - [ ]{0,2} # Zero, one, or two spaces. - \1 # Marker character - ){2,} # Group repeated at least twice - [ ]* # Trailing spaces - $ # End of line. - ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - /// - /// Turn Markdown horizontal rules into HTML hr tags - /// - /// - /// *** - /// * * * - /// --- - /// - - - - /// - private string DoHorizontalRules(string text) - { - return _horizontalRules.Replace(text, " - /// Turn Markdown lists into HTML ul and ol and li tags - /// - private string DoLists(string text) - { - // We use a different prefix before nested lists than top-level lists. - // See extended comment in _ProcessListItems(). - if (_listLevel > 0) - text = _listNested.Replace(text, new MatchEvaluator(ListEvaluator)); - else - text = _listTopLevel.Replace(text, new MatchEvaluator(ListEvaluator)); - - return text; - } - - private string ListEvaluator(Match match) - { - string list = match.Groups[1].Value; - string listType = Regex.IsMatch(match.Groups[3].Value, _markerUL) ? "ul" : "ol"; - string result; - - // Turn double returns into triple returns, so that we can make a - // paragraph for the last item in a list, if necessary: - list = Regex.Replace(list, @"\n{2,}", "\n\n\n"); - result = ProcessListItems(list, listType == "ul" ? _markerUL : _markerOL); - - result = string.Format("<{0}>\n{1}\n", listType, result); - return result; - } - - /// - /// Process the contents of a single ordered or unordered list, splitting it - /// into individual list items. - /// - private string ProcessListItems(string list, string marker) - { - // The listLevel global keeps track of when we're inside a list. - // Each time we enter a list, we increment it; when we leave a list, - // we decrement. If it's zero, we're not in a list anymore. - - // We do this because when we're not inside a list, we want to treat - // something like this: - - // I recommend upgrading to version - // 8. Oops, now this line is treated - // as a sub-list. - - // As a single paragraph, despite the fact that the second line starts - // with a digit-period-space sequence. - - // Whereas when we're inside a list (or sub-list), that line will be - // treated as the start of a sub-list. What a kludge, huh? This is - // an aspect of Markdown's syntax that's hard to parse perfectly - // without resorting to mind-reading. Perhaps the solution is to - // change the syntax rules such that sub-lists must start with a - // starting cardinal number; e.g. "1." or "a.". - - _listLevel++; - - // Trim trailing blank lines: - list = Regex.Replace(list, @"\n{2,}\z", "\n"); - - string pattern = string.Format( - @"(\n)? # leading line = $1 - (^[ ]*) # leading whitespace = $2 - ({0}) [ ]+ # list marker = $3 - ((?s:.+?) # list item text = $4 - (\n{{1,2}})) - (?= \n* (\z | \2 ({0}) [ ]+))", marker); - - list = Regex.Replace(list, pattern, new MatchEvaluator(ListItemEvaluator), - RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline); - _listLevel--; - return list; - } - - private string ListItemEvaluator(Match match) - { - string item = match.Groups[4].Value; - string leadingLine = match.Groups[1].Value; - - if (!String.IsNullOrEmpty(leadingLine) || Regex.IsMatch(item, @"\n{2,}")) - // we could correct any bad indentation here.. - item = RunBlockGamut(Outdent(item) + "\n"); - else - { - // recursion for sub-lists - item = DoLists(Outdent(item)); - item = item.TrimEnd('\n'); - item = RunSpanGamut(item); - } - - return string.Format("
  • {0}
  • \n", item); - } - - - private static Regex _codeBlock = new Regex(string.Format(@" - (?:\n\n|\A\n?) - ( # $1 = the code block -- one or more lines, starting with a space - (?: - (?:[ ]{{{0}}}) # Lines must start with a tab-width of spaces - .*\n+ - )+ - ) - ((?=^[ ]{{0,{0}}}\S)|\Z) # Lookahead for non-space at line-start, or end of doc", - _tabWidth), RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); - - /// - /// /// Turn Markdown 4-space indented code into HTML pre code blocks - /// - private string DoCodeBlocks(string text) - { - text = _codeBlock.Replace(text, new MatchEvaluator(CodeBlockEvaluator)); - return text; - } - - private string CodeBlockEvaluator(Match match) - { - string codeBlock = match.Groups[1].Value; - - codeBlock = EncodeCode(Outdent(codeBlock)); - codeBlock = _newlinesLeadingTrailing.Replace(codeBlock, ""); - - return string.Concat("\n\n
    ", codeBlock, "\n
    \n\n"); - } - - private static Regex _codeSpan = new Regex(@" - (? - /// Turn Markdown `code spans` into HTML code tags - /// - private string DoCodeSpans(string text) - { - // * You can use multiple backticks as the delimiters if you want to - // include literal backticks in the code span. So, this input: - // - // Just type ``foo `bar` baz`` at the prompt. - // - // Will translate to: - // - //

    Just type foo `bar` baz at the prompt.

    - // - // There's no arbitrary limit to the number of backticks you - // can use as delimters. If you need three consecutive backticks - // in your code, use four for delimiters, etc. - // - // * You can use spaces to get literal backticks at the edges: - // - // ... type `` `bar` `` ... - // - // Turns to: - // - // ... type `bar` ... - // - - return _codeSpan.Replace(text, new MatchEvaluator(CodeSpanEvaluator)); - } - - private string CodeSpanEvaluator(Match match) - { - string span = match.Groups[2].Value; - span = Regex.Replace(span, @"^[ ]*", ""); // leading whitespace - span = Regex.Replace(span, @"[ ]*$", ""); // trailing whitespace - span = EncodeCode(span); - - return string.Concat("", span, ""); - } - - - private static Regex _bold = new Regex(@"(\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1", - RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled); - private static Regex _strictBold = new Regex(@"([\W_]|^) (\*\*|__) (?=\S) ([^\r]*?\S[\*_]*) \2 ([\W_]|$)", - RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled); - - private static Regex _italic = new Regex(@"(\*|_) (?=\S) (.+?) (?<=\S) \1", - RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled); - private static Regex _strictItalic = new Regex(@"([\W_]|^) (\*|_) (?=\S) ([^\r\*_]*?\S) \2 ([\W_]|$)", - RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled); - - /// - /// Turn Markdown *italics* and **bold** into HTML strong and em tags - /// - private string DoItalicsAndBold(string text) - { - - // must go first, then - if (_strictBoldItalic) - { - text = _strictBold.Replace(text, "$1$3$4"); - text = _strictItalic.Replace(text, "$1$3$4"); - } - else - { - text = _bold.Replace(text, "$2"); - text = _italic.Replace(text, "$2"); - } - return text; - } - - /// - /// Turn markdown line breaks (two space at end of line) into HTML break tags - /// - private string DoHardBreaks(string text) - { - if (_autoNewlines) - text = Regex.Replace(text, @"\n", string.Format("[ ]? # '>' at the start of a line - .+\n # rest of the first line - (.+\n)* # subsequent consecutive lines - \n* # blanks - )+ - )", RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Compiled); - - /// - /// Turn Markdown > quoted blocks into HTML blockquote blocks - /// - private string DoBlockQuotes(string text) - { - return _blockquote.Replace(text, new MatchEvaluator(BlockQuoteEvaluator)); - } - - private string BlockQuoteEvaluator(Match match) - { - string bq = match.Groups[1].Value; - - bq = Regex.Replace(bq, @"^[ ]*>[ ]?", "", RegexOptions.Multiline); // trim one level of quoting - bq = Regex.Replace(bq, @"^[ ]+$", "", RegexOptions.Multiline); // trim whitespace-only lines - bq = RunBlockGamut(bq); // recurse - - bq = Regex.Replace(bq, @"^", " ", RegexOptions.Multiline); - - // These leading spaces screw with
     content, so we need to fix that:
    -            bq = Regex.Replace(bq, @"(\s*
    .+?
    )", new MatchEvaluator(BlockQuoteEvaluator2), RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline); - - return string.Format("
    \n{0}\n
    \n\n", bq); - } - - private string BlockQuoteEvaluator2(Match match) - { - return Regex.Replace(match.Groups[1].Value, @"^ ", "", RegexOptions.Multiline); - } - - private static Regex _autolinkBare = new Regex(@"(^|\s)(https?|ftp)(://[-A-Z0-9+&@#/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#/%=~_|\[\]])($|\W)", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - - /// - /// Turn angle-delimited URLs into HTML anchor tags - /// - /// - /// <http://www.example.com> - /// - private string DoAutoLinks(string text) - { - - if (_autoHyperlink) - { - // fixup arbitrary URLs by adding Markdown < > so they get linked as well - // note that at this point, all other URL in the text are already hyperlinked as - // *except* for the case - text = _autolinkBare.Replace(text, @"$1<$2$3>$4"); - } - - // Hyperlinks: - text = Regex.Replace(text, "<((https?|ftp):[^'\">\\s]+)>", new MatchEvaluator(HyperlinkEvaluator)); - - if (_linkEmails) - { - // Email addresses: - string pattern = - @"< - (?:mailto:)? - ( - [-.\w]+ - \@ - [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ - ) - >"; - text = Regex.Replace(text, pattern, new MatchEvaluator(EmailEvaluator), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - } - - return text; - } - - private string HyperlinkEvaluator(Match match) - { - string link = match.Groups[1].Value; - return string.Format("{0}", link); - } - - private string EmailEvaluator(Match match) - { - string email = Unescape(match.Groups[1].Value); - - // - // Input: an email address, e.g. "foo@example.com" - // - // Output: the email address as a mailto link, with each character - // of the address encoded as either a decimal or hex entity, in - // the hopes of foiling most address harvesting spam bots. E.g.: - // - // foo - // @example.com - // - // Based by a filter by Matthew Wickline, posted to the BBEdit-Talk - // mailing list: - // - email = "mailto:" + email; - - // leave ':' alone (to spot mailto: later) - email = EncodeEmailAddress(email); - - email = string.Format("{0}", email); - - // strip the mailto: from the visible part - email = Regex.Replace(email, "\">.+?:", "\">"); - return email; - } - - - private static Regex _outDent = new Regex(@"^[ ]{1," + _tabWidth + @"}", RegexOptions.Multiline | RegexOptions.Compiled); - - /// - /// Remove one level of line-leading spaces - /// - private string Outdent(string block) - { - return _outDent.Replace(block, ""); - } - - - #region Encoding and Normalization - - - /// - /// encodes email address randomly - /// roughly 10% raw, 45% hex, 45% dec - /// note that @ is always encoded and : never is - /// - private string EncodeEmailAddress(string addr) - { - var sb = new StringBuilder(addr.Length * 5); - var rand = new Random(); - int r; - foreach (char c in addr) - { - r = rand.Next(1, 100); - if ((r > 90 || c == ':') && c != '@') - sb.Append(c); // m - else if (r < 45) - sb.AppendFormat("&#x{0:x};", (int)c); // m - else - sb.AppendFormat("&#{0};", (int)c); // m - } - return sb.ToString(); - } - - private static Regex _codeEncoder = new Regex(@"&|<|>|\\|\*|_|\{|\}|\[|\]", RegexOptions.Compiled); - - /// - /// Encode/escape certain Markdown characters inside code blocks and spans where they are literals - /// - private string EncodeCode(string code) - { - return _codeEncoder.Replace(code, EncodeCodeEvaluator); - } - private string EncodeCodeEvaluator(Match match) - { - switch (match.Value) - { - // Encode all ampersands; HTML entities are not - // entities within a Markdown code span. - case "&": - return "&"; - // Do the angle bracket song and dance - case "<": - return "<"; - case ">": - return ">"; - // escape characters that are magic in Markdown - default: - return _escapeTable[match.Value]; - } - } - - - private static Regex _amps = new Regex(@"&(?!(#[0-9]+)|(#[xX][a-fA-F0-9])|([a-zA-Z][a-zA-Z0-9]*);)", RegexOptions.ExplicitCapture | RegexOptions.Compiled); - private static Regex _angles = new Regex(@"<(?![A-Za-z/?\$!])", RegexOptions.ExplicitCapture | RegexOptions.Compiled); - - /// - /// Encode any ampersands (that aren't part of an HTML entity) and left or right angle brackets - /// - private string EncodeAmpsAndAngles(string s) - { - s = _amps.Replace(s, "&"); - s = _angles.Replace(s, "<"); - return s; - } - - private static Regex _backslashEscapes; - - /// - /// Encodes any escaped characters such as \`, \*, \[ etc - /// - private string EscapeBackslashes(string s) - { - return _backslashEscapes.Replace(s, new MatchEvaluator(EscapeBackslashesEvaluator)); - } - private string EscapeBackslashesEvaluator(Match match) - { - return _backslashEscapeTable[match.Value]; - } - - private static Regex _unescapes = new Regex("\x1A\\d+\x1A", RegexOptions.Compiled); - - /// - /// swap back in all the special characters we've hidden - /// - private string Unescape(string s) - { - return _unescapes.Replace(s, new MatchEvaluator(UnescapeEvaluator)); - } - private string UnescapeEvaluator(Match match) - { - return _invertedEscapeTable[match.Value]; - } - - - /// - /// escapes Bold [ * ] and Italic [ _ ] characters - /// - private string EscapeBoldItalic(string s) - { - s = s.Replace("*", _escapeTable["*"]); - s = s.Replace("_", _escapeTable["_"]); - return s; - } - - private static char[] _problemUrlChars = @"""'*()[]$:".ToCharArray(); - - /// - /// hex-encodes some unusual "problem" chars in URLs to avoid URL detection problems - /// - private string EncodeProblemUrlChars(string url) - { - if (!_encodeProblemUrlCharacters) return url; - - var sb = new StringBuilder(url.Length); - bool encode; - char c; - - for (int i = 0; i < url.Length; i++) - { - c = url[i]; - encode = Array.IndexOf(_problemUrlChars, c) != -1; - if (encode && c == ':' && i < url.Length - 1) - encode = !(url[i + 1] == '/') && !(url[i + 1] >= '0' && url[i + 1] <= '9'); - - if (encode) - sb.Append("%" + String.Format("{0:x}", (byte)c)); - else - sb.Append(c); - } - - return sb.ToString(); - } - - - /// - /// Within tags -- meaning between < and > -- encode [\ ` * _] so they - /// don't conflict with their use in Markdown for code, italics and strong. - /// We're replacing each such character with its corresponding hash - /// value; this is likely overkill, but it should prevent us from colliding - /// with the escape values by accident. - /// - private string EscapeSpecialCharsWithinTagAttributes(string text) - { - var tokens = TokenizeHTML(text); - - // now, rebuild text from the tokens - var sb = new StringBuilder(text.Length); - - foreach (var token in tokens) - { - string value = token.Value; - - if (token.Type == TokenType.Tag) - { - value = value.Replace(@"\", _escapeTable[@"\"]); - value = Regex.Replace(value, "(?<=.)(?=.)", _escapeTable[@"`"]); - value = EscapeBoldItalic(value); - } - - sb.Append(value); - } - - return sb.ToString(); - } - - /// - /// convert all tabs to _tabWidth spaces; - /// standardizes line endings from DOS (CR LF) or Mac (CR) to UNIX (LF); - /// makes sure text ends with a couple of newlines; - /// removes any blank lines (only spaces) in the text - /// - private string Normalize(string text) - { - var output = new StringBuilder(text.Length); - var line = new StringBuilder(); - bool valid = false; - - for (int i = 0; i < text.Length; i++) - { - switch (text[i]) - { - case '\n': - if (valid) output.Append(line); - output.Append('\n'); - line.Length = 0; valid = false; - break; - case '\r': - if ((i < text.Length - 1) && (text[i + 1] != '\n')) - { - if (valid) output.Append(line); - output.Append('\n'); - line.Length = 0; valid = false; - } - break; - case '\t': - int width = (_tabWidth - line.Length % _tabWidth); - for (int k = 0; k < width; k++) - line.Append(' '); - break; - case '\x1A': - break; - default: - if (!valid && text[i] != ' ') valid = true; - line.Append(text[i]); - break; - } - } - - if (valid) output.Append(line); - output.Append('\n'); - - // add two newlines to the end before return - return output.Append("\n\n").ToString(); - } - - #endregion - - /// - /// this is to emulate what's evailable in PHP - /// - private static string RepeatString(string text, int count) - { - var sb = new StringBuilder(text.Length * count); - for (int i = 0; i < count; i++) - sb.Append(text); - return sb.ToString(); - } - - } -} \ No newline at end of file diff --git a/Processers/EMark.cs b/Processers/EMark.cs index d315e40..5d63a5e 100644 --- a/Processers/EMark.cs +++ b/Processers/EMark.cs @@ -1,11 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace MEditor.Processers +namespace MEditor.Processers { public enum EMark { - bold, itail, boldanditail, + bold, + itail, + boldanditail, } -} +} \ No newline at end of file diff --git a/Processers/IProcesser.cs b/Processers/IProcesser.cs index 5c39523..11008dc 100644 --- a/Processers/IProcesser.cs +++ b/Processers/IProcesser.cs @@ -1,24 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Text; +using ICSharpCode.AvalonEdit; -using ICSharpCode.AvalonEdit; - -namespace MEditor.Processers -{ - public interface IProcesser - { - /// - /// 可以处理的标签类型 - /// - EMark[] ProcessMarks { get; set; } - - /// - /// 处理并返回处理后的文本 - /// - /// 待处理的文本 - /// 标签类型 - /// 处理后的返回 - void Process(TextEditor rtb, EMark mark); - } -} +namespace MEditor.Processers +{ + public interface IProcesser + { + /// + /// 可以处理的标签类型 + /// + EMark[] ProcessMarks { get; set; } + + /// + /// 处理并返回处理后的文本 + /// + /// 待处理的文本 + /// 标签类型 + /// 处理后的返回 + void Process(TextEditor rtb, EMark mark); + } +} \ No newline at end of file diff --git a/Processers/ProcesserBold.cs b/Processers/ProcesserBold.cs index 7a3fb5c..ac09df8 100644 --- a/Processers/ProcesserBold.cs +++ b/Processers/ProcesserBold.cs @@ -1,75 +1,62 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - +using System.Text.RegularExpressions; using ICSharpCode.AvalonEdit; - -namespace MEditor.Processers -{ - public class ProcesserBold:IProcesser - { - #region IProcesser 成员 - private EMark[] _marks=new EMark[]{EMark.boldanditail,EMark.bold,EMark.itail}; - - public EMark[] ProcessMarks - { - get - { - return _marks; - } - set - { - _marks = value; - } - } - - public void Process(TextEditor rtb, EMark mark) - { - - //粗体和斜体:用星号”*”或者下划线”_” - //一个表示斜体; - //两个表示粗体; - //三个表示粗斜体。 - switch (mark) - { - case EMark.bold: - Bold(rtb); - return; - case EMark.itail: - iterator(rtb); - return; - case EMark.boldanditail: - Bold(rtb); - iterator(rtb); - return; - } - } - - private void iterator(TextEditor rtb) - { - - } - - private void Bold(TextEditor rtb) - { - //int startPos = rtb.SelectionStart + rtb.SelectedText.Length; - - string source=rtb.SelectedText; - - Regex regex=new Regex(@"^\*\*(.*)\*\*$"); - Match mat=regex.Match(source); - if (mat.Success) - { - //manager.SelectedText = mat.Groups[1].Value;//what here doing ?????? - return; - } - //manager.SelectedText = "**" + manager.SelectedText + "**"; - rtb.SelectedText="**" + source + "**"; - - } - - - #endregion - } -} + +namespace MEditor.Processers +{ + public class ProcesserBold : IProcesser + { + #region IProcesser 成员 + + private EMark[] _marks = new[] {EMark.boldanditail, EMark.bold, EMark.itail}; + + public EMark[] ProcessMarks + { + get { return _marks; } + set { _marks = value; } + } + + public void Process(TextEditor rtb, EMark mark) + { + //粗体和斜体:用星号”*”或者下划线”_” + //一个表示斜体; + //两个表示粗体; + //三个表示粗斜体。 + switch (mark) + { + case EMark.bold: + Bold(rtb); + return; + case EMark.itail: + iterator(rtb); + return; + case EMark.boldanditail: + Bold(rtb); + iterator(rtb); + return; + } + } + + private void iterator(TextEditor rtb) + { + } + + private void Bold(TextEditor rtb) + { + //int startPos = rtb.SelectionStart + rtb.SelectedText.Length; + + string source = rtb.SelectedText; + + var regex = new Regex(@"^\*\*(.*)\*\*$"); + Match mat = regex.Match(source); + if (mat.Success) + { + //manager.SelectedText = mat.Groups[1].Value;//what here doing ?????? + return; + } + //manager.SelectedText = "**" + manager.SelectedText + "**"; + rtb.SelectedText = "**" + source + "**"; + } + + #endregion + } +} \ No newline at end of file diff --git a/Processers/ProcesserFactory.cs b/Processers/ProcesserFactory.cs index 1c62f6c..4e8cd2f 100644 --- a/Processers/ProcesserFactory.cs +++ b/Processers/ProcesserFactory.cs @@ -1,61 +1,59 @@ using System; using System.Collections.Generic; using System.Reflection; -using System.Text; - using ICSharpCode.AvalonEdit; - -namespace MEditor.Processers -{ - /// - /// 配置标签处理工厂,即给工厂添加处理器 - /// - public class ProcesserFactory - { - private static SortedList _procs=new SortedList(); - - static ProcesserFactory() - { - initProcesser(); - } - /// - /// 取得配置后的处理工厂对象 - /// - /// 指定为哪类服务器类型配置消息处理工厂 - /// - public static void Processe(TextEditor rtb, EMark mark) - { - if (_procs.ContainsKey(mark)) - { - _procs[mark].Process(rtb, mark); - } - } - - /// - /// 在此集中给工厂添加处理器 - /// - /// - private static void initProcesser() - { - Assembly assembly = Assembly.GetAssembly(typeof(ProcesserFactory)); - //得到Assembly中的所有类型 - Type[] types = assembly.GetTypes(); - - //遍历所有的类型,找到插件类型,并创建插件实例并加载 - foreach (Type type in types) - { - //判断类型是否派生自IPlugin接口 - if (type.GetInterface("IProcesser") != null) - { - //创建插件实例 - IProcesser processer = (IProcesser)Activator.CreateInstance(type); - foreach (EMark m in processer.ProcessMarks) - { - _procs.Add(m, processer); - } - } - } - } - - } -} + +namespace MEditor.Processers +{ + /// + /// 配置标签处理工厂,即给工厂添加处理器 + /// + public class ProcesserFactory + { + private static readonly SortedList _procs = new SortedList(); + + static ProcesserFactory() + { + initProcesser(); + } + + /// + /// 取得配置后的处理工厂对象 + /// + /// 指定为哪类服务器类型配置消息处理工厂 + /// + public static void Processe(TextEditor rtb, EMark mark) + { + if (_procs.ContainsKey(mark)) + { + _procs[mark].Process(rtb, mark); + } + } + + /// + /// 在此集中给工厂添加处理器 + /// + /// + private static void initProcesser() + { + Assembly assembly = Assembly.GetAssembly(typeof (ProcesserFactory)); + //得到Assembly中的所有类型 + Type[] types = assembly.GetTypes(); + + //遍历所有的类型,找到插件类型,并创建插件实例并加载 + foreach (Type type in types) + { + //判断类型是否派生自IPlugin接口 + if (type.GetInterface("IProcesser") != null) + { + //创建插件实例 + var processer = (IProcesser) Activator.CreateInstance(type); + foreach (EMark m in processer.ProcessMarks) + { + _procs.Add(m, processer); + } + } + } + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index be2f07a..909410e 100644 --- a/Program.cs +++ b/Program.cs @@ -1,26 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -namespace MEditor -{ - static class Program - { - /// - /// 应用程序的主入口点。 - /// - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - // Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); - Application.Run(new frmMain()); - } - - static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) - { - MessageBox.Show("Sorry,出现了一个错误!如果严重的影响了您的工作,请将它发给我allen.fantasy@gmail.com"+e.Exception.StackTrace); - } - } +using System; +using System.Threading; +using System.Windows.Forms; +using MEditor.TestForm; + +namespace MEditor +{ + internal static class Program + { + /// + /// 应用程序的主入口点。 + /// + [STAThread] + private static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + // Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); + Application.Run(new FrmMain()); + //Application.Run(new TestSundown()); + } + + private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + MessageBox.Show("Sorry,出现了一个错误!如果严重的影响了您的工作,请将它发给我allen.fantasy@gmail.com" + e.Exception.StackTrace); + } + } } \ No newline at end of file diff --git a/Sundownlib/README.md b/Sundownlib/README.md new file mode 100644 index 0000000..32e50d2 --- /dev/null +++ b/Sundownlib/README.md @@ -0,0 +1,20 @@ +# Sundown + +Sundown is the Markdown parsing library used at Github. This is a copy +of the code, please do not edit. + +* [Sundown on Github](https://github.com/vmg/sundown.git) + +## License + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Sundownlib/Sundown.cs b/Sundownlib/Sundown.cs new file mode 100644 index 0000000..928179c --- /dev/null +++ b/Sundownlib/Sundown.cs @@ -0,0 +1,131 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace MEditor.Sundownlib +{ + public sealed class Sundown : IDisposable + { + private const string Import = "SundownLib.dll"; + + private static readonly int sd_callbacks_Size = 26*IntPtr.Size; // 26 function pointers + private static readonly int html_renderopt_Size = 4*4 + IntPtr.Size; // 4 int32 + 1 pointer + private IntPtr handle; + private IntPtr htmlRenderOpts; + private IntPtr sdCallbacks; + + public Sundown() + { + sdCallbacks = Marshal.AllocHGlobal(sd_callbacks_Size); + htmlRenderOpts = Marshal.AllocHGlobal(html_renderopt_Size); + + sdhtml_renderer(sdCallbacks, htmlRenderOpts, 0); + handle = sd_markdown_new(mkd_extensions.ALL, new IntPtr(16), sdCallbacks, htmlRenderOpts); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + [DllImport(Import, CallingConvention = CallingConvention.Cdecl)] + private static extern void sdhtml_renderer(IntPtr callbacks, IntPtr htmlRenderOpts, uint render_flags); + + [DllImport(Import, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr sd_markdown_new(mkd_extensions extensions, IntPtr max_nesting, IntPtr callbacks, + IntPtr opaque); + + [DllImport(Import, CallingConvention = CallingConvention.Cdecl)] + private static extern void sd_markdown_free(IntPtr md); + + [DllImport(Import, CallingConvention = CallingConvention.Cdecl)] + private static extern void sd_markdown_render(IntPtr ob, byte[] document, IntPtr doc_size, IntPtr md); + + [DllImport(Import, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr bufnew(IntPtr size); + + [DllImport(Import, CallingConvention = CallingConvention.Cdecl)] + private static extern void bufrelease(IntPtr buf); + + public string Render(string str) + { + IntPtr ob = IntPtr.Zero; + + try + { + byte[] ib = Encoding.UTF8.GetBytes(str); + ob = bufnew(new IntPtr(64)); + + sd_markdown_render(ob, ib, new IntPtr(ib.Length), handle); + + int obLen = Marshal.ReadInt32(ob, IntPtr.Size); + IntPtr obDataPtr = Marshal.ReadIntPtr(ob); + var obBytes = new byte[obLen]; + + // woo super slow marshalling! + for (int i = 0; i < obLen; i++) + { + obBytes[i] = Marshal.ReadByte(obDataPtr, i); + } + + return Encoding.UTF8.GetString(obBytes); + } + finally + { + if (ob != IntPtr.Zero) + { + bufrelease(ob); + } + } + } + + ~Sundown() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + if (handle != IntPtr.Zero) + { + sd_markdown_free(handle); + handle = IntPtr.Zero; + } + + if (sdCallbacks != IntPtr.Zero) + { + Marshal.FreeHGlobal(sdCallbacks); + sdCallbacks = IntPtr.Zero; + } + + if (htmlRenderOpts != IntPtr.Zero) + { + Marshal.FreeHGlobal(htmlRenderOpts); + htmlRenderOpts = IntPtr.Zero; + } + } + + private enum mkd_extensions + { + MKDEXT_NO_INTRA_EMPHASIS = (1 << 0), + MKDEXT_TABLES = (1 << 1), + MKDEXT_FENCED_CODE = (1 << 2), + MKDEXT_AUTOLINK = (1 << 3), + MKDEXT_STRIKETHROUGH = (1 << 4), + MKDEXT_SPACE_HEADERS = (1 << 6), + MKDEXT_SUPERSCRIPT = (1 << 7), + MKDEXT_LAX_SPACING = (1 << 8), + + ALL = + MKDEXT_NO_INTRA_EMPHASIS | + MKDEXT_TABLES | + MKDEXT_FENCED_CODE | + MKDEXT_AUTOLINK | + MKDEXT_STRIKETHROUGH | + MKDEXT_SPACE_HEADERS | + MKDEXT_SUPERSCRIPT | + MKDEXT_LAX_SPACING + } + } +} \ No newline at end of file diff --git a/Sundownlib/SundownLib.vcxproj b/Sundownlib/SundownLib.vcxproj new file mode 100644 index 0000000..14b0edd --- /dev/null +++ b/Sundownlib/SundownLib.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + {4D5727E1-BC75-4B7A-B6B7-3D7BC2F7A12A} + Win32Proj + SundownLib + + + + DynamicLibrary + true + v110 + Unicode + + + DynamicLibrary + false + v110 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;SUNDOWNLIB_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;SUNDOWNLIB_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Sundownlib/SundownLib.vcxproj.filters b/Sundownlib/SundownLib.vcxproj.filters new file mode 100644 index 0000000..b861718 --- /dev/null +++ b/Sundownlib/SundownLib.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + + \ No newline at end of file diff --git a/Sundownlib/autolink.c b/Sundownlib/autolink.c new file mode 100644 index 0000000..6f8d6ab --- /dev/null +++ b/Sundownlib/autolink.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2011, Vicent Marti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "buffer.h" +#include "autolink.h" + +#include +#include +#include +#include + +#if defined(_WIN32) +#define strncasecmp _strnicmp +#endif + +int +sd_autolink_issafe(const uint8_t *link, size_t link_len) +{ + static const size_t valid_uris_count = 5; + static const char *valid_uris[] = { + "/", "http://", "https://", "ftp://", "mailto:" + }; + + size_t i; + + for (i = 0; i < valid_uris_count; ++i) { + size_t len = strlen(valid_uris[i]); + + if (link_len > len && + strncasecmp((char *)link, valid_uris[i], len) == 0 && + isalnum(link[len])) + return 1; + } + + return 0; +} + +static size_t +autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size) +{ + uint8_t cclose, copen = 0; + size_t i; + + for (i = 0; i < link_end; ++i) + if (data[i] == '<') { + link_end = i; + break; + } + + while (link_end > 0) { + if (strchr("?!.,", data[link_end - 1]) != NULL) + link_end--; + + else if (data[link_end - 1] == ';') { + size_t new_end = link_end - 2; + + while (new_end > 0 && isalpha(data[new_end])) + new_end--; + + if (new_end < link_end - 2 && data[new_end] == '&') + link_end = new_end; + else + link_end--; + } + else break; + } + + if (link_end == 0) + return 0; + + cclose = data[link_end - 1]; + + switch (cclose) { + case '"': copen = '"'; break; + case '\'': copen = '\''; break; + case ')': copen = '('; break; + case ']': copen = '['; break; + case '}': copen = '{'; break; + } + + if (copen != 0) { + size_t closing = 0; + size_t opening = 0; + size_t i = 0; + + /* Try to close the final punctuation sign in this same line; + * if we managed to close it outside of the URL, that means that it's + * not part of the URL. If it closes inside the URL, that means it + * is part of the URL. + * + * Examples: + * + * foo http://www.pokemon.com/Pikachu_(Electric) bar + * => http://www.pokemon.com/Pikachu_(Electric) + * + * foo (http://www.pokemon.com/Pikachu_(Electric)) bar + * => http://www.pokemon.com/Pikachu_(Electric) + * + * foo http://www.pokemon.com/Pikachu_(Electric)) bar + * => http://www.pokemon.com/Pikachu_(Electric)) + * + * (foo http://www.pokemon.com/Pikachu_(Electric)) bar + * => foo http://www.pokemon.com/Pikachu_(Electric) + */ + + while (i < link_end) { + if (data[i] == copen) + opening++; + else if (data[i] == cclose) + closing++; + + i++; + } + + if (closing != opening) + link_end--; + } + + return link_end; +} + +static size_t +check_domain(uint8_t *data, size_t size, int allow_short) +{ + size_t i, np = 0; + + if (!isalnum(data[0])) + return 0; + + for (i = 1; i < size - 1; ++i) { + if (data[i] == '.') np++; + else if (!isalnum(data[i]) && data[i] != '-') break; + } + + if (allow_short) { + /* We don't need a valid domain in the strict sense (with + * least one dot; so just make sure it's composed of valid + * domain characters and return the length of the the valid + * sequence. */ + return i; + } else { + /* a valid domain needs to have at least a dot. + * that's as far as we get */ + return np ? i : 0; + } +} + +size_t +sd_autolink__www( + size_t *rewind_p, + struct buf *link, + uint8_t *data, + size_t max_rewind, + size_t size, + unsigned int flags) +{ + size_t link_end; + + if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1])) + return 0; + + if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) + return 0; + + link_end = check_domain(data, size, 0); + + if (link_end == 0) + return 0; + + while (link_end < size && !isspace(data[link_end])) + link_end++; + + link_end = autolink_delim(data, link_end, max_rewind, size); + + if (link_end == 0) + return 0; + + bufput(link, data, link_end); + *rewind_p = 0; + + return (int)link_end; +} + +size_t +sd_autolink__email( + size_t *rewind_p, + struct buf *link, + uint8_t *data, + size_t max_rewind, + size_t size, + unsigned int flags) +{ + size_t link_end, rewind; + int nb = 0, np = 0; + + for (rewind = 0; rewind < max_rewind; ++rewind) { + uint8_t c = data[-rewind - 1]; + + if (isalnum(c)) + continue; + + if (strchr(".+-_", c) != NULL) + continue; + + break; + } + + if (rewind == 0) + return 0; + + for (link_end = 0; link_end < size; ++link_end) { + uint8_t c = data[link_end]; + + if (isalnum(c)) + continue; + + if (c == '@') + nb++; + else if (c == '.' && link_end < size - 1) + np++; + else if (c != '-' && c != '_') + break; + } + + if (link_end < 2 || nb != 1 || np == 0 || + !isalpha(data[link_end - 1])) + return 0; + + link_end = autolink_delim(data, link_end, max_rewind, size); + + if (link_end == 0) + return 0; + + bufput(link, data - rewind, link_end + rewind); + *rewind_p = rewind; + + return link_end; +} + +size_t +sd_autolink__url( + size_t *rewind_p, + struct buf *link, + uint8_t *data, + size_t max_rewind, + size_t size, + unsigned int flags) +{ + size_t link_end, rewind = 0, domain_len; + + if (size < 4 || data[1] != '/' || data[2] != '/') + return 0; + + while (rewind < max_rewind && isalpha(data[-rewind - 1])) + rewind++; + + if (!sd_autolink_issafe(data - rewind, size + rewind)) + return 0; + + link_end = strlen("://"); + + domain_len = check_domain( + data + link_end, + size - link_end, + flags & SD_AUTOLINK_SHORT_DOMAINS); + + if (domain_len == 0) + return 0; + + link_end += domain_len; + while (link_end < size && !isspace(data[link_end])) + link_end++; + + link_end = autolink_delim(data, link_end, max_rewind, size); + + if (link_end == 0) + return 0; + + bufput(link, data - rewind, link_end + rewind); + *rewind_p = rewind; + + return link_end; +} + diff --git a/Sundownlib/autolink.h b/Sundownlib/autolink.h new file mode 100644 index 0000000..65e0fe6 --- /dev/null +++ b/Sundownlib/autolink.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, Vicent Marti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UPSKIRT_AUTOLINK_H +#define UPSKIRT_AUTOLINK_H + +#include "buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + SD_AUTOLINK_SHORT_DOMAINS = (1 << 0), +}; + +int +sd_autolink_issafe(const uint8_t *link, size_t link_len); + +size_t +sd_autolink__www(size_t *rewind_p, struct buf *link, + uint8_t *data, size_t offset, size_t size, unsigned int flags); + +size_t +sd_autolink__email(size_t *rewind_p, struct buf *link, + uint8_t *data, size_t offset, size_t size, unsigned int flags); + +size_t +sd_autolink__url(size_t *rewind_p, struct buf *link, + uint8_t *data, size_t offset, size_t size, unsigned int flags); + +#ifdef __cplusplus +} +#endif + +#endif + +/* vim: set filetype=c: */ diff --git a/Sundownlib/buffer.c b/Sundownlib/buffer.c new file mode 100644 index 0000000..a29538f --- /dev/null +++ b/Sundownlib/buffer.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2008, Natacha Porté + * Copyright (c) 2011, Vicent Martí + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb + +#include "buffer.h" + +#include +#include +#include +#include + +/* MSVC compat */ +#if defined(_MSC_VER) +# define _buf_vsnprintf _vsnprintf +#else +# define _buf_vsnprintf vsnprintf +#endif + +int +bufprefix(const struct buf *buf, const char *prefix) +{ + size_t i; + assert(buf && buf->unit); + + for (i = 0; i < buf->size; ++i) { + if (prefix[i] == 0) + return 0; + + if (buf->data[i] != prefix[i]) + return buf->data[i] - prefix[i]; + } + + return 0; +} + +/* bufgrow: increasing the allocated size to the given value */ +int +bufgrow(struct buf *buf, size_t neosz) +{ + size_t neoasz; + void *neodata; + + assert(buf && buf->unit); + + if (neosz > BUFFER_MAX_ALLOC_SIZE) + return BUF_ENOMEM; + + if (buf->asize >= neosz) + return BUF_OK; + + neoasz = buf->asize + buf->unit; + while (neoasz < neosz) + neoasz += buf->unit; + + neodata = realloc(buf->data, neoasz); + if (!neodata) + return BUF_ENOMEM; + + buf->data = neodata; + buf->asize = neoasz; + return BUF_OK; +} + + +/* bufnew: allocation of a new buffer */ +extern __declspec(dllexport) struct buf * +bufnew(size_t unit) +{ + struct buf *ret; + ret = malloc(sizeof (struct buf)); + + if (ret) { + ret->data = 0; + ret->size = ret->asize = 0; + ret->unit = unit; + } + return ret; +} + +/* bufnullterm: NULL-termination of the string array */ +const char * +bufcstr(struct buf *buf) +{ + assert(buf && buf->unit); + + if (buf->size < buf->asize && buf->data[buf->size] == 0) + return (char *)buf->data; + + if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) { + buf->data[buf->size] = 0; + return (char *)buf->data; + } + + return NULL; +} + +/* bufprintf: formatted printing to a buffer */ +void +bufprintf(struct buf *buf, const char *fmt, ...) +{ + va_list ap; + int n; + + assert(buf && buf->unit); + + if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0) + return; + + va_start(ap, fmt); + n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); + va_end(ap); + + if (n < 0) { +#ifdef _MSC_VER + va_start(ap, fmt); + n = _vscprintf(fmt, ap); + va_end(ap); +#else + return; +#endif + } + + if ((size_t)n >= buf->asize - buf->size) { + if (bufgrow(buf, buf->size + n + 1) < 0) + return; + + va_start(ap, fmt); + n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); + va_end(ap); + } + + if (n < 0) + return; + + buf->size += n; +} + +/* bufput: appends raw data to a buffer */ +void +bufput(struct buf *buf, const void *data, size_t len) +{ + assert(buf && buf->unit); + + if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0) + return; + + memcpy(buf->data + buf->size, data, len); + buf->size += len; +} + +/* bufputs: appends a NUL-terminated string to a buffer */ +void +bufputs(struct buf *buf, const char *str) +{ + bufput(buf, str, strlen(str)); +} + + +/* bufputc: appends a single uint8_t to a buffer */ +void +bufputc(struct buf *buf, int c) +{ + assert(buf && buf->unit); + + if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0) + return; + + buf->data[buf->size] = c; + buf->size += 1; +} + +/* bufrelease: decrease the reference count and free the buffer if needed */ +void +bufrelease(struct buf *buf) +{ + if (!buf) + return; + + free(buf->data); + free(buf); +} + + +/* bufreset: frees internal data of the buffer */ +void +bufreset(struct buf *buf) +{ + if (!buf) + return; + + free(buf->data); + buf->data = NULL; + buf->size = buf->asize = 0; +} + +/* bufslurp: removes a given number of bytes from the head of the array */ +void +bufslurp(struct buf *buf, size_t len) +{ + assert(buf && buf->unit); + + if (len >= buf->size) { + buf->size = 0; + return; + } + + buf->size -= len; + memmove(buf->data, buf->data + len, buf->size); +} + diff --git a/Sundownlib/buffer.h b/Sundownlib/buffer.h new file mode 100644 index 0000000..02275d8 --- /dev/null +++ b/Sundownlib/buffer.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008, Natacha Porté + * Copyright (c) 2011, Vicent Martí + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef BUFFER_H__ +#define BUFFER_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) +#define __attribute__(x) +#define inline +#endif + +typedef enum { + BUF_OK = 0, + BUF_ENOMEM = -1, +} buferror_t; + +/* struct buf: character array buffer */ +struct buf { + uint8_t *data; /* actual character data */ + size_t size; /* size of the string */ + size_t asize; /* allocated size (0 = volatile buffer) */ + size_t unit; /* reallocation unit size (0 = read-only buffer) */ +}; + +/* CONST_BUF: global buffer from a string litteral */ +#define BUF_STATIC(string) \ + { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 } + +/* VOLATILE_BUF: macro for creating a volatile buffer on the stack */ +#define BUF_VOLATILE(strname) \ + { (uint8_t *)strname, strlen(strname), 0, 0, 0 } + +/* BUFPUTSL: optimized bufputs of a string litteral */ +#define BUFPUTSL(output, literal) \ + bufput(output, literal, sizeof literal - 1) + +/* bufgrow: increasing the allocated size to the given value */ +int bufgrow(struct buf *, size_t); + +/* bufnew: allocation of a new buffer */ +extern __declspec(dllexport) struct buf *bufnew(size_t) __attribute__ ((malloc)); + +/* bufnullterm: NUL-termination of the string array (making a C-string) */ +const char *bufcstr(struct buf *); + +/* bufprefix: compare the beginning of a buffer with a string */ +int bufprefix(const struct buf *buf, const char *prefix); + +/* bufput: appends raw data to a buffer */ +void bufput(struct buf *, const void *, size_t); + +/* bufputs: appends a NUL-terminated string to a buffer */ +void bufputs(struct buf *, const char *); + +/* bufputc: appends a single char to a buffer */ +void bufputc(struct buf *, int); + +/* bufrelease: decrease the reference count and free the buffer if needed */ +extern __declspec(dllexport) void bufrelease(struct buf *); + +/* bufreset: frees internal data of the buffer */ +void bufreset(struct buf *); + +/* bufslurp: removes a given number of bytes from the head of the array */ +void bufslurp(struct buf *, size_t); + +/* bufprintf: formatted printing to a buffer */ +void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sundownlib/houdini.h b/Sundownlib/houdini.h new file mode 100644 index 0000000..fda478c --- /dev/null +++ b/Sundownlib/houdini.h @@ -0,0 +1,37 @@ +#ifndef HOUDINI_H__ +#define HOUDINI_H__ + +#include "buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HOUDINI_USE_LOCALE +# define _isxdigit(c) isxdigit(c) +# define _isdigit(c) isdigit(c) +#else +/* + * Helper _isdigit methods -- do not trust the current locale + * */ +# define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL) +# define _isdigit(c) ((c) >= '0' && (c) <= '9') +#endif + +extern __declspec(dllexport) void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure); +extern __declspec(dllexport) void houdini_unescape_html(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_escape_xml(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_escape_uri(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_escape_url(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_unescape_uri(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_unescape_url(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size); +extern __declspec(dllexport) void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sundownlib/houdini_href_e.c b/Sundownlib/houdini_href_e.c new file mode 100644 index 0000000..981b3b1 --- /dev/null +++ b/Sundownlib/houdini_href_e.c @@ -0,0 +1,108 @@ +#include +#include +#include + +#include "houdini.h" + +#define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) + +/* + * The following characters will not be escaped: + * + * -_.+!*'(),%#@?=;:/,+&$ alphanum + * + * Note that this character set is the addition of: + * + * - The characters which are safe to be in an URL + * - The characters which are *not* safe to be in + * an URL because they are RESERVED characters. + * + * We asume (lazily) that any RESERVED char that + * appears inside an URL is actually meant to + * have its native function (i.e. as an URL + * component/separator) and hence needs no escaping. + * + * There are two exceptions: the chacters & (amp) + * and ' (single quote) do not appear in the table. + * They are meant to appear in the URL as components, + * yet they require special HTML-entity escaping + * to generate valid HTML markup. + * + * All other characters will be escaped to %XX. + * + */ +static const char HREF_SAFE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +void +houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size) +{ + static const char hex_chars[] = "0123456789ABCDEF"; + size_t i = 0, org; + char hex_str[3]; + + bufgrow(ob, ESCAPE_GROW_FACTOR(size)); + hex_str[0] = '%'; + + while (i < size) { + org = i; + while (i < size && HREF_SAFE[src[i]] != 0) + i++; + + if (i > org) + bufput(ob, src + org, i - org); + + /* escaping */ + if (i >= size) + break; + + switch (src[i]) { + /* amp appears all the time in URLs, but needs + * HTML-entity escaping to be inside an href */ + case '&': + BUFPUTSL(ob, "&"); + break; + + /* the single quote is a valid URL character + * according to the standard; it needs HTML + * entity escaping too */ + case '\'': + BUFPUTSL(ob, "'"); + break; + + /* the space can be escaped to %20 or a plus + * sign. we're going with the generic escape + * for now. the plus thing is more commonly seen + * when building GET strings */ +#if 0 + case ' ': + bufputc(ob, '+'); + break; +#endif + + /* every other character goes with a %XX escaping */ + default: + hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; + hex_str[2] = hex_chars[src[i] & 0xF]; + bufput(ob, hex_str, 3); + } + + i++; + } +} diff --git a/Sundownlib/houdini_html_e.c b/Sundownlib/houdini_html_e.c new file mode 100644 index 0000000..d9bbf18 --- /dev/null +++ b/Sundownlib/houdini_html_e.c @@ -0,0 +1,84 @@ +#include +#include +#include + +#include "houdini.h" + +#define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) /* this is very scientific, yes */ + +/** + * According to the OWASP rules: + * + * & --> & + * < --> < + * > --> > + * " --> " + * ' --> ' ' is not recommended + * / --> / forward slash is included as it helps end an HTML entity + * + */ +static const char HTML_ESCAPE_TABLE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const char *HTML_ESCAPES[] = { + "", + """, + "&", + "'", + "/", + "<", + ">" +}; + +void +houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure) +{ + size_t i = 0, org, esc = 0; + + bufgrow(ob, ESCAPE_GROW_FACTOR(size)); + + while (i < size) { + org = i; + while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) + i++; + + if (i > org) + bufput(ob, src + org, i - org); + + /* escaping */ + if (i >= size) + break; + + /* The forward slash is only escaped in secure mode */ + if (src[i] == '/' && !secure) { + bufputc(ob, '/'); + } else { + bufputs(ob, HTML_ESCAPES[esc]); + } + + i++; + } +} + +void +houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size) +{ + houdini_escape_html0(ob, src, size, 1); +} + diff --git a/Sundownlib/html.c b/Sundownlib/html.c new file mode 100644 index 0000000..7f08ee8 --- /dev/null +++ b/Sundownlib/html.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2009, Natacha Porté + * Copyright (c) 2011, Vicent Marti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "markdown.h" +#include "html.h" + +#include +#include +#include +#include + +#include "houdini.h" + +#define USE_XHTML(opt) (opt->flags & HTML_USE_XHTML) + +int +sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname) +{ + size_t i; + int closed = 0; + + if (tag_size < 3 || tag_data[0] != '<') + return HTML_TAG_NONE; + + i = 1; + + if (tag_data[i] == '/') { + closed = 1; + i++; + } + + for (; i < tag_size; ++i, ++tagname) { + if (*tagname == 0) + break; + + if (tag_data[i] != *tagname) + return HTML_TAG_NONE; + } + + if (i == tag_size) + return HTML_TAG_NONE; + + if (isspace(tag_data[i]) || tag_data[i] == '>') + return closed ? HTML_TAG_CLOSE : HTML_TAG_OPEN; + + return HTML_TAG_NONE; +} + +static inline void escape_html(struct buf *ob, const uint8_t *source, size_t length) +{ + houdini_escape_html0(ob, source, length, 0); +} + +static inline void escape_href(struct buf *ob, const uint8_t *source, size_t length) +{ + houdini_escape_href(ob, source, length); +} + +/******************** + * GENERIC RENDERER * + ********************/ +static int +rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque) +{ + struct html_renderopt *options = opaque; + + if (!link || !link->size) + return 0; + + if ((options->flags & HTML_SAFELINK) != 0 && + !sd_autolink_issafe(link->data, link->size) && + type != MKDA_EMAIL) + return 0; + + BUFPUTSL(ob, "data, link->size); + + if (options->link_attributes) { + bufputc(ob, '\"'); + options->link_attributes(ob, link, opaque); + bufputc(ob, '>'); + } else { + BUFPUTSL(ob, "\">"); + } + + /* + * Pretty printing: if we get an email address as + * an actual URI, e.g. `mailto:foo@bar.com`, we don't + * want to print the `mailto:` prefix + */ + if (bufprefix(link, "mailto:") == 0) { + escape_html(ob, link->data + 7, link->size - 7); + } else { + escape_html(ob, link->data, link->size); + } + + BUFPUTSL(ob, ""); + + return 1; +} + +static void +rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + + if (lang && lang->size) { + size_t i, cls; + BUFPUTSL(ob, "
    size; ++i, ++cls) {
    +			while (i < lang->size && isspace(lang->data[i]))
    +				i++;
    +
    +			if (i < lang->size) {
    +				size_t org = i;
    +				while (i < lang->size && !isspace(lang->data[i]))
    +					i++;
    +
    +				if (lang->data[org] == '.')
    +					org++;
    +
    +				if (cls) bufputc(ob, ' ');
    +				escape_html(ob, lang->data + org, i - org);
    +			}
    +		}
    +
    +		BUFPUTSL(ob, "\">");
    +	} else
    +		BUFPUTSL(ob, "
    ");
    +
    +	if (text)
    +		escape_html(ob, text->data, text->size);
    +
    +	BUFPUTSL(ob, "
    \n"); +} + +static void +rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + BUFPUTSL(ob, "
    \n"); + if (text) bufput(ob, text->data, text->size); + BUFPUTSL(ob, "
    \n"); +} + +static int +rndr_codespan(struct buf *ob, const struct buf *text, void *opaque) +{ + BUFPUTSL(ob, ""); + if (text) escape_html(ob, text->data, text->size); + BUFPUTSL(ob, ""); + return 1; +} + +static int +rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque) +{ + if (!text || !text->size) + return 0; + + BUFPUTSL(ob, ""); + bufput(ob, text->data, text->size); + BUFPUTSL(ob, ""); + return 1; +} + +static int +rndr_double_emphasis(struct buf *ob, const struct buf *text, void *opaque) +{ + if (!text || !text->size) + return 0; + + BUFPUTSL(ob, ""); + bufput(ob, text->data, text->size); + BUFPUTSL(ob, ""); + + return 1; +} + +static int +rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque) +{ + if (!text || !text->size) return 0; + BUFPUTSL(ob, ""); + if (text) bufput(ob, text->data, text->size); + BUFPUTSL(ob, ""); + return 1; +} + +static int +rndr_linebreak(struct buf *ob, void *opaque) +{ + struct html_renderopt *options = opaque; + bufputs(ob, USE_XHTML(options) ? "
    \n" : "
    \n"); + return 1; +} + +static void +rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque) +{ + struct html_renderopt *options = opaque; + + if (ob->size) + bufputc(ob, '\n'); + + if (options->flags & HTML_TOC) + bufprintf(ob, "", level, options->toc_data.header_count++); + else + bufprintf(ob, "", level); + + if (text) bufput(ob, text->data, text->size); + bufprintf(ob, "\n", level); +} + +static int +rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) +{ + struct html_renderopt *options = opaque; + + if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size)) + return 0; + + BUFPUTSL(ob, "size) + escape_href(ob, link->data, link->size); + + if (title && title->size) { + BUFPUTSL(ob, "\" title=\""); + escape_html(ob, title->data, title->size); + } + + if (options->link_attributes) { + bufputc(ob, '\"'); + options->link_attributes(ob, link, opaque); + bufputc(ob, '>'); + } else { + BUFPUTSL(ob, "\">"); + } + + if (content && content->size) bufput(ob, content->data, content->size); + BUFPUTSL(ob, ""); + return 1; +} + +static void +rndr_list(struct buf *ob, const struct buf *text, int flags, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + bufput(ob, flags & MKD_LIST_ORDERED ? "
      \n" : "
        \n", 5); + if (text) bufput(ob, text->data, text->size); + bufput(ob, flags & MKD_LIST_ORDERED ? "
    \n" : "\n", 6); +} + +static void +rndr_listitem(struct buf *ob, const struct buf *text, int flags, void *opaque) +{ + BUFPUTSL(ob, "
  • "); + if (text) { + size_t size = text->size; + while (size && text->data[size - 1] == '\n') + size--; + + bufput(ob, text->data, size); + } + BUFPUTSL(ob, "
  • \n"); +} + +static void +rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque) +{ + struct html_renderopt *options = opaque; + size_t i = 0; + + if (ob->size) bufputc(ob, '\n'); + + if (!text || !text->size) + return; + + while (i < text->size && isspace(text->data[i])) i++; + + if (i == text->size) + return; + + BUFPUTSL(ob, "

    "); + if (options->flags & HTML_HARD_WRAP) { + size_t org; + while (i < text->size) { + org = i; + while (i < text->size && text->data[i] != '\n') + i++; + + if (i > org) + bufput(ob, text->data + org, i - org); + + /* + * do not insert a line break if this newline + * is the last character on the paragraph + */ + if (i >= text->size - 1) + break; + + rndr_linebreak(ob, opaque); + i++; + } + } else { + bufput(ob, &text->data[i], text->size - i); + } + BUFPUTSL(ob, "

    \n"); +} + +static void +rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque) +{ + size_t org, sz; + if (!text) return; + sz = text->size; + while (sz > 0 && text->data[sz - 1] == '\n') sz--; + org = 0; + while (org < sz && text->data[org] == '\n') org++; + if (org >= sz) return; + if (ob->size) bufputc(ob, '\n'); + bufput(ob, text->data + org, sz - org); + bufputc(ob, '\n'); +} + +static int +rndr_triple_emphasis(struct buf *ob, const struct buf *text, void *opaque) +{ + if (!text || !text->size) return 0; + BUFPUTSL(ob, ""); + bufput(ob, text->data, text->size); + BUFPUTSL(ob, ""); + return 1; +} + +static void +rndr_hrule(struct buf *ob, void *opaque) +{ + struct html_renderopt *options = opaque; + if (ob->size) bufputc(ob, '\n'); + bufputs(ob, USE_XHTML(options) ? "
    \n" : "
    \n"); +} + +static int +rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque) +{ + struct html_renderopt *options = opaque; + if (!link || !link->size) return 0; + + BUFPUTSL(ob, "data, link->size); + BUFPUTSL(ob, "\" alt=\""); + + if (alt && alt->size) + escape_html(ob, alt->data, alt->size); + + if (title && title->size) { + BUFPUTSL(ob, "\" title=\""); + escape_html(ob, title->data, title->size); } + + bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">"); + return 1; +} + +static int +rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque) +{ + struct html_renderopt *options = opaque; + + /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES + * It doens't see if there are any valid tags, just escape all of them. */ + if((options->flags & HTML_ESCAPE) != 0) { + escape_html(ob, text->data, text->size); + return 1; + } + + if ((options->flags & HTML_SKIP_HTML) != 0) + return 1; + + if ((options->flags & HTML_SKIP_STYLE) != 0 && + sdhtml_is_tag(text->data, text->size, "style")) + return 1; + + if ((options->flags & HTML_SKIP_LINKS) != 0 && + sdhtml_is_tag(text->data, text->size, "a")) + return 1; + + if ((options->flags & HTML_SKIP_IMAGES) != 0 && + sdhtml_is_tag(text->data, text->size, "img")) + return 1; + + bufput(ob, text->data, text->size); + return 1; +} + +static void +rndr_table(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + BUFPUTSL(ob, "\n"); + if (header) + bufput(ob, header->data, header->size); + BUFPUTSL(ob, "\n"); + if (body) + bufput(ob, body->data, body->size); + BUFPUTSL(ob, "
    \n"); +} + +static void +rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque) +{ + BUFPUTSL(ob, "\n"); + if (text) + bufput(ob, text->data, text->size); + BUFPUTSL(ob, "\n"); +} + +static void +rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque) +{ + if (flags & MKD_TABLE_HEADER) { + BUFPUTSL(ob, ""); + break; + + case MKD_TABLE_ALIGN_L: + BUFPUTSL(ob, " align=\"left\">"); + break; + + case MKD_TABLE_ALIGN_R: + BUFPUTSL(ob, " align=\"right\">"); + break; + + default: + BUFPUTSL(ob, ">"); + } + + if (text) + bufput(ob, text->data, text->size); + + if (flags & MKD_TABLE_HEADER) { + BUFPUTSL(ob, "\n"); + } else { + BUFPUTSL(ob, "\n"); + } +} + +static int +rndr_superscript(struct buf *ob, const struct buf *text, void *opaque) +{ + if (!text || !text->size) return 0; + BUFPUTSL(ob, ""); + bufput(ob, text->data, text->size); + BUFPUTSL(ob, ""); + return 1; +} + +static void +rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque) +{ + if (text) + escape_html(ob, text->data, text->size); +} + +static void +toc_header(struct buf *ob, const struct buf *text, int level, void *opaque) +{ + struct html_renderopt *options = opaque; + + /* set the level offset if this is the first header + * we're parsing for the document */ + if (options->toc_data.current_level == 0) { + options->toc_data.level_offset = level - 1; + } + level -= options->toc_data.level_offset; + + if (level > options->toc_data.current_level) { + while (level > options->toc_data.current_level) { + BUFPUTSL(ob, "
      \n
    • \n"); + options->toc_data.current_level++; + } + } else if (level < options->toc_data.current_level) { + BUFPUTSL(ob, "
    • \n"); + while (level < options->toc_data.current_level) { + BUFPUTSL(ob, "
    \n\n"); + options->toc_data.current_level--; + } + BUFPUTSL(ob,"
  • \n"); + } else { + BUFPUTSL(ob,"
  • \n
  • \n"); + } + + bufprintf(ob, "", options->toc_data.header_count++); + if (text) + escape_html(ob, text->data, text->size); + BUFPUTSL(ob, "\n"); +} + +static int +toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) +{ + if (content && content->size) + bufput(ob, content->data, content->size); + return 1; +} + +static void +toc_finalize(struct buf *ob, void *opaque) +{ + struct html_renderopt *options = opaque; + + while (options->toc_data.current_level > 0) { + BUFPUTSL(ob, "
  • \n\n"); + options->toc_data.current_level--; + } +} + +void +sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options) +{ + static const struct sd_callbacks cb_default = { + NULL, + NULL, + NULL, + toc_header, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, + rndr_codespan, + rndr_double_emphasis, + rndr_emphasis, + NULL, + NULL, + toc_link, + NULL, + rndr_triple_emphasis, + rndr_strikethrough, + rndr_superscript, + + NULL, + NULL, + + NULL, + toc_finalize, + }; + + memset(options, 0x0, sizeof(struct html_renderopt)); + options->flags = HTML_TOC; + + memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); +} + +void +sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags) +{ + static const struct sd_callbacks cb_default = { + rndr_blockcode, + rndr_blockquote, + rndr_raw_block, + rndr_header, + rndr_hrule, + rndr_list, + rndr_listitem, + rndr_paragraph, + rndr_table, + rndr_tablerow, + rndr_tablecell, + + rndr_autolink, + rndr_codespan, + rndr_double_emphasis, + rndr_emphasis, + rndr_image, + rndr_linebreak, + rndr_link, + rndr_raw_html, + rndr_triple_emphasis, + rndr_strikethrough, + rndr_superscript, + + NULL, + rndr_normal_text, + + NULL, + NULL, + }; + + /* Prepare the options pointer */ + memset(options, 0x0, sizeof(struct html_renderopt)); + options->flags = render_flags; + + /* Prepare the callbacks */ + memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); + + if (render_flags & HTML_SKIP_IMAGES) + callbacks->image = NULL; + + if (render_flags & HTML_SKIP_LINKS) { + callbacks->link = NULL; + callbacks->autolink = NULL; + } + + if (render_flags & HTML_SKIP_HTML || render_flags & HTML_ESCAPE) + callbacks->blockhtml = NULL; +} diff --git a/Sundownlib/html.h b/Sundownlib/html.h new file mode 100644 index 0000000..af63df6 --- /dev/null +++ b/Sundownlib/html.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, Vicent Marti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UPSKIRT_HTML_H +#define UPSKIRT_HTML_H + +#include "markdown.h" +#include "buffer.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct html_renderopt { + struct { + int header_count; + int current_level; + int level_offset; + } toc_data; + + unsigned int flags; + + /* extra callbacks */ + void (*link_attributes)(struct buf *ob, const struct buf *url, void *self); +}; + +typedef enum { + HTML_SKIP_HTML = (1 << 0), + HTML_SKIP_STYLE = (1 << 1), + HTML_SKIP_IMAGES = (1 << 2), + HTML_SKIP_LINKS = (1 << 3), + HTML_EXPAND_TABS = (1 << 4), + HTML_SAFELINK = (1 << 5), + HTML_TOC = (1 << 6), + HTML_HARD_WRAP = (1 << 7), + HTML_USE_XHTML = (1 << 8), + HTML_ESCAPE = (1 << 9), +} html_render_mode; + +typedef enum { + HTML_TAG_NONE = 0, + HTML_TAG_OPEN, + HTML_TAG_CLOSE, +} html_tag; + +int +sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname); + +extern __declspec(dllexport) void +sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags); + +extern __declspec(dllexport) void +sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr); + +extern __declspec(dllexport) void +sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Sundownlib/html_blocks.h b/Sundownlib/html_blocks.h new file mode 100644 index 0000000..09a758f --- /dev/null +++ b/Sundownlib/html_blocks.h @@ -0,0 +1,206 @@ +/* C code produced by gperf version 3.0.3 */ +/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */ +/* Computed positions: -k'1-2' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +/* maximum key range = 37, duplicates = 0 */ + +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 + }; +#endif + +#ifndef GPERF_CASE_STRNCMP +#define GPERF_CASE_STRNCMP 1 +static int +gperf_case_strncmp (s1, s2, n) + register const char *s1; + register const char *s2; + register unsigned int n; +{ + for (; n > 0;) + { + unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; + unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; + if (c1 != 0 && c1 == c2) + { + n--; + continue; + } + return (int)c1 - (int)c2; + } + return 0; +} +#endif + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash_block_tag (str, len) + register const char *str; + register unsigned int len; +{ + static const unsigned char asso_values[] = + { + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 8, 30, 25, 20, 15, 10, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 0, 38, 0, 38, + 5, 5, 5, 15, 0, 38, 38, 0, 15, 10, + 0, 38, 38, 15, 0, 5, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 0, 38, + 0, 38, 5, 5, 5, 15, 0, 38, 38, 0, + 15, 10, 0, 38, 38, 15, 0, 5, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[1]+1]; + /*FALLTHROUGH*/ + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval; +} + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const char * +find_block_tag (str, len) + register const char *str; + register unsigned int len; +{ + enum + { + TOTAL_KEYWORDS = 24, + MIN_WORD_LENGTH = 1, + MAX_WORD_LENGTH = 10, + MIN_HASH_VALUE = 1, + MAX_HASH_VALUE = 37 + }; + + static const char * const wordlist[] = + { + "", + "p", + "dl", + "div", + "math", + "table", + "", + "ul", + "del", + "form", + "blockquote", + "figure", + "ol", + "fieldset", + "", + "h1", + "", + "h6", + "pre", + "", "", + "script", + "h5", + "noscript", + "", + "style", + "iframe", + "h4", + "ins", + "", "", "", + "h3", + "", "", "", "", + "h2" + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash_block_tag (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register const char *s = wordlist[key]; + + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') + return s; + } + } + return 0; +} diff --git a/Sundownlib/html_smartypants.c b/Sundownlib/html_smartypants.c new file mode 100644 index 0000000..367c26a --- /dev/null +++ b/Sundownlib/html_smartypants.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2011, Vicent Marti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "buffer.h" +#include "html.h" + +#include +#include +#include +#include + +#if defined(_WIN32) +#define snprintf _snprintf +#endif + +struct smartypants_data { + int in_squote; + int in_dquote; +}; + +static size_t smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); +static size_t smartypants_cb__escape(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); + +static size_t (*smartypants_cb_ptrs[]) + (struct buf *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) = +{ + NULL, /* 0 */ + smartypants_cb__dash, /* 1 */ + smartypants_cb__parens, /* 2 */ + smartypants_cb__squote, /* 3 */ + smartypants_cb__dquote, /* 4 */ + smartypants_cb__amp, /* 5 */ + smartypants_cb__period, /* 6 */ + smartypants_cb__number, /* 7 */ + smartypants_cb__ltag, /* 8 */ + smartypants_cb__backtick, /* 9 */ + smartypants_cb__escape, /* 10 */ +}; + +static const uint8_t smartypants_cb_chars[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0, + 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static inline int +word_boundary(uint8_t c) +{ + return c == 0 || isspace(c) || ispunct(c); +} + +static int +smartypants_quotes(struct buf *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open) +{ + char ent[8]; + + if (*is_open && !word_boundary(next_char)) + return 0; + + if (!(*is_open) && !word_boundary(previous_char)) + return 0; + + snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote); + *is_open = !(*is_open); + bufputs(ob, ent); + return 1; +} + +static size_t +smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size >= 2) { + uint8_t t1 = tolower(text[1]); + + if (t1 == '\'') { + if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) + return 1; + } + + if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && + (size == 3 || word_boundary(text[2]))) { + BUFPUTSL(ob, "’"); + return 0; + } + + if (size >= 3) { + uint8_t t2 = tolower(text[2]); + + if (((t1 == 'r' && t2 == 'e') || + (t1 == 'l' && t2 == 'l') || + (t1 == 'v' && t2 == 'e')) && + (size == 4 || word_boundary(text[3]))) { + BUFPUTSL(ob, "’"); + return 0; + } + } + } + + if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote)) + return 0; + + bufputc(ob, text[0]); + return 0; +} + +static size_t +smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size >= 3) { + uint8_t t1 = tolower(text[1]); + uint8_t t2 = tolower(text[2]); + + if (t1 == 'c' && t2 == ')') { + BUFPUTSL(ob, "©"); + return 2; + } + + if (t1 == 'r' && t2 == ')') { + BUFPUTSL(ob, "®"); + return 2; + } + + if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') { + BUFPUTSL(ob, "™"); + return 3; + } + } + + bufputc(ob, text[0]); + return 0; +} + +static size_t +smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size >= 3 && text[1] == '-' && text[2] == '-') { + BUFPUTSL(ob, "—"); + return 2; + } + + if (size >= 2 && text[1] == '-') { + BUFPUTSL(ob, "–"); + return 1; + } + + bufputc(ob, text[0]); + return 0; +} + +static size_t +smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size >= 6 && memcmp(text, """, 6) == 0) { + if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote)) + return 5; + } + + if (size >= 4 && memcmp(text, "�", 4) == 0) + return 3; + + bufputc(ob, '&'); + return 0; +} + +static size_t +smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size >= 3 && text[1] == '.' && text[2] == '.') { + BUFPUTSL(ob, "…"); + return 2; + } + + if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') { + BUFPUTSL(ob, "…"); + return 4; + } + + bufputc(ob, text[0]); + return 0; +} + +static size_t +smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size >= 2 && text[1] == '`') { + if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) + return 1; + } + + return 0; +} + +static size_t +smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (word_boundary(previous_char) && size >= 3) { + if (text[0] == '1' && text[1] == '/' && text[2] == '2') { + if (size == 3 || word_boundary(text[3])) { + BUFPUTSL(ob, "½"); + return 2; + } + } + + if (text[0] == '1' && text[1] == '/' && text[2] == '4') { + if (size == 3 || word_boundary(text[3]) || + (size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) { + BUFPUTSL(ob, "¼"); + return 2; + } + } + + if (text[0] == '3' && text[1] == '/' && text[2] == '4') { + if (size == 3 || word_boundary(text[3]) || + (size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) { + BUFPUTSL(ob, "¾"); + return 2; + } + } + } + + bufputc(ob, text[0]); + return 0; +} + +static size_t +smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote)) + BUFPUTSL(ob, """); + + return 0; +} + +static size_t +smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + static const char *skip_tags[] = { + "pre", "code", "var", "samp", "kbd", "math", "script", "style" + }; + static const size_t skip_tags_count = 8; + + size_t tag, i = 0; + + while (i < size && text[i] != '>') + i++; + + for (tag = 0; tag < skip_tags_count; ++tag) { + if (sdhtml_is_tag(text, size, skip_tags[tag]) == HTML_TAG_OPEN) + break; + } + + if (tag < skip_tags_count) { + for (;;) { + while (i < size && text[i] != '<') + i++; + + if (i == size) + break; + + if (sdhtml_is_tag(text + i, size - i, skip_tags[tag]) == HTML_TAG_CLOSE) + break; + + i++; + } + + while (i < size && text[i] != '>') + i++; + } + + bufput(ob, text, i + 1); + return i; +} + +static size_t +smartypants_cb__escape(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) +{ + if (size < 2) + return 0; + + switch (text[1]) { + case '\\': + case '"': + case '\'': + case '.': + case '-': + case '`': + bufputc(ob, text[1]); + return 1; + + default: + bufputc(ob, '\\'); + return 0; + } +} + +#if 0 +static struct { + uint8_t c0; + const uint8_t *pattern; + const uint8_t *entity; + int skip; +} smartypants_subs[] = { + { '\'', "'s>", "’", 0 }, + { '\'', "'t>", "’", 0 }, + { '\'', "'re>", "’", 0 }, + { '\'', "'ll>", "’", 0 }, + { '\'', "'ve>", "’", 0 }, + { '\'', "'m>", "’", 0 }, + { '\'', "'d>", "’", 0 }, + { '-', "--", "—", 1 }, + { '-', "<->", "–", 0 }, + { '.', "...", "…", 2 }, + { '.', ". . .", "…", 4 }, + { '(', "(c)", "©", 2 }, + { '(', "(r)", "®", 2 }, + { '(', "(tm)", "™", 3 }, + { '3', "<3/4>", "¾", 2 }, + { '3', "<3/4ths>", "¾", 2 }, + { '1', "<1/2>", "½", 2 }, + { '1', "<1/4>", "¼", 2 }, + { '1', "<1/4th>", "¼", 2 }, + { '&', "�", 0, 3 }, +}; +#endif + +void +sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size) +{ + size_t i; + struct smartypants_data smrt = {0, 0}; + + if (!text) + return; + + bufgrow(ob, size); + + for (i = 0; i < size; ++i) { + size_t org; + uint8_t action = 0; + + org = i; + while (i < size && (action = smartypants_cb_chars[text[i]]) == 0) + i++; + + if (i > org) + bufput(ob, text + org, i - org); + + if (i < size) { + i += smartypants_cb_ptrs[(int)action] + (ob, &smrt, i ? text[i - 1] : 0, text + i, size - i); + } + } +} + + diff --git a/Sundownlib/markdown.c b/Sundownlib/markdown.c new file mode 100644 index 0000000..ea3cf23 --- /dev/null +++ b/Sundownlib/markdown.c @@ -0,0 +1,2556 @@ +/* markdown.c - generic markdown parser */ + +/* + * Copyright (c) 2009, Natacha Porté + * Copyright (c) 2011, Vicent Marti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "markdown.h" +#include "stack.h" + +#include +#include +#include +#include + +#if defined(_WIN32) +#define strncasecmp _strnicmp +#endif + +#define REF_TABLE_SIZE 8 + +#define BUFFER_BLOCK 0 +#define BUFFER_SPAN 1 + +#define MKD_LI_END 8 /* internal list flag */ + +#define gperf_case_strncmp(s1, s2, n) strncasecmp(s1, s2, n) +#define GPERF_DOWNCASE 1 +#define GPERF_CASE_STRNCMP 1 +#include "html_blocks.h" + +/*************** + * LOCAL TYPES * + ***************/ + +/* link_ref: reference to a link */ +struct link_ref { + unsigned int id; + + struct buf *link; + struct buf *title; + + struct link_ref *next; +}; + +/* char_trigger: function pointer to render active chars */ +/* returns the number of chars taken care of */ +/* data is the pointer of the beginning of the span */ +/* offset is the number of valid chars before data */ +struct sd_markdown; +typedef size_t +(*char_trigger)(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); + +static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); +static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); + +enum markdown_char_t { + MD_CHAR_NONE = 0, + MD_CHAR_EMPHASIS, + MD_CHAR_CODESPAN, + MD_CHAR_LINEBREAK, + MD_CHAR_LINK, + MD_CHAR_LANGLE, + MD_CHAR_ESCAPE, + MD_CHAR_ENTITITY, + MD_CHAR_AUTOLINK_URL, + MD_CHAR_AUTOLINK_EMAIL, + MD_CHAR_AUTOLINK_WWW, + MD_CHAR_SUPERSCRIPT, +}; + +static char_trigger markdown_char_ptrs[] = { + NULL, + &char_emphasis, + &char_codespan, + &char_linebreak, + &char_link, + &char_langle_tag, + &char_escape, + &char_entity, + &char_autolink_url, + &char_autolink_email, + &char_autolink_www, + &char_superscript, +}; + +/* render • structure containing one particular render */ +struct sd_markdown { + struct sd_callbacks cb; + void *opaque; + + struct link_ref *refs[REF_TABLE_SIZE]; + uint8_t active_char[256]; + struct stack work_bufs[2]; + unsigned int ext_flags; + size_t max_nesting; + int in_link_body; +}; + +/*************************** + * HELPER FUNCTIONS * + ***************************/ + +static inline struct buf * +rndr_newbuf(struct sd_markdown *rndr, int type) +{ + static const size_t buf_size[2] = {256, 64}; + struct buf *work = NULL; + struct stack *pool = &rndr->work_bufs[type]; + + if (pool->size < pool->asize && + pool->item[pool->size] != NULL) { + work = pool->item[pool->size++]; + work->size = 0; + } else { + work = bufnew(buf_size[type]); + stack_push(pool, work); + } + + return work; +} + +static inline void +rndr_popbuf(struct sd_markdown *rndr, int type) +{ + rndr->work_bufs[type].size--; +} + +static void +unscape_text(struct buf *ob, struct buf *src) +{ + size_t i = 0, org; + while (i < src->size) { + org = i; + while (i < src->size && src->data[i] != '\\') + i++; + + if (i > org) + bufput(ob, src->data + org, i - org); + + if (i + 1 >= src->size) + break; + + bufputc(ob, src->data[i + 1]); + i += 2; + } +} + +static unsigned int +hash_link_ref(const uint8_t *link_ref, size_t length) +{ + size_t i; + unsigned int hash = 0; + + for (i = 0; i < length; ++i) + hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash; + + return hash; +} + +static struct link_ref * +add_link_ref( + struct link_ref **references, + const uint8_t *name, size_t name_size) +{ + struct link_ref *ref = calloc(1, sizeof(struct link_ref)); + + if (!ref) + return NULL; + + ref->id = hash_link_ref(name, name_size); + ref->next = references[ref->id % REF_TABLE_SIZE]; + + references[ref->id % REF_TABLE_SIZE] = ref; + return ref; +} + +static struct link_ref * +find_link_ref(struct link_ref **references, uint8_t *name, size_t length) +{ + unsigned int hash = hash_link_ref(name, length); + struct link_ref *ref = NULL; + + ref = references[hash % REF_TABLE_SIZE]; + + while (ref != NULL) { + if (ref->id == hash) + return ref; + + ref = ref->next; + } + + return NULL; +} + +static void +free_link_refs(struct link_ref **references) +{ + size_t i; + + for (i = 0; i < REF_TABLE_SIZE; ++i) { + struct link_ref *r = references[i]; + struct link_ref *next; + + while (r) { + next = r->next; + bufrelease(r->link); + bufrelease(r->title); + free(r); + r = next; + } + } +} + +/* + * Check whether a char is a Markdown space. + + * Right now we only consider spaces the actual + * space and a newline: tabs and carriage returns + * are filtered out during the preprocessing phase. + * + * If we wanted to actually be UTF-8 compliant, we + * should instead extract an Unicode codepoint from + * this character and check for space properties. + */ +static inline int +_isspace(int c) +{ + return c == ' ' || c == '\n'; +} + +/**************************** + * INLINE PARSING FUNCTIONS * + ****************************/ + +/* is_mail_autolink • looks for the address part of a mail autolink and '>' */ +/* this is less strict than the original markdown e-mail address matching */ +static size_t +is_mail_autolink(uint8_t *data, size_t size) +{ + size_t i = 0, nb = 0; + + /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */ + for (i = 0; i < size; ++i) { + if (isalnum(data[i])) + continue; + + switch (data[i]) { + case '@': + nb++; + + case '-': + case '.': + case '_': + break; + + case '>': + return (nb == 1) ? i + 1 : 0; + + default: + return 0; + } + } + + return 0; +} + +/* tag_length • returns the length of the given tag, or 0 is it's not valid */ +static size_t +tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink) +{ + size_t i, j; + + /* a valid tag can't be shorter than 3 chars */ + if (size < 3) return 0; + + /* begins with a '<' optionally followed by '/', followed by letter or number */ + if (data[0] != '<') return 0; + i = (data[1] == '/') ? 2 : 1; + + if (!isalnum(data[i])) + return 0; + + /* scheme test */ + *autolink = MKDA_NOT_AUTOLINK; + + /* try to find the beginning of an URI */ + while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-')) + i++; + + if (i > 1 && data[i] == '@') { + if ((j = is_mail_autolink(data + i, size - i)) != 0) { + *autolink = MKDA_EMAIL; + return i + j; + } + } + + if (i > 2 && data[i] == ':') { + *autolink = MKDA_NORMAL; + i++; + } + + /* completing autolink test: no whitespace or ' or " */ + if (i >= size) + *autolink = MKDA_NOT_AUTOLINK; + + else if (*autolink) { + j = i; + + while (i < size) { + if (data[i] == '\\') i += 2; + else if (data[i] == '>' || data[i] == '\'' || + data[i] == '"' || data[i] == ' ' || data[i] == '\n') + break; + else i++; + } + + if (i >= size) return 0; + if (i > j && data[i] == '>') return i + 1; + /* one of the forbidden chars has been found */ + *autolink = MKDA_NOT_AUTOLINK; + } + + /* looking for sometinhg looking like a tag end */ + while (i < size && data[i] != '>') i++; + if (i >= size) return 0; + return i + 1; +} + +/* parse_inline • parses inline markdown elements */ +static void +parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t i = 0, end = 0; + uint8_t action = 0; + struct buf work = { 0, 0, 0, 0 }; + + if (rndr->work_bufs[BUFFER_SPAN].size + + rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting) + return; + + while (i < size) { + /* copying inactive chars into the output */ + while (end < size && (action = rndr->active_char[data[end]]) == 0) { + end++; + } + + if (rndr->cb.normal_text) { + work.data = data + i; + work.size = end - i; + rndr->cb.normal_text(ob, &work, rndr->opaque); + } + else + bufput(ob, data + i, end - i); + + if (end >= size) break; + i = end; + + end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i); + if (!end) /* no action from the callback */ + end = i + 1; + else { + i += end; + end = i; + } + } +} + +/* find_emph_char • looks for the next emph uint8_t, skipping other constructs */ +static size_t +find_emph_char(uint8_t *data, size_t size, uint8_t c) +{ + size_t i = 1; + + while (i < size) { + while (i < size && data[i] != c && data[i] != '`' && data[i] != '[') + i++; + + if (i == size) + return 0; + + if (data[i] == c) + return i; + + /* not counting escaped chars */ + if (i && data[i - 1] == '\\') { + i++; continue; + } + + if (data[i] == '`') { + size_t span_nb = 0, bt; + size_t tmp_i = 0; + + /* counting the number of opening backticks */ + while (i < size && data[i] == '`') { + i++; span_nb++; + } + + if (i >= size) return 0; + + /* finding the matching closing sequence */ + bt = 0; + while (i < size && bt < span_nb) { + if (!tmp_i && data[i] == c) tmp_i = i; + if (data[i] == '`') bt++; + else bt = 0; + i++; + } + + if (i >= size) return tmp_i; + } + /* skipping a link */ + else if (data[i] == '[') { + size_t tmp_i = 0; + uint8_t cc; + + i++; + while (i < size && data[i] != ']') { + if (!tmp_i && data[i] == c) tmp_i = i; + i++; + } + + i++; + while (i < size && (data[i] == ' ' || data[i] == '\n')) + i++; + + if (i >= size) + return tmp_i; + + switch (data[i]) { + case '[': + cc = ']'; break; + + case '(': + cc = ')'; break; + + default: + if (tmp_i) + return tmp_i; + else + continue; + } + + i++; + while (i < size && data[i] != cc) { + if (!tmp_i && data[i] == c) tmp_i = i; + i++; + } + + if (i >= size) + return tmp_i; + + i++; + } + } + + return 0; +} + +/* parse_emph1 • parsing single emphase */ +/* closed by a symbol not preceded by whitespace and not followed by symbol */ +static size_t +parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) +{ + size_t i = 0, len; + struct buf *work = 0; + int r; + + if (!rndr->cb.emphasis) return 0; + + /* skipping one symbol if coming from emph3 */ + if (size > 1 && data[0] == c && data[1] == c) i = 1; + + while (i < size) { + len = find_emph_char(data + i, size - i, c); + if (!len) return 0; + i += len; + if (i >= size) return 0; + + if (data[i] == c && !_isspace(data[i - 1])) { + + if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) { + if (i + 1 < size && isalnum(data[i + 1])) + continue; + } + + work = rndr_newbuf(rndr, BUFFER_SPAN); + parse_inline(work, rndr, data, i); + r = rndr->cb.emphasis(ob, work, rndr->opaque); + rndr_popbuf(rndr, BUFFER_SPAN); + return r ? i + 1 : 0; + } + } + + return 0; +} + +/* parse_emph2 • parsing single emphase */ +static size_t +parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) +{ + int (*render_method)(struct buf *ob, const struct buf *text, void *opaque); + size_t i = 0, len; + struct buf *work = 0; + int r; + + render_method = (c == '~') ? rndr->cb.strikethrough : rndr->cb.double_emphasis; + + if (!render_method) + return 0; + + while (i < size) { + len = find_emph_char(data + i, size - i, c); + if (!len) return 0; + i += len; + + if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) { + work = rndr_newbuf(rndr, BUFFER_SPAN); + parse_inline(work, rndr, data, i); + r = render_method(ob, work, rndr->opaque); + rndr_popbuf(rndr, BUFFER_SPAN); + return r ? i + 2 : 0; + } + i++; + } + return 0; +} + +/* parse_emph3 • parsing single emphase */ +/* finds the first closing tag, and delegates to the other emph */ +static size_t +parse_emph3(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) +{ + size_t i = 0, len; + int r; + + while (i < size) { + len = find_emph_char(data + i, size - i, c); + if (!len) return 0; + i += len; + + /* skip whitespace preceded symbols */ + if (data[i] != c || _isspace(data[i - 1])) + continue; + + if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && rndr->cb.triple_emphasis) { + /* triple symbol found */ + struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN); + + parse_inline(work, rndr, data, i); + r = rndr->cb.triple_emphasis(ob, work, rndr->opaque); + rndr_popbuf(rndr, BUFFER_SPAN); + return r ? i + 3 : 0; + + } else if (i + 1 < size && data[i + 1] == c) { + /* double symbol found, handing over to emph1 */ + len = parse_emph1(ob, rndr, data - 2, size + 2, c); + if (!len) return 0; + else return len - 2; + + } else { + /* single symbol found, handing over to emph2 */ + len = parse_emph2(ob, rndr, data - 1, size + 1, c); + if (!len) return 0; + else return len - 1; + } + } + return 0; +} + +/* char_emphasis • single and double emphasis parsing */ +static size_t +char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + uint8_t c = data[0]; + size_t ret; + + if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) { + if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>') + return 0; + } + + if (size > 2 && data[1] != c) { + /* whitespace cannot follow an opening emphasis; + * strikethrough only takes two characters '~~' */ + if (c == '~' || _isspace(data[1]) || (ret = parse_emph1(ob, rndr, data + 1, size - 1, c)) == 0) + return 0; + + return ret + 1; + } + + if (size > 3 && data[1] == c && data[2] != c) { + if (_isspace(data[2]) || (ret = parse_emph2(ob, rndr, data + 2, size - 2, c)) == 0) + return 0; + + return ret + 2; + } + + if (size > 4 && data[1] == c && data[2] == c && data[3] != c) { + if (c == '~' || _isspace(data[3]) || (ret = parse_emph3(ob, rndr, data + 3, size - 3, c)) == 0) + return 0; + + return ret + 3; + } + + return 0; +} + + +/* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */ +static size_t +char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + if (offset < 2 || data[-1] != ' ' || data[-2] != ' ') + return 0; + + /* removing the last space from ob and rendering */ + while (ob->size && ob->data[ob->size - 1] == ' ') + ob->size--; + + return rndr->cb.linebreak(ob, rndr->opaque) ? 1 : 0; +} + + +/* char_codespan • '`' parsing a code span (assuming codespan != 0) */ +static size_t +char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + size_t end, nb = 0, i, f_begin, f_end; + + /* counting the number of backticks in the delimiter */ + while (nb < size && data[nb] == '`') + nb++; + + /* finding the next delimiter */ + i = 0; + for (end = nb; end < size && i < nb; end++) { + if (data[end] == '`') i++; + else i = 0; + } + + if (i < nb && end >= size) + return 0; /* no matching delimiter */ + + /* trimming outside whitespaces */ + f_begin = nb; + while (f_begin < end && data[f_begin] == ' ') + f_begin++; + + f_end = end - nb; + while (f_end > nb && data[f_end-1] == ' ') + f_end--; + + /* real code span */ + if (f_begin < f_end) { + struct buf work = { data + f_begin, f_end - f_begin, 0, 0 }; + if (!rndr->cb.codespan(ob, &work, rndr->opaque)) + end = 0; + } else { + if (!rndr->cb.codespan(ob, 0, rndr->opaque)) + end = 0; + } + + return end; +} + + +/* char_escape • '\\' backslash escape */ +static size_t +char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>^~"; + struct buf work = { 0, 0, 0, 0 }; + + if (size > 1) { + if (strchr(escape_chars, data[1]) == NULL) + return 0; + + if (rndr->cb.normal_text) { + work.data = data + 1; + work.size = 1; + rndr->cb.normal_text(ob, &work, rndr->opaque); + } + else bufputc(ob, data[1]); + } else if (size == 1) { + bufputc(ob, data[0]); + } + + return 2; +} + +/* char_entity • '&' escaped when it doesn't belong to an entity */ +/* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ +static size_t +char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + size_t end = 1; + struct buf work = { 0, 0, 0, 0 }; + + if (end < size && data[end] == '#') + end++; + + while (end < size && isalnum(data[end])) + end++; + + if (end < size && data[end] == ';') + end++; /* real entity */ + else + return 0; /* lone '&' */ + + if (rndr->cb.entity) { + work.data = data; + work.size = end; + rndr->cb.entity(ob, &work, rndr->opaque); + } + else bufput(ob, data, end); + + return end; +} + +/* char_langle_tag • '<' when tags or autolinks are allowed */ +static size_t +char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + enum mkd_autolink altype = MKDA_NOT_AUTOLINK; + size_t end = tag_length(data, size, &altype); + struct buf work = { data, end, 0, 0 }; + int ret = 0; + + if (end > 2) { + if (rndr->cb.autolink && altype != MKDA_NOT_AUTOLINK) { + struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN); + work.data = data + 1; + work.size = end - 2; + unscape_text(u_link, &work); + ret = rndr->cb.autolink(ob, u_link, altype, rndr->opaque); + rndr_popbuf(rndr, BUFFER_SPAN); + } + else if (rndr->cb.raw_html_tag) + ret = rndr->cb.raw_html_tag(ob, &work, rndr->opaque); + } + + if (!ret) return 0; + else return end; +} + +static size_t +char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + struct buf *link, *link_url, *link_text; + size_t link_len, rewind; + + if (!rndr->cb.link || rndr->in_link_body) + return 0; + + link = rndr_newbuf(rndr, BUFFER_SPAN); + + if ((link_len = sd_autolink__www(&rewind, link, data, offset, size, 0)) > 0) { + link_url = rndr_newbuf(rndr, BUFFER_SPAN); + BUFPUTSL(link_url, "http://"); + bufput(link_url, link->data, link->size); + + ob->size -= rewind; + if (rndr->cb.normal_text) { + link_text = rndr_newbuf(rndr, BUFFER_SPAN); + rndr->cb.normal_text(link_text, link, rndr->opaque); + rndr->cb.link(ob, link_url, NULL, link_text, rndr->opaque); + rndr_popbuf(rndr, BUFFER_SPAN); + } else { + rndr->cb.link(ob, link_url, NULL, link, rndr->opaque); + } + rndr_popbuf(rndr, BUFFER_SPAN); + } + + rndr_popbuf(rndr, BUFFER_SPAN); + return link_len; +} + +static size_t +char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + struct buf *link; + size_t link_len, rewind; + + if (!rndr->cb.autolink || rndr->in_link_body) + return 0; + + link = rndr_newbuf(rndr, BUFFER_SPAN); + + if ((link_len = sd_autolink__email(&rewind, link, data, offset, size, 0)) > 0) { + ob->size -= rewind; + rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque); + } + + rndr_popbuf(rndr, BUFFER_SPAN); + return link_len; +} + +static size_t +char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + struct buf *link; + size_t link_len, rewind; + + if (!rndr->cb.autolink || rndr->in_link_body) + return 0; + + link = rndr_newbuf(rndr, BUFFER_SPAN); + + if ((link_len = sd_autolink__url(&rewind, link, data, offset, size, 0)) > 0) { + ob->size -= rewind; + rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque); + } + + rndr_popbuf(rndr, BUFFER_SPAN); + return link_len; +} + +/* char_link • '[': parsing a link or an image */ +static size_t +char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + int is_img = (offset && data[-1] == '!'), level; + size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; + struct buf *content = 0; + struct buf *link = 0; + struct buf *title = 0; + struct buf *u_link = 0; + size_t org_work_size = rndr->work_bufs[BUFFER_SPAN].size; + int text_has_nl = 0, ret = 0; + int in_title = 0, qtype = 0; + + /* checking whether the correct renderer exists */ + if ((is_img && !rndr->cb.image) || (!is_img && !rndr->cb.link)) + goto cleanup; + + /* looking for the matching closing bracket */ + for (level = 1; i < size; i++) { + if (data[i] == '\n') + text_has_nl = 1; + + else if (data[i - 1] == '\\') + continue; + + else if (data[i] == '[') + level++; + + else if (data[i] == ']') { + level--; + if (level <= 0) + break; + } + } + + if (i >= size) + goto cleanup; + + txt_e = i; + i++; + + /* skip any amount of whitespace or newline */ + /* (this is much more laxist than original markdown syntax) */ + while (i < size && _isspace(data[i])) + i++; + + /* inline style link */ + if (i < size && data[i] == '(') { + /* skipping initial whitespace */ + i++; + + while (i < size && _isspace(data[i])) + i++; + + link_b = i; + + /* looking for link end: ' " ) */ + while (i < size) { + if (data[i] == '\\') i += 2; + else if (data[i] == ')') break; + else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break; + else i++; + } + + if (i >= size) goto cleanup; + link_e = i; + + /* looking for title end if present */ + if (data[i] == '\'' || data[i] == '"') { + qtype = data[i]; + in_title = 1; + i++; + title_b = i; + + while (i < size) { + if (data[i] == '\\') i += 2; + else if (data[i] == qtype) {in_title = 0; i++;} + else if ((data[i] == ')') && !in_title) break; + else i++; + } + + if (i >= size) goto cleanup; + + /* skipping whitespaces after title */ + title_e = i - 1; + while (title_e > title_b && _isspace(data[title_e])) + title_e--; + + /* checking for closing quote presence */ + if (data[title_e] != '\'' && data[title_e] != '"') { + title_b = title_e = 0; + link_e = i; + } + } + + /* remove whitespace at the end of the link */ + while (link_e > link_b && _isspace(data[link_e - 1])) + link_e--; + + /* remove optional angle brackets around the link */ + if (data[link_b] == '<') link_b++; + if (data[link_e - 1] == '>') link_e--; + + /* building escaped link and title */ + if (link_e > link_b) { + link = rndr_newbuf(rndr, BUFFER_SPAN); + bufput(link, data + link_b, link_e - link_b); + } + + if (title_e > title_b) { + title = rndr_newbuf(rndr, BUFFER_SPAN); + bufput(title, data + title_b, title_e - title_b); + } + + i++; + } + + /* reference style link */ + else if (i < size && data[i] == '[') { + struct buf id = { 0, 0, 0, 0 }; + struct link_ref *lr; + + /* looking for the id */ + i++; + link_b = i; + while (i < size && data[i] != ']') i++; + if (i >= size) goto cleanup; + link_e = i; + + /* finding the link_ref */ + if (link_b == link_e) { + if (text_has_nl) { + struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN); + size_t j; + + for (j = 1; j < txt_e; j++) { + if (data[j] != '\n') + bufputc(b, data[j]); + else if (data[j - 1] != ' ') + bufputc(b, ' '); + } + + id.data = b->data; + id.size = b->size; + } else { + id.data = data + 1; + id.size = txt_e - 1; + } + } else { + id.data = data + link_b; + id.size = link_e - link_b; + } + + lr = find_link_ref(rndr->refs, id.data, id.size); + if (!lr) + goto cleanup; + + /* keeping link and title from link_ref */ + link = lr->link; + title = lr->title; + i++; + } + + /* shortcut reference style link */ + else { + struct buf id = { 0, 0, 0, 0 }; + struct link_ref *lr; + + /* crafting the id */ + if (text_has_nl) { + struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN); + size_t j; + + for (j = 1; j < txt_e; j++) { + if (data[j] != '\n') + bufputc(b, data[j]); + else if (data[j - 1] != ' ') + bufputc(b, ' '); + } + + id.data = b->data; + id.size = b->size; + } else { + id.data = data + 1; + id.size = txt_e - 1; + } + + /* finding the link_ref */ + lr = find_link_ref(rndr->refs, id.data, id.size); + if (!lr) + goto cleanup; + + /* keeping link and title from link_ref */ + link = lr->link; + title = lr->title; + + /* rewinding the whitespace */ + i = txt_e + 1; + } + + /* building content: img alt is escaped, link content is parsed */ + if (txt_e > 1) { + content = rndr_newbuf(rndr, BUFFER_SPAN); + if (is_img) { + bufput(content, data + 1, txt_e - 1); + } else { + /* disable autolinking when parsing inline the + * content of a link */ + rndr->in_link_body = 1; + parse_inline(content, rndr, data + 1, txt_e - 1); + rndr->in_link_body = 0; + } + } + + if (link) { + u_link = rndr_newbuf(rndr, BUFFER_SPAN); + unscape_text(u_link, link); + } + + /* calling the relevant rendering function */ + if (is_img) { + if (ob->size && ob->data[ob->size - 1] == '!') + ob->size -= 1; + + ret = rndr->cb.image(ob, u_link, title, content, rndr->opaque); + } else { + ret = rndr->cb.link(ob, u_link, title, content, rndr->opaque); + } + + /* cleanup */ +cleanup: + rndr->work_bufs[BUFFER_SPAN].size = (int)org_work_size; + return ret ? i : 0; +} + +static size_t +char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) +{ + size_t sup_start, sup_len; + struct buf *sup; + + if (!rndr->cb.superscript) + return 0; + + if (size < 2) + return 0; + + if (data[1] == '(') { + sup_start = sup_len = 2; + + while (sup_len < size && data[sup_len] != ')' && data[sup_len - 1] != '\\') + sup_len++; + + if (sup_len == size) + return 0; + } else { + sup_start = sup_len = 1; + + while (sup_len < size && !_isspace(data[sup_len])) + sup_len++; + } + + if (sup_len - sup_start == 0) + return (sup_start == 2) ? 3 : 0; + + sup = rndr_newbuf(rndr, BUFFER_SPAN); + parse_inline(sup, rndr, data + sup_start, sup_len - sup_start); + rndr->cb.superscript(ob, sup, rndr->opaque); + rndr_popbuf(rndr, BUFFER_SPAN); + + return (sup_start == 2) ? sup_len + 1 : sup_len; +} + +/********************************* + * BLOCK-LEVEL PARSING FUNCTIONS * + *********************************/ + +/* is_empty • returns the line length when it is empty, 0 otherwise */ +static size_t +is_empty(uint8_t *data, size_t size) +{ + size_t i; + + for (i = 0; i < size && data[i] != '\n'; i++) + if (data[i] != ' ') + return 0; + + return i + 1; +} + +/* is_hrule • returns whether a line is a horizontal rule */ +static int +is_hrule(uint8_t *data, size_t size) +{ + size_t i = 0, n = 0; + uint8_t c; + + /* skipping initial spaces */ + if (size < 3) return 0; + if (data[0] == ' ') { i++; + if (data[1] == ' ') { i++; + if (data[2] == ' ') { i++; } } } + + /* looking at the hrule uint8_t */ + if (i + 2 >= size + || (data[i] != '*' && data[i] != '-' && data[i] != '_')) + return 0; + c = data[i]; + + /* the whole line must be the char or whitespace */ + while (i < size && data[i] != '\n') { + if (data[i] == c) n++; + else if (data[i] != ' ') + return 0; + + i++; + } + + return n >= 3; +} + +/* check if a line begins with a code fence; return the + * width of the code fence */ +static size_t +prefix_codefence(uint8_t *data, size_t size) +{ + size_t i = 0, n = 0; + uint8_t c; + + /* skipping initial spaces */ + if (size < 3) return 0; + if (data[0] == ' ') { i++; + if (data[1] == ' ') { i++; + if (data[2] == ' ') { i++; } } } + + /* looking at the hrule uint8_t */ + if (i + 2 >= size || !(data[i] == '~' || data[i] == '`')) + return 0; + + c = data[i]; + + /* the whole line must be the uint8_t or whitespace */ + while (i < size && data[i] == c) { + n++; i++; + } + + if (n < 3) + return 0; + + return i; +} + +/* check if a line is a code fence; return its size if it is */ +static size_t +is_codefence(uint8_t *data, size_t size, struct buf *syntax) +{ + size_t i = 0, syn_len = 0; + uint8_t *syn_start; + + i = prefix_codefence(data, size); + if (i == 0) + return 0; + + while (i < size && data[i] == ' ') + i++; + + syn_start = data + i; + + if (i < size && data[i] == '{') { + i++; syn_start++; + + while (i < size && data[i] != '}' && data[i] != '\n') { + syn_len++; i++; + } + + if (i == size || data[i] != '}') + return 0; + + /* strip all whitespace at the beginning and the end + * of the {} block */ + while (syn_len > 0 && _isspace(syn_start[0])) { + syn_start++; syn_len--; + } + + while (syn_len > 0 && _isspace(syn_start[syn_len - 1])) + syn_len--; + + i++; + } else { + while (i < size && !_isspace(data[i])) { + syn_len++; i++; + } + } + + if (syntax) { + syntax->data = syn_start; + syntax->size = syn_len; + } + + while (i < size && data[i] != '\n') { + if (!_isspace(data[i])) + return 0; + + i++; + } + + return i + 1; +} + +/* is_atxheader • returns whether the line is a hash-prefixed header */ +static int +is_atxheader(struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + if (data[0] != '#') + return 0; + + if (rndr->ext_flags & MKDEXT_SPACE_HEADERS) { + size_t level = 0; + + while (level < size && level < 6 && data[level] == '#') + level++; + + if (level < size && data[level] != ' ') + return 0; + } + + return 1; +} + +/* is_headerline • returns whether the line is a setext-style hdr underline */ +static int +is_headerline(uint8_t *data, size_t size) +{ + size_t i = 0; + + /* test of level 1 header */ + if (data[i] == '=') { + for (i = 1; i < size && data[i] == '='; i++); + while (i < size && data[i] == ' ') i++; + return (i >= size || data[i] == '\n') ? 1 : 0; } + + /* test of level 2 header */ + if (data[i] == '-') { + for (i = 1; i < size && data[i] == '-'; i++); + while (i < size && data[i] == ' ') i++; + return (i >= size || data[i] == '\n') ? 2 : 0; } + + return 0; +} + +static int +is_next_headerline(uint8_t *data, size_t size) +{ + size_t i = 0; + + while (i < size && data[i] != '\n') + i++; + + if (++i >= size) + return 0; + + return is_headerline(data + i, size - i); +} + +/* prefix_quote • returns blockquote prefix length */ +static size_t +prefix_quote(uint8_t *data, size_t size) +{ + size_t i = 0; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + + if (i < size && data[i] == '>') { + if (i + 1 < size && data[i + 1] == ' ') + return i + 2; + + return i + 1; + } + + return 0; +} + +/* prefix_code • returns prefix length for block code*/ +static size_t +prefix_code(uint8_t *data, size_t size) +{ + if (size > 3 && data[0] == ' ' && data[1] == ' ' + && data[2] == ' ' && data[3] == ' ') return 4; + + return 0; +} + +/* prefix_oli • returns ordered list item prefix */ +static size_t +prefix_oli(uint8_t *data, size_t size) +{ + size_t i = 0; + + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + + if (i >= size || data[i] < '0' || data[i] > '9') + return 0; + + while (i < size && data[i] >= '0' && data[i] <= '9') + i++; + + if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ') + return 0; + + if (is_next_headerline(data + i, size - i)) + return 0; + + return i + 2; +} + +/* prefix_uli • returns ordered list item prefix */ +static size_t +prefix_uli(uint8_t *data, size_t size) +{ + size_t i = 0; + + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + + if (i + 1 >= size || + (data[i] != '*' && data[i] != '+' && data[i] != '-') || + data[i + 1] != ' ') + return 0; + + if (is_next_headerline(data + i, size - i)) + return 0; + + return i + 2; +} + + +/* parse_block • parsing of one block, returning next uint8_t to parse */ +static void parse_block(struct buf *ob, struct sd_markdown *rndr, + uint8_t *data, size_t size); + + +/* parse_blockquote • handles parsing of a blockquote fragment */ +static size_t +parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t beg, end = 0, pre, work_size = 0; + uint8_t *work_data = 0; + struct buf *out = 0; + + out = rndr_newbuf(rndr, BUFFER_BLOCK); + beg = 0; + while (beg < size) { + for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); + + pre = prefix_quote(data + beg, end - beg); + + if (pre) + beg += pre; /* skipping prefix */ + + /* empty line followed by non-quote line */ + else if (is_empty(data + beg, end - beg) && + (end >= size || (prefix_quote(data + end, size - end) == 0 && + !is_empty(data + end, size - end)))) + break; + + if (beg < end) { /* copy into the in-place working buffer */ + /* bufput(work, data + beg, end - beg); */ + if (!work_data) + work_data = data + beg; + else if (data + beg != work_data + work_size) + memmove(work_data + work_size, data + beg, end - beg); + work_size += end - beg; + } + beg = end; + } + + parse_block(out, rndr, work_data, work_size); + if (rndr->cb.blockquote) + rndr->cb.blockquote(ob, out, rndr->opaque); + rndr_popbuf(rndr, BUFFER_BLOCK); + return end; +} + +static size_t +parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render); + +/* parse_blockquote • handles parsing of a regular paragraph */ +static size_t +parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t i = 0, end = 0; + int level = 0; + struct buf work = { data, 0, 0, 0 }; + + while (i < size) { + for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; + + if (is_empty(data + i, size - i)) + break; + + if ((level = is_headerline(data + i, size - i)) != 0) + break; + + if (is_atxheader(rndr, data + i, size - i) || + is_hrule(data + i, size - i) || + prefix_quote(data + i, size - i)) { + end = i; + break; + } + + /* + * Early termination of a paragraph with the same logic + * as Markdown 1.0.0. If this logic is applied, the + * Markdown 1.0.3 test suite won't pass cleanly + * + * :: If the first character in a new line is not a letter, + * let's check to see if there's some kind of block starting + * here + */ + if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) { + if (prefix_oli(data + i, size - i) || + prefix_uli(data + i, size - i)) { + end = i; + break; + } + + /* see if an html block starts here */ + if (data[i] == '<' && rndr->cb.blockhtml && + parse_htmlblock(ob, rndr, data + i, size - i, 0)) { + end = i; + break; + } + + /* see if a code fence starts here */ + if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && + is_codefence(data + i, size - i, NULL) != 0) { + end = i; + break; + } + } + + i = end; + } + + work.size = i; + while (work.size && data[work.size - 1] == '\n') + work.size--; + + if (!level) { + struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK); + parse_inline(tmp, rndr, work.data, work.size); + if (rndr->cb.paragraph) + rndr->cb.paragraph(ob, tmp, rndr->opaque); + rndr_popbuf(rndr, BUFFER_BLOCK); + } else { + struct buf *header_work; + + if (work.size) { + size_t beg; + i = work.size; + work.size -= 1; + + while (work.size && data[work.size] != '\n') + work.size -= 1; + + beg = work.size + 1; + while (work.size && data[work.size - 1] == '\n') + work.size -= 1; + + if (work.size > 0) { + struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK); + parse_inline(tmp, rndr, work.data, work.size); + + if (rndr->cb.paragraph) + rndr->cb.paragraph(ob, tmp, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_BLOCK); + work.data += beg; + work.size = i - beg; + } + else work.size = i; + } + + header_work = rndr_newbuf(rndr, BUFFER_SPAN); + parse_inline(header_work, rndr, work.data, work.size); + + if (rndr->cb.header) + rndr->cb.header(ob, header_work, (int)level, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_SPAN); + } + + return end; +} + +/* parse_fencedcode • handles parsing of a block-level code fragment */ +static size_t +parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t beg, end; + struct buf *work = 0; + struct buf lang = { 0, 0, 0, 0 }; + + beg = is_codefence(data, size, &lang); + if (beg == 0) return 0; + + work = rndr_newbuf(rndr, BUFFER_BLOCK); + + while (beg < size) { + size_t fence_end; + struct buf fence_trail = { 0, 0, 0, 0 }; + + fence_end = is_codefence(data + beg, size - beg, &fence_trail); + if (fence_end != 0 && fence_trail.size == 0) { + beg += fence_end; + break; + } + + for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); + + if (beg < end) { + /* verbatim copy to the working buffer, + escaping entities */ + if (is_empty(data + beg, end - beg)) + bufputc(work, '\n'); + else bufput(work, data + beg, end - beg); + } + beg = end; + } + + if (work->size && work->data[work->size - 1] != '\n') + bufputc(work, '\n'); + + if (rndr->cb.blockcode) + rndr->cb.blockcode(ob, work, lang.size ? &lang : NULL, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_BLOCK); + return beg; +} + +static size_t +parse_blockcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t beg, end, pre; + struct buf *work = 0; + + work = rndr_newbuf(rndr, BUFFER_BLOCK); + + beg = 0; + while (beg < size) { + for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {}; + pre = prefix_code(data + beg, end - beg); + + if (pre) + beg += pre; /* skipping prefix */ + else if (!is_empty(data + beg, end - beg)) + /* non-empty non-prefixed line breaks the pre */ + break; + + if (beg < end) { + /* verbatim copy to the working buffer, + escaping entities */ + if (is_empty(data + beg, end - beg)) + bufputc(work, '\n'); + else bufput(work, data + beg, end - beg); + } + beg = end; + } + + while (work->size && work->data[work->size - 1] == '\n') + work->size -= 1; + + bufputc(work, '\n'); + + if (rndr->cb.blockcode) + rndr->cb.blockcode(ob, work, NULL, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_BLOCK); + return beg; +} + +/* parse_listitem • parsing of a single list item */ +/* assuming initial prefix is already removed */ +static size_t +parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int *flags) +{ + struct buf *work = 0, *inter = 0; + size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; + int in_empty = 0, has_inside_empty = 0, in_fence = 0; + + /* keeping track of the first indentation prefix */ + while (orgpre < 3 && orgpre < size && data[orgpre] == ' ') + orgpre++; + + beg = prefix_uli(data, size); + if (!beg) + beg = prefix_oli(data, size); + + if (!beg) + return 0; + + /* skipping to the beginning of the following line */ + end = beg; + while (end < size && data[end - 1] != '\n') + end++; + + /* getting working buffers */ + work = rndr_newbuf(rndr, BUFFER_SPAN); + inter = rndr_newbuf(rndr, BUFFER_SPAN); + + /* putting the first line into the working buffer */ + bufput(work, data + beg, end - beg); + beg = end; + + /* process the following lines */ + while (beg < size) { + size_t has_next_uli = 0, has_next_oli = 0; + + end++; + + while (end < size && data[end - 1] != '\n') + end++; + + /* process an empty line */ + if (is_empty(data + beg, end - beg)) { + in_empty = 1; + beg = end; + continue; + } + + /* calculating the indentation */ + i = 0; + while (i < 4 && beg + i < end && data[beg + i] == ' ') + i++; + + pre = i; + + if (rndr->ext_flags & MKDEXT_FENCED_CODE) { + if (is_codefence(data + beg + i, end - beg - i, NULL) != 0) + in_fence = !in_fence; + } + + /* Only check for new list items if we are **not** inside + * a fenced code block */ + if (!in_fence) { + has_next_uli = prefix_uli(data + beg + i, end - beg - i); + has_next_oli = prefix_oli(data + beg + i, end - beg - i); + } + + /* checking for ul/ol switch */ + if (in_empty && ( + ((*flags & MKD_LIST_ORDERED) && has_next_uli) || + (!(*flags & MKD_LIST_ORDERED) && has_next_oli))){ + *flags |= MKD_LI_END; + break; /* the following item must have same list type */ + } + + /* checking for a new item */ + if ((has_next_uli && !is_hrule(data + beg + i, end - beg - i)) || has_next_oli) { + if (in_empty) + has_inside_empty = 1; + + if (pre == orgpre) /* the following item must have */ + break; /* the same indentation */ + + if (!sublist) + sublist = work->size; + } + /* joining only indented stuff after empty lines; + * note that now we only require 1 space of indentation + * to continue a list */ + else if (in_empty && pre == 0) { + *flags |= MKD_LI_END; + break; + } + else if (in_empty) { + bufputc(work, '\n'); + has_inside_empty = 1; + } + + in_empty = 0; + + /* adding the line without prefix into the working buffer */ + bufput(work, data + beg + i, end - beg - i); + beg = end; + } + + /* render of li contents */ + if (has_inside_empty) + *flags |= MKD_LI_BLOCK; + + if (*flags & MKD_LI_BLOCK) { + /* intermediate render of block li */ + if (sublist && sublist < work->size) { + parse_block(inter, rndr, work->data, sublist); + parse_block(inter, rndr, work->data + sublist, work->size - sublist); + } + else + parse_block(inter, rndr, work->data, work->size); + } else { + /* intermediate render of inline li */ + if (sublist && sublist < work->size) { + parse_inline(inter, rndr, work->data, sublist); + parse_block(inter, rndr, work->data + sublist, work->size - sublist); + } + else + parse_inline(inter, rndr, work->data, work->size); + } + + /* render of li itself */ + if (rndr->cb.listitem) + rndr->cb.listitem(ob, inter, *flags, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_SPAN); + rndr_popbuf(rndr, BUFFER_SPAN); + return beg; +} + + +/* parse_list • parsing ordered or unordered list block */ +static size_t +parse_list(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int flags) +{ + struct buf *work = 0; + size_t i = 0, j; + + work = rndr_newbuf(rndr, BUFFER_BLOCK); + + while (i < size) { + j = parse_listitem(work, rndr, data + i, size - i, &flags); + i += j; + + if (!j || (flags & MKD_LI_END)) + break; + } + + if (rndr->cb.list) + rndr->cb.list(ob, work, flags, rndr->opaque); + rndr_popbuf(rndr, BUFFER_BLOCK); + return i; +} + +/* parse_atxheader • parsing of atx-style headers */ +static size_t +parse_atxheader(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t level = 0; + size_t i, end, skip; + + while (level < size && level < 6 && data[level] == '#') + level++; + + for (i = level; i < size && data[i] == ' '; i++); + + for (end = i; end < size && data[end] != '\n'; end++); + skip = end; + + while (end && data[end - 1] == '#') + end--; + + while (end && data[end - 1] == ' ') + end--; + + if (end > i) { + struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN); + + parse_inline(work, rndr, data + i, end - i); + + if (rndr->cb.header) + rndr->cb.header(ob, work, (int)level, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_SPAN); + } + + return skip; +} + + +/* htmlblock_end • checking end of HTML block : [ \t]*\n[ \t*]\n */ +/* returns the length on match, 0 otherwise */ +static size_t +htmlblock_end_tag( + const char *tag, + size_t tag_len, + struct sd_markdown *rndr, + uint8_t *data, + size_t size) +{ + size_t i, w; + + /* checking if tag is a match */ + if (tag_len + 3 >= size || + strncasecmp((char *)data + 2, tag, tag_len) != 0 || + data[tag_len + 2] != '>') + return 0; + + /* checking white lines */ + i = tag_len + 3; + w = 0; + if (i < size && (w = is_empty(data + i, size - i)) == 0) + return 0; /* non-blank after tag */ + i += w; + w = 0; + + if (i < size) + w = is_empty(data + i, size - i); + + return i + w; +} + +static size_t +htmlblock_end(const char *curtag, + struct sd_markdown *rndr, + uint8_t *data, + size_t size, + int start_of_line) +{ + size_t tag_size = strlen(curtag); + size_t i = 1, end_tag; + int block_lines = 0; + + while (i < size) { + i++; + while (i < size && !(data[i - 1] == '<' && data[i] == '/')) { + if (data[i] == '\n') + block_lines++; + + i++; + } + + /* If we are only looking for unindented tags, skip the tag + * if it doesn't follow a newline. + * + * The only exception to this is if the tag is still on the + * initial line; in that case it still counts as a closing + * tag + */ + if (start_of_line && block_lines > 0 && data[i - 2] != '\n') + continue; + + if (i + 2 + tag_size >= size) + break; + + end_tag = htmlblock_end_tag(curtag, tag_size, rndr, data + i - 1, size - i + 1); + if (end_tag) + return i + end_tag - 1; + } + + return 0; +} + + +/* parse_htmlblock • parsing of inline HTML block */ +static size_t +parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render) +{ + size_t i, j = 0, tag_end; + const char *curtag = NULL; + struct buf work = { data, 0, 0, 0 }; + + /* identification of the opening tag */ + if (size < 2 || data[0] != '<') + return 0; + + i = 1; + while (i < size && data[i] != '>' && data[i] != ' ') + i++; + + if (i < size) + curtag = find_block_tag((char *)data + 1, (int)i - 1); + + /* handling of special cases */ + if (!curtag) { + + /* HTML comment, laxist form */ + if (size > 5 && data[1] == '!' && data[2] == '-' && data[3] == '-') { + i = 5; + + while (i < size && !(data[i - 2] == '-' && data[i - 1] == '-' && data[i] == '>')) + i++; + + i++; + + if (i < size) + j = is_empty(data + i, size - i); + + if (j) { + work.size = i + j; + if (do_render && rndr->cb.blockhtml) + rndr->cb.blockhtml(ob, &work, rndr->opaque); + return work.size; + } + } + + /* HR, which is the only self-closing block tag considered */ + if (size > 4 && (data[1] == 'h' || data[1] == 'H') && (data[2] == 'r' || data[2] == 'R')) { + i = 3; + while (i < size && data[i] != '>') + i++; + + if (i + 1 < size) { + i++; + j = is_empty(data + i, size - i); + if (j) { + work.size = i + j; + if (do_render && rndr->cb.blockhtml) + rndr->cb.blockhtml(ob, &work, rndr->opaque); + return work.size; + } + } + } + + /* no special case recognised */ + return 0; + } + + /* looking for an unindented matching closing tag */ + /* followed by a blank line */ + tag_end = htmlblock_end(curtag, rndr, data, size, 1); + + /* if not found, trying a second pass looking for indented match */ + /* but not if tag is "ins" or "del" (following original Markdown.pl) */ + if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) { + tag_end = htmlblock_end(curtag, rndr, data, size, 0); + } + + if (!tag_end) + return 0; + + /* the end of the block has been found */ + work.size = tag_end; + if (do_render && rndr->cb.blockhtml) + rndr->cb.blockhtml(ob, &work, rndr->opaque); + + return tag_end; +} + +static void +parse_table_row( + struct buf *ob, + struct sd_markdown *rndr, + uint8_t *data, + size_t size, + size_t columns, + int *col_data, + int header_flag) +{ + size_t i = 0, col; + struct buf *row_work = 0; + + if (!rndr->cb.table_cell || !rndr->cb.table_row) + return; + + row_work = rndr_newbuf(rndr, BUFFER_SPAN); + + if (i < size && data[i] == '|') + i++; + + for (col = 0; col < columns && i < size; ++col) { + size_t cell_start, cell_end; + struct buf *cell_work; + + cell_work = rndr_newbuf(rndr, BUFFER_SPAN); + + while (i < size && _isspace(data[i])) + i++; + + cell_start = i; + + while (i < size && data[i] != '|') + i++; + + cell_end = i - 1; + + while (cell_end > cell_start && _isspace(data[cell_end])) + cell_end--; + + parse_inline(cell_work, rndr, data + cell_start, 1 + cell_end - cell_start); + rndr->cb.table_cell(row_work, cell_work, col_data[col] | header_flag, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_SPAN); + i++; + } + + for (; col < columns; ++col) { + struct buf empty_cell = { 0, 0, 0, 0 }; + rndr->cb.table_cell(row_work, &empty_cell, col_data[col] | header_flag, rndr->opaque); + } + + rndr->cb.table_row(ob, row_work, rndr->opaque); + + rndr_popbuf(rndr, BUFFER_SPAN); +} + +static size_t +parse_table_header( + struct buf *ob, + struct sd_markdown *rndr, + uint8_t *data, + size_t size, + size_t *columns, + int **column_data) +{ + int pipes; + size_t i = 0, col, header_end, under_end; + + pipes = 0; + while (i < size && data[i] != '\n') + if (data[i++] == '|') + pipes++; + + if (i == size || pipes == 0) + return 0; + + header_end = i; + + while (header_end > 0 && _isspace(data[header_end - 1])) + header_end--; + + if (data[0] == '|') + pipes--; + + if (header_end && data[header_end - 1] == '|') + pipes--; + + *columns = pipes + 1; + *column_data = calloc(*columns, sizeof(int)); + + /* Parse the header underline */ + i++; + if (i < size && data[i] == '|') + i++; + + under_end = i; + while (under_end < size && data[under_end] != '\n') + under_end++; + + for (col = 0; col < *columns && i < under_end; ++col) { + size_t dashes = 0; + + while (i < under_end && data[i] == ' ') + i++; + + if (data[i] == ':') { + i++; (*column_data)[col] |= MKD_TABLE_ALIGN_L; + dashes++; + } + + while (i < under_end && data[i] == '-') { + i++; dashes++; + } + + if (i < under_end && data[i] == ':') { + i++; (*column_data)[col] |= MKD_TABLE_ALIGN_R; + dashes++; + } + + while (i < under_end && data[i] == ' ') + i++; + + if (i < under_end && data[i] != '|') + break; + + if (dashes < 3) + break; + + i++; + } + + if (col < *columns) + return 0; + + parse_table_row( + ob, rndr, data, + header_end, + *columns, + *column_data, + MKD_TABLE_HEADER + ); + + return under_end + 1; +} + +static size_t +parse_table( + struct buf *ob, + struct sd_markdown *rndr, + uint8_t *data, + size_t size) +{ + size_t i; + + struct buf *header_work = 0; + struct buf *body_work = 0; + + size_t columns; + int *col_data = NULL; + + header_work = rndr_newbuf(rndr, BUFFER_SPAN); + body_work = rndr_newbuf(rndr, BUFFER_BLOCK); + + i = parse_table_header(header_work, rndr, data, size, &columns, &col_data); + if (i > 0) { + + while (i < size) { + size_t row_start; + int pipes = 0; + + row_start = i; + + while (i < size && data[i] != '\n') + if (data[i++] == '|') + pipes++; + + if (pipes == 0 || i == size) { + i = row_start; + break; + } + + parse_table_row( + body_work, + rndr, + data + row_start, + i - row_start, + columns, + col_data, 0 + ); + + i++; + } + + if (rndr->cb.table) + rndr->cb.table(ob, header_work, body_work, rndr->opaque); + } + + free(col_data); + rndr_popbuf(rndr, BUFFER_SPAN); + rndr_popbuf(rndr, BUFFER_BLOCK); + return i; +} + +/* parse_block • parsing of one block, returning next uint8_t to parse */ +static void +parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) +{ + size_t beg, end, i; + uint8_t *txt_data; + beg = 0; + + if (rndr->work_bufs[BUFFER_SPAN].size + + rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting) + return; + + while (beg < size) { + txt_data = data + beg; + end = size - beg; + + if (is_atxheader(rndr, txt_data, end)) + beg += parse_atxheader(ob, rndr, txt_data, end); + + else if (data[beg] == '<' && rndr->cb.blockhtml && + (i = parse_htmlblock(ob, rndr, txt_data, end, 1)) != 0) + beg += i; + + else if ((i = is_empty(txt_data, end)) != 0) + beg += i; + + else if (is_hrule(txt_data, end)) { + if (rndr->cb.hrule) + rndr->cb.hrule(ob, rndr->opaque); + + while (beg < size && data[beg] != '\n') + beg++; + + beg++; + } + + else if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && + (i = parse_fencedcode(ob, rndr, txt_data, end)) != 0) + beg += i; + + else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 && + (i = parse_table(ob, rndr, txt_data, end)) != 0) + beg += i; + + else if (prefix_quote(txt_data, end)) + beg += parse_blockquote(ob, rndr, txt_data, end); + + else if (prefix_code(txt_data, end)) + beg += parse_blockcode(ob, rndr, txt_data, end); + + else if (prefix_uli(txt_data, end)) + beg += parse_list(ob, rndr, txt_data, end, 0); + + else if (prefix_oli(txt_data, end)) + beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); + + else + beg += parse_paragraph(ob, rndr, txt_data, end); + } +} + + + +/********************* + * REFERENCE PARSING * + *********************/ + +/* is_ref • returns whether a line is a reference or not */ +static int +is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_ref **refs) +{ +/* int n; */ + size_t i = 0; + size_t id_offset, id_end; + size_t link_offset, link_end; + size_t title_offset, title_end; + size_t line_end; + + /* up to 3 optional leading spaces */ + if (beg + 3 >= end) return 0; + if (data[beg] == ' ') { i = 1; + if (data[beg + 1] == ' ') { i = 2; + if (data[beg + 2] == ' ') { i = 3; + if (data[beg + 3] == ' ') return 0; } } } + i += beg; + + /* id part: anything but a newline between brackets */ + if (data[i] != '[') return 0; + i++; + id_offset = i; + while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') + i++; + if (i >= end || data[i] != ']') return 0; + id_end = i; + + /* spacer: colon (space | tab)* newline? (space | tab)* */ + i++; + if (i >= end || data[i] != ':') return 0; + i++; + while (i < end && data[i] == ' ') i++; + if (i < end && (data[i] == '\n' || data[i] == '\r')) { + i++; + if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; } + while (i < end && data[i] == ' ') i++; + if (i >= end) return 0; + + /* link: whitespace-free sequence, optionally between angle brackets */ + if (data[i] == '<') + i++; + + link_offset = i; + + while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r') + i++; + + if (data[i - 1] == '>') link_end = i - 1; + else link_end = i; + + /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ + while (i < end && data[i] == ' ') i++; + if (i < end && data[i] != '\n' && data[i] != '\r' + && data[i] != '\'' && data[i] != '"' && data[i] != '(') + return 0; + line_end = 0; + /* computing end-of-line */ + if (i >= end || data[i] == '\r' || data[i] == '\n') line_end = i; + if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') + line_end = i + 1; + + /* optional (space|tab)* spacer after a newline */ + if (line_end) { + i = line_end + 1; + while (i < end && data[i] == ' ') i++; } + + /* optional title: any non-newline sequence enclosed in '"() + alone on its line */ + title_offset = title_end = 0; + if (i + 1 < end + && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { + i++; + title_offset = i; + /* looking for EOL */ + while (i < end && data[i] != '\n' && data[i] != '\r') i++; + if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') + title_end = i + 1; + else title_end = i; + /* stepping back */ + i -= 1; + while (i > title_offset && data[i] == ' ') + i -= 1; + if (i > title_offset + && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { + line_end = title_end; + title_end = i; } } + + if (!line_end || link_end == link_offset) + return 0; /* garbage after the link empty link */ + + /* a valid ref has been found, filling-in return structures */ + if (last) + *last = line_end; + + if (refs) { + struct link_ref *ref; + + ref = add_link_ref(refs, data + id_offset, id_end - id_offset); + if (!ref) + return 0; + + ref->link = bufnew(link_end - link_offset); + bufput(ref->link, data + link_offset, link_end - link_offset); + + if (title_end > title_offset) { + ref->title = bufnew(title_end - title_offset); + bufput(ref->title, data + title_offset, title_end - title_offset); + } + } + + return 1; +} + +static void expand_tabs(struct buf *ob, const uint8_t *line, size_t size) +{ + size_t i = 0, tab = 0; + + while (i < size) { + size_t org = i; + + while (i < size && line[i] != '\t') { + i++; tab++; + } + + if (i > org) + bufput(ob, line + org, i - org); + + if (i >= size) + break; + + do { + bufputc(ob, ' '); tab++; + } while (tab % 4); + + i++; + } +} + +/********************** + * EXPORTED FUNCTIONS * + **********************/ + +struct sd_markdown * +sd_markdown_new( + unsigned int extensions, + size_t max_nesting, + const struct sd_callbacks *callbacks, + void *opaque) +{ + struct sd_markdown *md = NULL; + + assert(max_nesting > 0 && callbacks); + + md = malloc(sizeof(struct sd_markdown)); + if (!md) + return NULL; + + memcpy(&md->cb, callbacks, sizeof(struct sd_callbacks)); + + stack_init(&md->work_bufs[BUFFER_BLOCK], 4); + stack_init(&md->work_bufs[BUFFER_SPAN], 8); + + memset(md->active_char, 0x0, 256); + + if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) { + md->active_char['*'] = MD_CHAR_EMPHASIS; + md->active_char['_'] = MD_CHAR_EMPHASIS; + if (extensions & MKDEXT_STRIKETHROUGH) + md->active_char['~'] = MD_CHAR_EMPHASIS; + } + + if (md->cb.codespan) + md->active_char['`'] = MD_CHAR_CODESPAN; + + if (md->cb.linebreak) + md->active_char['\n'] = MD_CHAR_LINEBREAK; + + if (md->cb.image || md->cb.link) + md->active_char['['] = MD_CHAR_LINK; + + md->active_char['<'] = MD_CHAR_LANGLE; + md->active_char['\\'] = MD_CHAR_ESCAPE; + md->active_char['&'] = MD_CHAR_ENTITITY; + + if (extensions & MKDEXT_AUTOLINK) { + md->active_char[':'] = MD_CHAR_AUTOLINK_URL; + md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; + md->active_char['w'] = MD_CHAR_AUTOLINK_WWW; + } + + if (extensions & MKDEXT_SUPERSCRIPT) + md->active_char['^'] = MD_CHAR_SUPERSCRIPT; + + /* Extension data */ + md->ext_flags = extensions; + md->opaque = opaque; + md->max_nesting = max_nesting; + md->in_link_body = 0; + + return md; +} + +void +sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md) +{ +#define MARKDOWN_GROW(x) ((x) + ((x) >> 1)) + static const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF}; + + struct buf *text; + size_t beg, end; + + text = bufnew(64); + if (!text) + return; + + /* Preallocate enough space for our buffer to avoid expanding while copying */ + bufgrow(text, doc_size); + + /* reset the references table */ + memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); + + /* first pass: looking for references, copying everything else */ + beg = 0; + + /* Skip a possible UTF-8 BOM, even though the Unicode standard + * discourages having these in UTF-8 documents */ + if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0) + beg += 3; + + while (beg < doc_size) /* iterating over lines */ + if (is_ref(document, beg, doc_size, &end, md->refs)) + beg = end; + else { /* skipping to the next line */ + end = beg; + while (end < doc_size && document[end] != '\n' && document[end] != '\r') + end++; + + /* adding the line body if present */ + if (end > beg) + expand_tabs(text, document + beg, end - beg); + + while (end < doc_size && (document[end] == '\n' || document[end] == '\r')) { + /* add one \n per newline */ + if (document[end] == '\n' || (end + 1 < doc_size && document[end + 1] != '\n')) + bufputc(text, '\n'); + end++; + } + + beg = end; + } + + /* pre-grow the output buffer to minimize allocations */ + bufgrow(ob, MARKDOWN_GROW(text->size)); + + /* second pass: actual rendering */ + if (md->cb.doc_header) + md->cb.doc_header(ob, md->opaque); + + if (text->size) { + /* adding a final newline if not already present */ + if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r') + bufputc(text, '\n'); + + parse_block(ob, md, text->data, text->size); + } + + if (md->cb.doc_footer) + md->cb.doc_footer(ob, md->opaque); + + /* clean-up */ + bufrelease(text); + free_link_refs(md->refs); + + assert(md->work_bufs[BUFFER_SPAN].size == 0); + assert(md->work_bufs[BUFFER_BLOCK].size == 0); +} + +void +sd_markdown_free(struct sd_markdown *md) +{ + size_t i; + + for (i = 0; i < (size_t)md->work_bufs[BUFFER_SPAN].asize; ++i) + bufrelease(md->work_bufs[BUFFER_SPAN].item[i]); + + for (i = 0; i < (size_t)md->work_bufs[BUFFER_BLOCK].asize; ++i) + bufrelease(md->work_bufs[BUFFER_BLOCK].item[i]); + + stack_free(&md->work_bufs[BUFFER_SPAN]); + stack_free(&md->work_bufs[BUFFER_BLOCK]); + + free(md); +} + +void +sd_version(int *ver_major, int *ver_minor, int *ver_revision) +{ + *ver_major = SUNDOWN_VER_MAJOR; + *ver_minor = SUNDOWN_VER_MINOR; + *ver_revision = SUNDOWN_VER_REVISION; +} + +/* vim: set filetype=c: */ diff --git a/Sundownlib/markdown.h b/Sundownlib/markdown.h new file mode 100644 index 0000000..5ec83e2 --- /dev/null +++ b/Sundownlib/markdown.h @@ -0,0 +1,138 @@ +/* markdown.h - generic markdown parser */ + +/* + * Copyright (c) 2009, Natacha Porté + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UPSKIRT_MARKDOWN_H +#define UPSKIRT_MARKDOWN_H + +#include "buffer.h" +#include "autolink.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUNDOWN_VERSION "1.16.0" +#define SUNDOWN_VER_MAJOR 1 +#define SUNDOWN_VER_MINOR 16 +#define SUNDOWN_VER_REVISION 0 + +/******************** + * TYPE DEFINITIONS * + ********************/ + +/* mkd_autolink - type of autolink */ +enum mkd_autolink { + MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ + MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */ + MKDA_EMAIL, /* e-mail link without explit mailto: */ +}; + +enum mkd_tableflags { + MKD_TABLE_ALIGN_L = 1, + MKD_TABLE_ALIGN_R = 2, + MKD_TABLE_ALIGN_CENTER = 3, + MKD_TABLE_ALIGNMASK = 3, + MKD_TABLE_HEADER = 4 +}; + +enum mkd_extensions { + MKDEXT_NO_INTRA_EMPHASIS = (1 << 0), + MKDEXT_TABLES = (1 << 1), + MKDEXT_FENCED_CODE = (1 << 2), + MKDEXT_AUTOLINK = (1 << 3), + MKDEXT_STRIKETHROUGH = (1 << 4), + MKDEXT_SPACE_HEADERS = (1 << 6), + MKDEXT_SUPERSCRIPT = (1 << 7), + MKDEXT_LAX_SPACING = (1 << 8), +}; + +/* sd_callbacks - functions for rendering parsed data */ +struct sd_callbacks { + /* block level callbacks - NULL skips the block */ + void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque); + void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque); + void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque); + void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque); + void (*hrule)(struct buf *ob, void *opaque); + void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque); + void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque); + void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque); + void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque); + void (*table_row)(struct buf *ob, const struct buf *text, void *opaque); + void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque); + + + /* span level callbacks - NULL or return 0 prints the span verbatim */ + int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque); + int (*codespan)(struct buf *ob, const struct buf *text, void *opaque); + int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque); + int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque); + int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque); + int (*linebreak)(struct buf *ob, void *opaque); + int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque); + int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque); + int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque); + int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque); + int (*superscript)(struct buf *ob, const struct buf *text, void *opaque); + + /* low level callbacks - NULL copies input directly into the output */ + void (*entity)(struct buf *ob, const struct buf *entity, void *opaque); + void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque); + + /* header and footer */ + void (*doc_header)(struct buf *ob, void *opaque); + void (*doc_footer)(struct buf *ob, void *opaque); +}; + +struct sd_markdown; + +/********* + * FLAGS * + *********/ + +/* list/listitem flags */ +#define MKD_LIST_ORDERED 1 +#define MKD_LI_BLOCK 2 /*
  • containing block data */ + +/********************** + * EXPORTED FUNCTIONS * + **********************/ + +extern __declspec(dllexport) struct sd_markdown * +sd_markdown_new( + unsigned int extensions, + size_t max_nesting, + const struct sd_callbacks *callbacks, + void *opaque); + +extern __declspec(dllexport) void +sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md); + +extern __declspec(dllexport) void +sd_markdown_free(struct sd_markdown *md); + +extern __declspec(dllexport) void +sd_version(int *major, int *minor, int *revision); + +#ifdef __cplusplus +} +#endif + +#endif + +/* vim: set filetype=c: */ diff --git a/Sundownlib/stack.c b/Sundownlib/stack.c new file mode 100644 index 0000000..ce069ff --- /dev/null +++ b/Sundownlib/stack.c @@ -0,0 +1,81 @@ +#include "stack.h" +#include + +int +stack_grow(struct stack *st, size_t new_size) +{ + void **new_st; + + if (st->asize >= new_size) + return 0; + + new_st = realloc(st->item, new_size * sizeof(void *)); + if (new_st == NULL) + return -1; + + memset(new_st + st->asize, 0x0, + (new_size - st->asize) * sizeof(void *)); + + st->item = new_st; + st->asize = new_size; + + if (st->size > new_size) + st->size = new_size; + + return 0; +} + +void +stack_free(struct stack *st) +{ + if (!st) + return; + + free(st->item); + + st->item = NULL; + st->size = 0; + st->asize = 0; +} + +int +stack_init(struct stack *st, size_t initial_size) +{ + st->item = NULL; + st->size = 0; + st->asize = 0; + + if (!initial_size) + initial_size = 8; + + return stack_grow(st, initial_size); +} + +void * +stack_pop(struct stack *st) +{ + if (!st->size) + return NULL; + + return st->item[--st->size]; +} + +int +stack_push(struct stack *st, void *item) +{ + if (stack_grow(st, st->size * 2) < 0) + return -1; + + st->item[st->size++] = item; + return 0; +} + +void * +stack_top(struct stack *st) +{ + if (!st->size) + return NULL; + + return st->item[st->size - 1]; +} + diff --git a/Sundownlib/stack.h b/Sundownlib/stack.h new file mode 100644 index 0000000..08ff030 --- /dev/null +++ b/Sundownlib/stack.h @@ -0,0 +1,29 @@ +#ifndef STACK_H__ +#define STACK_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct stack { + void **item; + size_t size; + size_t asize; +}; + +void stack_free(struct stack *); +int stack_grow(struct stack *, size_t); +int stack_init(struct stack *, size_t); + +int stack_push(struct stack *, void *); + +void *stack_pop(struct stack *); +void *stack_top(struct stack *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/TabSelectRec.cs b/TabSelectRec.cs index 3a7cf93..e285a33 100644 --- a/TabSelectRec.cs +++ b/TabSelectRec.cs @@ -1,31 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace MEditor -{ - public class TabSelectRec - { - /// - /// 浏览文档的顺序记录队列,用于关闭tab时激活页面的顺序 - /// - static Stack _selectSeque = new Stack(); - - public static void Rec(int ind) - { - _selectSeque.Push(ind); - } - - /// - /// 返回-1 说明没有记录 - /// - /// - public static int GetLast() - { - if(_selectSeque.Count>0) - return _selectSeque.Pop(); - - return -1; - } - } -} +using System.Collections.Generic; + +namespace MEditor +{ + public class TabSelectRec + { + /// + /// 浏览文档的顺序记录队列,用于关闭tab时激活页面的顺序 + /// + private static readonly Stack _selectSeque = new Stack(); + + public static void Rec(int ind) + { + _selectSeque.Push(ind); + } + + /// + /// 返回-1 说明没有记录 + /// + /// + public static int GetLast() + { + if (_selectSeque.Count > 0) + return _selectSeque.Pop(); + + return -1; + } + } +} \ No newline at end of file diff --git a/TestForm/TestSundown.Designer.cs b/TestForm/TestSundown.Designer.cs new file mode 100644 index 0000000..9e4282b --- /dev/null +++ b/TestForm/TestSundown.Designer.cs @@ -0,0 +1,70 @@ +namespace MEditor.TestForm +{ + partial class TestSundown + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.button1 = new System.Windows.Forms.Button(); + this.webControl1 = new Awesomium.Windows.Forms.WebControl(this.components); + this.SuspendLayout(); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(305, 384); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 0; + this.button1.Text = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // webControl1 + // + this.webControl1.Location = new System.Drawing.Point(12, 12); + this.webControl1.Size = new System.Drawing.Size(696, 353); + this.webControl1.TabIndex = 1; + // + // TestSundown + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(724, 419); + this.Controls.Add(this.webControl1); + this.Controls.Add(this.button1); + this.Name = "TestSundown"; + this.Text = "TestSundown"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private Awesomium.Windows.Forms.WebControl webControl1; + } +} \ No newline at end of file diff --git a/TestForm/TestSundown.cs b/TestForm/TestSundown.cs new file mode 100644 index 0000000..6a78e09 --- /dev/null +++ b/TestForm/TestSundown.cs @@ -0,0 +1,22 @@ +using System; +using System.Windows.Forms; +using MEditor.Sundownlib; + +namespace MEditor.TestForm +{ + public partial class TestSundown : Form + { + private readonly Sundown sundown; + + public TestSundown() + { + InitializeComponent(); + sundown = new Sundown(); + } + + private void button1_Click(object sender, EventArgs e) + { + this.webControl1.LoadHTML(sundown.Render("**llkllll**")); + } + } +} \ No newline at end of file diff --git a/TestForm/TestSundown.resx b/TestForm/TestSundown.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/TestForm/TestSundown.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Utils.cs b/Utils.cs index 8de30a7..c21a24a 100644 --- a/Utils.cs +++ b/Utils.cs @@ -6,179 +6,171 @@ * * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件 */ + using System; using System.Collections; using System.IO; -using System.Security; +using System.Linq; using System.Text; -using System.Windows; - -using MarkdownSharp; using MEditor.Properties; +using MEditor.Sundownlib; namespace MEditor { - /// - /// Description of Utils. - /// - internal static class Utils - { - // Fields - private static Settings _settings = Settings.Default; + /// + /// Description of Utils. + /// + internal static class Utils + { + // Fields + private static readonly Settings _settings = Settings.Default; + private static readonly Sundownlib.Sundown _sundown = new Sundown(); + + // Methods + public static string AppendValidHTMLTags(string input, string fileName = null, bool isLivePreview = true) + { + var builder = new StringBuilder(); + if (!isLivePreview) + { + builder.AppendLine( + ""); + } + builder.AppendLine(""); + builder.AppendLine(""); + if (string.IsNullOrEmpty(fileName)) + { + fileName = "Markdown"; + } + builder.AppendLine("" + Path.GetFileName(fileName) + ""); + builder.AppendLine(""); + builder.AppendLine(" "); + builder.AppendLine( + " "); + builder.AppendLine(" "); + builder.AppendLine(" "); + + builder.AppendLine(""); + if (isLivePreview) + { + //if (_settings.HTML_EnableRelativeImagePaths && (fileName != "Markdown")) + //{ + // builder.AppendLine(@""); + //} + builder.AppendLine( + ""); + builder.AppendLine( + ""); + builder.AppendLine(""); + } + builder.AppendLine(""); + builder.AppendLine(""); + // builder.AppendLine(@"
    
    +            //func main() {
    +            //    ch := make(chan int)
    +            //    ch <- 1
    +            //    x, ok := <- ch
    +            //    ok = true
    +            //    x = nil
    +            //    float_var := 1.0e10
    +            //    defer fmt.Println(')
    +            //    defer fmt.Println(`exitting now\`)
    +            //    var fv1 float64 = 0.75
    +            //    go println(len(""hello world!""))
    +            //
    + //"); + builder.AppendLine(""); + builder.AppendLine(""); + return builder.ToString(); + } - // Methods - public static string AppendValidHTMLTags(string input, string fileName, bool isLivePreview) - { - StringBuilder builder = new StringBuilder(); - if (!isLivePreview) - { - builder.AppendLine(""); - } - builder.AppendLine(""); - builder.AppendLine(""); - if (string.IsNullOrEmpty(fileName)) - { - fileName = "Markdown"; - } - builder.AppendLine("" + Path.GetFileName(fileName) + ""); - builder.AppendLine(""); - builder.AppendLine(""); - if (isLivePreview) - { - if (_settings.HTML_EnableRelativeImagePaths && (fileName != "Markdown")) - { - builder.AppendLine(@""); - } - builder.AppendLine(""); - builder.AppendLine(""); - } - builder.AppendLine(""); - builder.AppendLine(""); - builder.AppendLine(input); - builder.AppendLine(""); - builder.AppendLine(""); - builder.Append(""); - return builder.ToString(); - } + public static bool Contains(this ArrayList input, string stringToCheck, StringComparison comparison) + { + return input.Cast().Any(str => str.IndexOf(stringToCheck, comparison) >= 0); + } - public static bool Contains(this ArrayList input, string stringToCheck, StringComparison comparison) - { - foreach (string str in input) - { - if (str.IndexOf(stringToCheck, comparison) >= 0) - { - return true; - } - } - return false; - } + public static bool Contains(this string input, string stringToCheck, StringComparison comparison) + { + if (string.IsNullOrEmpty(input)) + { + return false; + } + return (input.IndexOf(stringToCheck, comparison) >= 0); + } - public static bool Contains(this string input, string stringToCheck, StringComparison comparison) - { - if (string.IsNullOrEmpty(input)) - { - return false; - } - return (input.IndexOf(stringToCheck, comparison) >= 0); - } + public static string ConvertTextToHTML(string plainText) + { - public static string ConvertTextToHTML(string plainText) - { - MarkdownOptions options = new MarkdownOptions { - AutoHyperlink = _settings.Markdown_AutoHyperlink, -// AutoNewLines = _settings.Markdown_AutoNewLines, - LinkEmails = _settings.Markdown_LinkEmails, - EncodeProblemUrlCharacters = _settings.Markdown_EncodeProblemUrlCharacters - }; - Markdown markdown = new Markdown(options); - markdown.AutoNewLines=_settings.Markdown_AutoNewLines; - string str = string.Empty; - try - { - str = markdown.Transform(plainText); - } - catch (OutOfMemoryException) - { - throw; - } - catch (Exception) - { - throw; - } - return str; - } + return _sundown.Render(plainText); + } - -// public static string GenerateBugReportURL(string formUrl) -// { -// string version = Version; -// string versionString = Environment.OSVersion.VersionString; -// if (Environment.Is64BitOperatingSystem) -// { -// versionString = versionString + " x64"; -// } -// else -// { -// versionString = versionString + " x86"; -// } -// return (formUrl + "&entry_0=" + SecurityElement.Escape(version) + "&entry_4=" + SecurityElement.Escape(versionString)); -// } + // public static string GenerateBugReportURL(string formUrl) + // { + // string version = Version; + // string versionString = Environment.OSVersion.VersionString; + // if (Environment.Is64BitOperatingSystem) + // { + // versionString = versionString + " x64"; + // } + // else + // { + // versionString = versionString + " x86"; + // } + // return (formUrl + "&entry_0=" + SecurityElement.Escape(version) + "&entry_4=" + SecurityElement.Escape(versionString)); + // } - -// public static void RenderHTMLinBrowser(string markdown, string fileName) -// { -// string path = string.Empty; -// if (string.IsNullOrEmpty(fileName)) -// { -// path = Path.GetTempPath() + "MarkdownPadPreview.html"; -// } -// else -// { -// string directoryName = Path.GetDirectoryName(fileName); -// string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); -// path = directoryName + @"\" + fileNameWithoutExtension + "-MarkdownPadPreview.html"; -// } -// try -// { -// File.WriteAllText(path, AppendValidHTMLTags(markdown, fileName, false)); -// } -// catch (Exception exception) -// { -// MessageBox.Show("An error occurred while trying to save the preview document:\n\n" + exception.Message + "\n\nPlease try again. If the problem persists, please report it under Help --> Report a Bug.", "Error Saving Preview Document", MessageBoxButton.OK, MessageBoxImage.Exclamation); -// } -// path.StartProcess(); -// } + // public static void RenderHTMLinBrowser(string markdown, string fileName) + // { + // string path = string.Empty; + // if (string.IsNullOrEmpty(fileName)) + // { + // path = Path.GetTempPath() + "MarkdownPadPreview.html"; + // } + // else + // { + // string directoryName = Path.GetDirectoryName(fileName); + // string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); + // path = directoryName + @"\" + fileNameWithoutExtension + "-MarkdownPadPreview.html"; + // } + // try + // { + // File.WriteAllText(path, AppendValidHTMLTags(markdown, fileName, false)); + // } + // catch (Exception exception) + // { + // MessageBox.Show("An error occurred while trying to save the preview document:\n\n" + exception.Message + "\n\nPlease try again. If the problem persists, please report it under Help --> Report a Bug.", "Error Saving Preview Document", MessageBoxButton.OK, MessageBoxImage.Exclamation); + // } + // path.StartProcess(); + // } - - public static string WriteDocumentToLocalFile(string fileName, string document, string path) - { - string str = DateTime.Now.ToString("yyyyMMddHmmss"); - if (string.IsNullOrEmpty(fileName)) - { - fileName = "MarkdownPad.txt"; - } - string str2 = path; - path = str2 + @"\" + Path.GetFileNameWithoutExtension(fileName) + "_backup_" + str + Path.GetExtension(fileName); - StreamWriter writer = new StreamWriter(path, true); - writer.WriteLine(string.Concat(new object[] { "MarkdownPad Document Backup: ", fileName, " at ", DateTime.Now })); - writer.WriteLine("-------------------------------" + Environment.NewLine); - writer.Write(document); - writer.Close(); - return path; - } - - - } -} + public static string WriteDocumentToLocalFile(string fileName, string document, string path) + { + string str = DateTime.Now.ToString("yyyyMMddHmmss"); + if (string.IsNullOrEmpty(fileName)) + { + fileName = "MarkdownPad.txt"; + } + string str2 = path; + path = str2 + @"\" + Path.GetFileNameWithoutExtension(fileName) + "_backup_" + str + + Path.GetExtension(fileName); + var writer = new StreamWriter(path, true); + writer.WriteLine( + string.Concat(new object[] { "MarkdownPad Document Backup: ", fileName, " at ", DateTime.Now })); + writer.WriteLine("-------------------------------" + Environment.NewLine); + writer.Write(document); + writer.Close(); + return path; + } + } +} \ No newline at end of file diff --git a/_ReSharper.MEditor/ProjectFileDataCache/ShouldUseHostCompilerProvider.cache.dat b/_ReSharper.MEditor/ProjectFileDataCache/ShouldUseHostCompilerProvider.cache.dat index b8501b7..e04ef75 100644 Binary files a/_ReSharper.MEditor/ProjectFileDataCache/ShouldUseHostCompilerProvider.cache.dat and b/_ReSharper.MEditor/ProjectFileDataCache/ShouldUseHostCompilerProvider.cache.dat differ diff --git a/_ReSharper.MEditor/RecentItems/RecentFiles.dat b/_ReSharper.MEditor/RecentItems/RecentFiles.dat index 5364430..5492f94 100644 --- a/_ReSharper.MEditor/RecentItems/RecentFiles.dat +++ b/_ReSharper.MEditor/RecentItems/RecentFiles.dat @@ -1,12 +1,12 @@  - - + + - + \ No newline at end of file diff --git a/app.config b/app.config index 03e012a..6169eb6 100644 --- a/app.config +++ b/app.config @@ -516,263 +516,285 @@ blockquote{border-left:#555 3px solid; padding-left:10px;margin-left:20px;} - body{ - margin: 0 auto; - font-family: Georgia, Palatino, serif; - color: #444444; - line-height: 1; - max-width: 960px; - padding: 5px; - } - h1, h2, h3, h4 { - color: #111111; - font-weight: 400; - } - h1, h2, h3, h4, h5, p { - margin-bottom: 16px; - padding: 0; - } - h1 { - font-size: 28px; - } - h2 { - font-size: 22px; - margin: 20px 0 6px; - } - h3 { - font-size: 21px; - } - h4 { - font-size: 18px; - } - h5 { - font-size: 16px; - } - a { - color: #0099ff; - margin: 0; - padding: 0; - vertical-align: baseline; - } - a:hover { - text-decoration: none; - color: #ff6600; - } - a:visited { - color: purple; - } - ul, ol { - padding: 0; - margin: 0; - } - li { - line-height: 24px; - margin-left: 44px; - } - li ul, li ul { - margin-left: 24px; - } - p, ul, ol { - font-size: 14px; - line-height: 20px; - max-width: 540px; - } - pre { - padding: 0px 24px; - max-width: 800px; - white-space: pre-wrap; - } - code { - font-family: Consolas, Monaco, Andale Mono, monospace; - line-height: 1.5; - font-size: 13px; - } - aside { - display: block; - float: right; - width: 390px; - } - blockquote { - border-left:.5em solid #eee; - padding: 0 2em; - margin-left:0; - max-width: 476px; - } - blockquote cite { - font-size:14px; - line-height:20px; - color:#bfbfbf; - } - blockquote cite:before { - content: '\2014 \00A0'; - } - - blockquote p { - color: #666; - max-width: 460px; - } - hr { - width: 540px; - text-align: left; - margin: 0 auto 0 0; - color: #999; - } - - button, - input, - select, - textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; - } - button, input { - line-height: normal; - *overflow: visible; - } - button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; - } - button, - input[type="button"], - input[type="reset"], - input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; - } - input[type=checkbox], input[type=radio] { - cursor: pointer; - } - /* override default chrome & firefox settings */ - input:not([type="image"]), textarea { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - } - - input[type="search"] { - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - } - input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; - } - label, - input, - select, - textarea { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - font-weight: normal; - line-height: normal; - margin-bottom: 18px; - } - input[type=checkbox], input[type=radio] { - cursor: pointer; - margin-bottom: 0; - } - input[type=text], - input[type=password], - textarea, - select { - display: inline-block; - width: 210px; - padding: 4px; - font-size: 13px; - font-weight: normal; - line-height: 18px; - height: 18px; - color: #808080; - border: 1px solid #ccc; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - } - select, input[type=file] { - height: 27px; - line-height: 27px; - } - textarea { - height: auto; - } - - /* grey out placeholders */ - :-moz-placeholder { - color: #bfbfbf; - } - ::-webkit-input-placeholder { - color: #bfbfbf; - } - - input[type=text], - input[type=password], - select, - textarea { - -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; - -moz-transition: border linear 0.2s, box-shadow linear 0.2s; - transition: border linear 0.2s, box-shadow linear 0.2s; - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - } - input[type=text]:focus, input[type=password]:focus, textarea:focus { - outline: none; - border-color: rgba(82, 168, 236, 0.8); - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - } - - /* buttons */ - button { - display: inline-block; - padding: 4px 14px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - line-height: 18px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - background-color: #0064cd; - background-repeat: repeat-x; - background-image: -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd)); - background-image: -moz-linear-gradient(top, #049cdb, #0064cd); - background-image: -ms-linear-gradient(top, #049cdb, #0064cd); - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd)); - background-image: -webkit-linear-gradient(top, #049cdb, #0064cd); - background-image: -o-linear-gradient(top, #049cdb, #0064cd); - background-image: linear-gradient(top, #049cdb, #0064cd); - color: #fff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - border: 1px solid #004b9a; - border-bottom-color: #003f81; - -webkit-transition: 0.1s linear all; - -moz-transition: 0.1s linear all; - transition: 0.1s linear all; - border-color: #0064cd #0064cd #003f81; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - } - button:hover { - color: #fff; - background-position: 0 -15px; - text-decoration: none; - } - button:active { - -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - } - button::-moz-focus-inner { - padding: 0; - border: 0; - } + + body { + font-family: Helvetica, arial, sans-serif; + font-size: 14px; + line-height: 1.6; + padding-top: 10px; + padding-bottom: 10px; + background-color: white; + } + + body > *:first-child { + margin-top: 0 !important; } + body > *:last-child { + margin-bottom: 0 !important; } + + a { + color: #4183C4; } + a.absent { + color: #cc0000; } + a.anchor { + display: block; + padding-left: 30px; + margin-left: -30px; + cursor: pointer; + position: absolute; + top: 0; + left: 0; + bottom: 0; } + + h1, h2, h3, h4, h5, h6 { + margin: 20px 0 10px; + padding: 0; + font-weight: bold; + -webkit-font-smoothing: antialiased; + cursor: text; + position: relative; } + + h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { + background: url("para.png") no-repeat 10px center; + text-decoration: none; } + + h1 tt, h1 code { + font-size: inherit; } + + h2 tt, h2 code { + font-size: inherit; } + + h3 tt, h3 code { + font-size: inherit; } + + h4 tt, h4 code { + font-size: inherit; } + + h5 tt, h5 code { + font-size: inherit; } + + h6 tt, h6 code { + font-size: inherit; } + + h1 { + font-size: 28px; + color: black; } + + h2 { + font-size: 24px; + border-bottom: 1px solid #cccccc; + color: black; } + + h3 { + font-size: 18px; } + + h4 { + font-size: 16px; } + + h5 { + font-size: 14px; } + + h6 { + color: #777777; + font-size: 14px; } + + p, blockquote, ul, ol, dl, li, table, pre { + margin: 15px 0; } + + hr { + background: transparent url("dirty-shade.png") repeat-x 0 0; + border: 0 none; + color: #cccccc; + height: 4px; + padding: 0; } + + body > h2:first-child { + margin-top: 0; + padding-top: 0; } + body > h1:first-child { + margin-top: 0; + padding-top: 0; } + body > h1:first-child + h2 { + margin-top: 0; + padding-top: 0; } + body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { + margin-top: 0; + padding-top: 0; } + + a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { + margin-top: 0; + padding-top: 0; } + + h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { + margin-top: 0; } + + li p.first { + display: inline-block; } + + ul, ol { + padding-left: 30px; } + + ul :first-child, ol :first-child { + margin-top: 0; } + + ul :last-child, ol :last-child { + margin-bottom: 0; } + + dl { + padding: 0; } + dl dt { + font-size: 14px; + font-weight: bold; + font-style: italic; + padding: 0; + margin: 15px 0 5px; } + dl dt:first-child { + padding: 0; } + dl dt > :first-child { + margin-top: 0; } + dl dt > :last-child { + margin-bottom: 0; } + dl dd { + margin: 0 0 15px; + padding: 0 15px; } + dl dd > :first-child { + margin-top: 0; } + dl dd > :last-child { + margin-bottom: 0; } + + blockquote { + border-left: 4px solid #dddddd; + padding: 0 15px; + color: #777777; } + blockquote > :first-child { + margin-top: 0; } + blockquote > :last-child { + margin-bottom: 0; } + + table { + padding: 0; } + table tr { + border-top: 1px solid #cccccc; + background-color: white; + margin: 0; + padding: 0; } + table tr:nth-child(2n) { + background-color: #f8f8f8; } + table tr th { + font-weight: bold; + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr td { + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr th :first-child, table tr td :first-child { + margin-top: 0; } + table tr th :last-child, table tr td :last-child { + margin-bottom: 0; } + + img { + max-width: 100%; } + + span.frame { + display: block; + overflow: hidden; } + span.frame > span { + border: 1px solid #dddddd; + display: block; + float: left; + overflow: hidden; + margin: 13px 0 0; + padding: 7px; + width: auto; } + span.frame span img { + display: block; + float: left; } + span.frame span span { + clear: both; + color: #333333; + display: block; + padding: 5px 0 0; } + span.align-center { + display: block; + overflow: hidden; + clear: both; } + span.align-center > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: center; } + span.align-center span img { + margin: 0 auto; + text-align: center; } + span.align-right { + display: block; + overflow: hidden; + clear: both; } + span.align-right > span { + display: block; + overflow: hidden; + margin: 13px 0 0; + text-align: right; } + span.align-right span img { + margin: 0; + text-align: right; } + span.float-left { + display: block; + margin-right: 13px; + overflow: hidden; + float: left; } + span.float-left span { + margin: 13px 0 0; } + span.float-right { + display: block; + margin-left: 13px; + overflow: hidden; + float: right; } + span.float-right > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: right; } + + code, tt { + margin: 0 2px; + padding: 0 5px; + white-space: nowrap; + border: 1px solid #eaeaea; + background-color: #f8f8f8; + border-radius: 3px; } + + pre code { + margin: 0; + padding: 0; + white-space: pre; + border: none; + background: transparent; } + + .highlight pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; } + + pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; } + pre code, pre tt { + background-color: transparent; + border: none; } + diff --git a/exeoutput/Cache/Cache/data_0 b/exeoutput/Cache/Cache/data_0 new file mode 100644 index 0000000..6fcf11b Binary files /dev/null and b/exeoutput/Cache/Cache/data_0 differ diff --git a/exeoutput/Cache/Cache/data_1 b/exeoutput/Cache/Cache/data_1 new file mode 100644 index 0000000..367d97e Binary files /dev/null and b/exeoutput/Cache/Cache/data_1 differ diff --git a/exeoutput/Cache/Cache/data_2 b/exeoutput/Cache/Cache/data_2 new file mode 100644 index 0000000..9306e6e Binary files /dev/null and b/exeoutput/Cache/Cache/data_2 differ diff --git a/exeoutput/Cache/Cache/data_3 b/exeoutput/Cache/Cache/data_3 new file mode 100644 index 0000000..c1a4df6 Binary files /dev/null and b/exeoutput/Cache/Cache/data_3 differ diff --git a/exeoutput/Cache/Cache/index b/exeoutput/Cache/Cache/index new file mode 100644 index 0000000..4a26bd0 Binary files /dev/null and b/exeoutput/Cache/Cache/index differ diff --git a/exeoutput/Cache/Cookies b/exeoutput/Cache/Cookies new file mode 100644 index 0000000..2161d8f Binary files /dev/null and b/exeoutput/Cache/Cookies differ diff --git a/exeoutput/MDEditor.exe b/exeoutput/MDEditor.exe index 64fe337..052ebd4 100644 Binary files a/exeoutput/MDEditor.exe and b/exeoutput/MDEditor.exe differ diff --git a/exeoutput/MDEditor.exe.config b/exeoutput/MDEditor.exe.config index 03e012a..6169eb6 100644 --- a/exeoutput/MDEditor.exe.config +++ b/exeoutput/MDEditor.exe.config @@ -516,263 +516,285 @@ blockquote{border-left:#555 3px solid; padding-left:10px;margin-left:20px;} - body{ - margin: 0 auto; - font-family: Georgia, Palatino, serif; - color: #444444; - line-height: 1; - max-width: 960px; - padding: 5px; - } - h1, h2, h3, h4 { - color: #111111; - font-weight: 400; - } - h1, h2, h3, h4, h5, p { - margin-bottom: 16px; - padding: 0; - } - h1 { - font-size: 28px; - } - h2 { - font-size: 22px; - margin: 20px 0 6px; - } - h3 { - font-size: 21px; - } - h4 { - font-size: 18px; - } - h5 { - font-size: 16px; - } - a { - color: #0099ff; - margin: 0; - padding: 0; - vertical-align: baseline; - } - a:hover { - text-decoration: none; - color: #ff6600; - } - a:visited { - color: purple; - } - ul, ol { - padding: 0; - margin: 0; - } - li { - line-height: 24px; - margin-left: 44px; - } - li ul, li ul { - margin-left: 24px; - } - p, ul, ol { - font-size: 14px; - line-height: 20px; - max-width: 540px; - } - pre { - padding: 0px 24px; - max-width: 800px; - white-space: pre-wrap; - } - code { - font-family: Consolas, Monaco, Andale Mono, monospace; - line-height: 1.5; - font-size: 13px; - } - aside { - display: block; - float: right; - width: 390px; - } - blockquote { - border-left:.5em solid #eee; - padding: 0 2em; - margin-left:0; - max-width: 476px; - } - blockquote cite { - font-size:14px; - line-height:20px; - color:#bfbfbf; - } - blockquote cite:before { - content: '\2014 \00A0'; - } - - blockquote p { - color: #666; - max-width: 460px; - } - hr { - width: 540px; - text-align: left; - margin: 0 auto 0 0; - color: #999; - } - - button, - input, - select, - textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; - } - button, input { - line-height: normal; - *overflow: visible; - } - button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; - } - button, - input[type="button"], - input[type="reset"], - input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; - } - input[type=checkbox], input[type=radio] { - cursor: pointer; - } - /* override default chrome & firefox settings */ - input:not([type="image"]), textarea { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - } - - input[type="search"] { - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - } - input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; - } - label, - input, - select, - textarea { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - font-weight: normal; - line-height: normal; - margin-bottom: 18px; - } - input[type=checkbox], input[type=radio] { - cursor: pointer; - margin-bottom: 0; - } - input[type=text], - input[type=password], - textarea, - select { - display: inline-block; - width: 210px; - padding: 4px; - font-size: 13px; - font-weight: normal; - line-height: 18px; - height: 18px; - color: #808080; - border: 1px solid #ccc; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - } - select, input[type=file] { - height: 27px; - line-height: 27px; - } - textarea { - height: auto; - } - - /* grey out placeholders */ - :-moz-placeholder { - color: #bfbfbf; - } - ::-webkit-input-placeholder { - color: #bfbfbf; - } - - input[type=text], - input[type=password], - select, - textarea { - -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; - -moz-transition: border linear 0.2s, box-shadow linear 0.2s; - transition: border linear 0.2s, box-shadow linear 0.2s; - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - } - input[type=text]:focus, input[type=password]:focus, textarea:focus { - outline: none; - border-color: rgba(82, 168, 236, 0.8); - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - } - - /* buttons */ - button { - display: inline-block; - padding: 4px 14px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - line-height: 18px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - background-color: #0064cd; - background-repeat: repeat-x; - background-image: -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd)); - background-image: -moz-linear-gradient(top, #049cdb, #0064cd); - background-image: -ms-linear-gradient(top, #049cdb, #0064cd); - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd)); - background-image: -webkit-linear-gradient(top, #049cdb, #0064cd); - background-image: -o-linear-gradient(top, #049cdb, #0064cd); - background-image: linear-gradient(top, #049cdb, #0064cd); - color: #fff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - border: 1px solid #004b9a; - border-bottom-color: #003f81; - -webkit-transition: 0.1s linear all; - -moz-transition: 0.1s linear all; - transition: 0.1s linear all; - border-color: #0064cd #0064cd #003f81; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - } - button:hover { - color: #fff; - background-position: 0 -15px; - text-decoration: none; - } - button:active { - -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - } - button::-moz-focus-inner { - padding: 0; - border: 0; - } + + body { + font-family: Helvetica, arial, sans-serif; + font-size: 14px; + line-height: 1.6; + padding-top: 10px; + padding-bottom: 10px; + background-color: white; + } + + body > *:first-child { + margin-top: 0 !important; } + body > *:last-child { + margin-bottom: 0 !important; } + + a { + color: #4183C4; } + a.absent { + color: #cc0000; } + a.anchor { + display: block; + padding-left: 30px; + margin-left: -30px; + cursor: pointer; + position: absolute; + top: 0; + left: 0; + bottom: 0; } + + h1, h2, h3, h4, h5, h6 { + margin: 20px 0 10px; + padding: 0; + font-weight: bold; + -webkit-font-smoothing: antialiased; + cursor: text; + position: relative; } + + h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { + background: url("para.png") no-repeat 10px center; + text-decoration: none; } + + h1 tt, h1 code { + font-size: inherit; } + + h2 tt, h2 code { + font-size: inherit; } + + h3 tt, h3 code { + font-size: inherit; } + + h4 tt, h4 code { + font-size: inherit; } + + h5 tt, h5 code { + font-size: inherit; } + + h6 tt, h6 code { + font-size: inherit; } + + h1 { + font-size: 28px; + color: black; } + + h2 { + font-size: 24px; + border-bottom: 1px solid #cccccc; + color: black; } + + h3 { + font-size: 18px; } + + h4 { + font-size: 16px; } + + h5 { + font-size: 14px; } + + h6 { + color: #777777; + font-size: 14px; } + + p, blockquote, ul, ol, dl, li, table, pre { + margin: 15px 0; } + + hr { + background: transparent url("dirty-shade.png") repeat-x 0 0; + border: 0 none; + color: #cccccc; + height: 4px; + padding: 0; } + + body > h2:first-child { + margin-top: 0; + padding-top: 0; } + body > h1:first-child { + margin-top: 0; + padding-top: 0; } + body > h1:first-child + h2 { + margin-top: 0; + padding-top: 0; } + body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { + margin-top: 0; + padding-top: 0; } + + a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { + margin-top: 0; + padding-top: 0; } + + h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { + margin-top: 0; } + + li p.first { + display: inline-block; } + + ul, ol { + padding-left: 30px; } + + ul :first-child, ol :first-child { + margin-top: 0; } + + ul :last-child, ol :last-child { + margin-bottom: 0; } + + dl { + padding: 0; } + dl dt { + font-size: 14px; + font-weight: bold; + font-style: italic; + padding: 0; + margin: 15px 0 5px; } + dl dt:first-child { + padding: 0; } + dl dt > :first-child { + margin-top: 0; } + dl dt > :last-child { + margin-bottom: 0; } + dl dd { + margin: 0 0 15px; + padding: 0 15px; } + dl dd > :first-child { + margin-top: 0; } + dl dd > :last-child { + margin-bottom: 0; } + + blockquote { + border-left: 4px solid #dddddd; + padding: 0 15px; + color: #777777; } + blockquote > :first-child { + margin-top: 0; } + blockquote > :last-child { + margin-bottom: 0; } + + table { + padding: 0; } + table tr { + border-top: 1px solid #cccccc; + background-color: white; + margin: 0; + padding: 0; } + table tr:nth-child(2n) { + background-color: #f8f8f8; } + table tr th { + font-weight: bold; + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr td { + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr th :first-child, table tr td :first-child { + margin-top: 0; } + table tr th :last-child, table tr td :last-child { + margin-bottom: 0; } + + img { + max-width: 100%; } + + span.frame { + display: block; + overflow: hidden; } + span.frame > span { + border: 1px solid #dddddd; + display: block; + float: left; + overflow: hidden; + margin: 13px 0 0; + padding: 7px; + width: auto; } + span.frame span img { + display: block; + float: left; } + span.frame span span { + clear: both; + color: #333333; + display: block; + padding: 5px 0 0; } + span.align-center { + display: block; + overflow: hidden; + clear: both; } + span.align-center > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: center; } + span.align-center span img { + margin: 0 auto; + text-align: center; } + span.align-right { + display: block; + overflow: hidden; + clear: both; } + span.align-right > span { + display: block; + overflow: hidden; + margin: 13px 0 0; + text-align: right; } + span.align-right span img { + margin: 0; + text-align: right; } + span.float-left { + display: block; + margin-right: 13px; + overflow: hidden; + float: left; } + span.float-left span { + margin: 13px 0 0; } + span.float-right { + display: block; + margin-left: 13px; + overflow: hidden; + float: right; } + span.float-right > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: right; } + + code, tt { + margin: 0 2px; + padding: 0 5px; + white-space: nowrap; + border: 1px solid #eaeaea; + background-color: #f8f8f8; + border-radius: 3px; } + + pre code { + margin: 0; + padding: 0; + white-space: pre; + border: none; + background: transparent; } + + .highlight pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; } + + pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; } + pre code, pre tt { + background-color: transparent; + border: none; } + diff --git a/exeoutput/MDEditor.pdb b/exeoutput/MDEditor.pdb index c50eedc..7315596 100644 Binary files a/exeoutput/MDEditor.pdb and b/exeoutput/MDEditor.pdb differ diff --git a/exeoutput/MDEditor.vshost.exe b/exeoutput/MDEditor.vshost.exe index 6b241bc..8c84517 100644 Binary files a/exeoutput/MDEditor.vshost.exe and b/exeoutput/MDEditor.vshost.exe differ diff --git a/exeoutput/MDEditor.vshost.exe.config b/exeoutput/MDEditor.vshost.exe.config index 03e012a..6169eb6 100644 --- a/exeoutput/MDEditor.vshost.exe.config +++ b/exeoutput/MDEditor.vshost.exe.config @@ -516,263 +516,285 @@ blockquote{border-left:#555 3px solid; padding-left:10px;margin-left:20px;} - body{ - margin: 0 auto; - font-family: Georgia, Palatino, serif; - color: #444444; - line-height: 1; - max-width: 960px; - padding: 5px; - } - h1, h2, h3, h4 { - color: #111111; - font-weight: 400; - } - h1, h2, h3, h4, h5, p { - margin-bottom: 16px; - padding: 0; - } - h1 { - font-size: 28px; - } - h2 { - font-size: 22px; - margin: 20px 0 6px; - } - h3 { - font-size: 21px; - } - h4 { - font-size: 18px; - } - h5 { - font-size: 16px; - } - a { - color: #0099ff; - margin: 0; - padding: 0; - vertical-align: baseline; - } - a:hover { - text-decoration: none; - color: #ff6600; - } - a:visited { - color: purple; - } - ul, ol { - padding: 0; - margin: 0; - } - li { - line-height: 24px; - margin-left: 44px; - } - li ul, li ul { - margin-left: 24px; - } - p, ul, ol { - font-size: 14px; - line-height: 20px; - max-width: 540px; - } - pre { - padding: 0px 24px; - max-width: 800px; - white-space: pre-wrap; - } - code { - font-family: Consolas, Monaco, Andale Mono, monospace; - line-height: 1.5; - font-size: 13px; - } - aside { - display: block; - float: right; - width: 390px; - } - blockquote { - border-left:.5em solid #eee; - padding: 0 2em; - margin-left:0; - max-width: 476px; - } - blockquote cite { - font-size:14px; - line-height:20px; - color:#bfbfbf; - } - blockquote cite:before { - content: '\2014 \00A0'; - } - - blockquote p { - color: #666; - max-width: 460px; - } - hr { - width: 540px; - text-align: left; - margin: 0 auto 0 0; - color: #999; - } - - button, - input, - select, - textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; - } - button, input { - line-height: normal; - *overflow: visible; - } - button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; - } - button, - input[type="button"], - input[type="reset"], - input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; - } - input[type=checkbox], input[type=radio] { - cursor: pointer; - } - /* override default chrome & firefox settings */ - input:not([type="image"]), textarea { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - } - - input[type="search"] { - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - } - input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; - } - label, - input, - select, - textarea { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - font-weight: normal; - line-height: normal; - margin-bottom: 18px; - } - input[type=checkbox], input[type=radio] { - cursor: pointer; - margin-bottom: 0; - } - input[type=text], - input[type=password], - textarea, - select { - display: inline-block; - width: 210px; - padding: 4px; - font-size: 13px; - font-weight: normal; - line-height: 18px; - height: 18px; - color: #808080; - border: 1px solid #ccc; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - } - select, input[type=file] { - height: 27px; - line-height: 27px; - } - textarea { - height: auto; - } - - /* grey out placeholders */ - :-moz-placeholder { - color: #bfbfbf; - } - ::-webkit-input-placeholder { - color: #bfbfbf; - } - - input[type=text], - input[type=password], - select, - textarea { - -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; - -moz-transition: border linear 0.2s, box-shadow linear 0.2s; - transition: border linear 0.2s, box-shadow linear 0.2s; - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); - } - input[type=text]:focus, input[type=password]:focus, textarea:focus { - outline: none; - border-color: rgba(82, 168, 236, 0.8); - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); - } - - /* buttons */ - button { - display: inline-block; - padding: 4px 14px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - line-height: 18px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - background-color: #0064cd; - background-repeat: repeat-x; - background-image: -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd)); - background-image: -moz-linear-gradient(top, #049cdb, #0064cd); - background-image: -ms-linear-gradient(top, #049cdb, #0064cd); - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd)); - background-image: -webkit-linear-gradient(top, #049cdb, #0064cd); - background-image: -o-linear-gradient(top, #049cdb, #0064cd); - background-image: linear-gradient(top, #049cdb, #0064cd); - color: #fff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - border: 1px solid #004b9a; - border-bottom-color: #003f81; - -webkit-transition: 0.1s linear all; - -moz-transition: 0.1s linear all; - transition: 0.1s linear all; - border-color: #0064cd #0064cd #003f81; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - } - button:hover { - color: #fff; - background-position: 0 -15px; - text-decoration: none; - } - button:active { - -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - } - button::-moz-focus-inner { - padding: 0; - border: 0; - } + + body { + font-family: Helvetica, arial, sans-serif; + font-size: 14px; + line-height: 1.6; + padding-top: 10px; + padding-bottom: 10px; + background-color: white; + } + + body > *:first-child { + margin-top: 0 !important; } + body > *:last-child { + margin-bottom: 0 !important; } + + a { + color: #4183C4; } + a.absent { + color: #cc0000; } + a.anchor { + display: block; + padding-left: 30px; + margin-left: -30px; + cursor: pointer; + position: absolute; + top: 0; + left: 0; + bottom: 0; } + + h1, h2, h3, h4, h5, h6 { + margin: 20px 0 10px; + padding: 0; + font-weight: bold; + -webkit-font-smoothing: antialiased; + cursor: text; + position: relative; } + + h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { + background: url("para.png") no-repeat 10px center; + text-decoration: none; } + + h1 tt, h1 code { + font-size: inherit; } + + h2 tt, h2 code { + font-size: inherit; } + + h3 tt, h3 code { + font-size: inherit; } + + h4 tt, h4 code { + font-size: inherit; } + + h5 tt, h5 code { + font-size: inherit; } + + h6 tt, h6 code { + font-size: inherit; } + + h1 { + font-size: 28px; + color: black; } + + h2 { + font-size: 24px; + border-bottom: 1px solid #cccccc; + color: black; } + + h3 { + font-size: 18px; } + + h4 { + font-size: 16px; } + + h5 { + font-size: 14px; } + + h6 { + color: #777777; + font-size: 14px; } + + p, blockquote, ul, ol, dl, li, table, pre { + margin: 15px 0; } + + hr { + background: transparent url("dirty-shade.png") repeat-x 0 0; + border: 0 none; + color: #cccccc; + height: 4px; + padding: 0; } + + body > h2:first-child { + margin-top: 0; + padding-top: 0; } + body > h1:first-child { + margin-top: 0; + padding-top: 0; } + body > h1:first-child + h2 { + margin-top: 0; + padding-top: 0; } + body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { + margin-top: 0; + padding-top: 0; } + + a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { + margin-top: 0; + padding-top: 0; } + + h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { + margin-top: 0; } + + li p.first { + display: inline-block; } + + ul, ol { + padding-left: 30px; } + + ul :first-child, ol :first-child { + margin-top: 0; } + + ul :last-child, ol :last-child { + margin-bottom: 0; } + + dl { + padding: 0; } + dl dt { + font-size: 14px; + font-weight: bold; + font-style: italic; + padding: 0; + margin: 15px 0 5px; } + dl dt:first-child { + padding: 0; } + dl dt > :first-child { + margin-top: 0; } + dl dt > :last-child { + margin-bottom: 0; } + dl dd { + margin: 0 0 15px; + padding: 0 15px; } + dl dd > :first-child { + margin-top: 0; } + dl dd > :last-child { + margin-bottom: 0; } + + blockquote { + border-left: 4px solid #dddddd; + padding: 0 15px; + color: #777777; } + blockquote > :first-child { + margin-top: 0; } + blockquote > :last-child { + margin-bottom: 0; } + + table { + padding: 0; } + table tr { + border-top: 1px solid #cccccc; + background-color: white; + margin: 0; + padding: 0; } + table tr:nth-child(2n) { + background-color: #f8f8f8; } + table tr th { + font-weight: bold; + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr td { + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr th :first-child, table tr td :first-child { + margin-top: 0; } + table tr th :last-child, table tr td :last-child { + margin-bottom: 0; } + + img { + max-width: 100%; } + + span.frame { + display: block; + overflow: hidden; } + span.frame > span { + border: 1px solid #dddddd; + display: block; + float: left; + overflow: hidden; + margin: 13px 0 0; + padding: 7px; + width: auto; } + span.frame span img { + display: block; + float: left; } + span.frame span span { + clear: both; + color: #333333; + display: block; + padding: 5px 0 0; } + span.align-center { + display: block; + overflow: hidden; + clear: both; } + span.align-center > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: center; } + span.align-center span img { + margin: 0 auto; + text-align: center; } + span.align-right { + display: block; + overflow: hidden; + clear: both; } + span.align-right > span { + display: block; + overflow: hidden; + margin: 13px 0 0; + text-align: right; } + span.align-right span img { + margin: 0; + text-align: right; } + span.float-left { + display: block; + margin-right: 13px; + overflow: hidden; + float: left; } + span.float-left span { + margin: 13px 0 0; } + span.float-right { + display: block; + margin-left: 13px; + overflow: hidden; + float: right; } + span.float-right > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: right; } + + code, tt { + margin: 0 2px; + padding: 0 5px; + white-space: nowrap; + border: 1px solid #eaeaea; + background-color: #f8f8f8; + border-radius: 3px; } + + pre code { + margin: 0; + padding: 0; + white-space: pre; + border: none; + background: transparent; } + + .highlight pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; } + + pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; } + pre code, pre tt { + background-color: transparent; + border: none; } + diff --git a/exeoutput/SundownLib.dll b/exeoutput/SundownLib.dll new file mode 100644 index 0000000..abe2dad Binary files /dev/null and b/exeoutput/SundownLib.dll differ diff --git a/exeoutput/debug.log b/exeoutput/debug.log new file mode 100644 index 0000000..173affa --- /dev/null +++ b/exeoutput/debug.log @@ -0,0 +1,11 @@ +[0603/010224:ERROR:ipc_channel_win.cc(261)] pipe error: 109 +[0603/015846:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020010:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020030:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020057:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020116:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020202:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020334:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020630:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/020704:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput +[0603/211613:ERROR:DataPak.cc(102)] Unable to load DataPak with path: G:\GitHub\MEditor\exeoutput diff --git a/exeoutput/libs/SundownLib.dll b/exeoutput/libs/SundownLib.dll new file mode 100644 index 0000000..c038e5a Binary files /dev/null and b/exeoutput/libs/SundownLib.dll differ diff --git a/exeoutput/te.html b/exeoutput/te.html new file mode 100644 index 0000000..cceb032 --- /dev/null +++ b/exeoutput/te.html @@ -0,0 +1,20 @@ + + +fff + + + + + + + +
    +
    +import java;
    +
    +
    + + diff --git a/exeoutput/template/styles/default.css b/exeoutput/template/styles/default.css new file mode 100644 index 0000000..e417fc1 --- /dev/null +++ b/exeoutput/template/styles/default.css @@ -0,0 +1,135 @@ +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #F0F0F0; +} + +pre code, +pre .subst, +pre .tag .title, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title { + color: black; +} + +pre .string, +pre .title, +pre .constant, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .flow, +pre .stream, +pre .bash .variable, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .tex .special, +pre .erlang_repl .function_or_atom, +pre .markdown .header { + color: #800; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk, +pre .markdown .blockquote { + color: #888; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .go .constant, +pre .change, +pre .markdown .bullet, +pre .markdown .link_url { + color: #080; +} + +pre .label, +pre .javadoc, +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .important, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula, +pre .erlang_repl .reserved, +pre .prompt, +pre .markdown .link_label, +pre .vhdl .attribute, +pre .clojure .attribute, +pre .coffeescript .property { + color: #88F +} + +pre .keyword, +pre .id, +pre .phpdoc, +pre .title, +pre .built_in, +pre .aggregate, +pre .css .tag, +pre .javadoctag, +pre .phpdoc, +pre .yardoctag, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .go .typename, +pre .tex .command, +pre .markdown .strong, +pre .request, +pre .status { + font-weight: bold; +} + +pre .markdown .emphasis { + font-style: italic; +} + +pre .nginx .built_in { + font-weight: normal; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/frmCss.cs b/frmCss.cs index 752a011..065f6ef 100644 --- a/frmCss.cs +++ b/frmCss.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; using System.Windows.Forms; using MEditor.Properties; @@ -11,15 +6,10 @@ namespace MEditor { public partial class frmCss : Form { + private readonly FrmMain _fm; private string _css = ""; - private frmMain _fm = null; - public string Css - { - get { return _css; } - set { _css = value; } - } - public frmCss(string css,frmMain fm) + public frmCss(string css, FrmMain fm) { InitializeComponent(); _css = css; @@ -27,15 +17,21 @@ public frmCss(string css,frmMain fm) txtCss.AppendText(css); } + public string Css + { + get { return _css; } + set { _css = value; } + } + private void button2_Click(object sender, EventArgs e) { //_fm.SetCss(txtTabWidth.Text); _fm.SetCss(txtCss.Text); _fm.SetExt(txtExt.Text); _fm.SaveSettings(); - + Close(); - } + } private void button1_Click(object sender, EventArgs e) { @@ -61,8 +57,8 @@ private void button5_Click(object sender, EventArgs e) private void button6_Click(object sender, EventArgs e) { Settings.Default.Reset(); - _css = Settings.Default.cssWhite; - txtCss.Text = _css; + _css = Settings.Default.cssWhite; + txtCss.Text = _css; _fm.SetOldStyle(); //_fm.ReadCss(); } @@ -70,8 +66,8 @@ private void button6_Click(object sender, EventArgs e) private void button7_Click(object sender, EventArgs e) { Settings.Default.Reset(); - _css = Settings.Default.css; - txtCss.Text = _css; + _css = Settings.Default.css; + txtCss.Text = _css; _fm.SetBlackWhiteStyle(); //_fm.ReadCss(); } @@ -80,6 +76,5 @@ private void frmCss_Load(object sender, EventArgs e) { txtExt.Text = Settings.Default.extfile; } - } -} +} \ No newline at end of file diff --git a/frmMain.Designer.cs b/frmMain.Designer.cs index 862b2f4..bfdafbf 100644 --- a/frmMain.Designer.cs +++ b/frmMain.Designer.cs @@ -1,7 +1,7 @@ using System.Windows.Forms.Integration; namespace MEditor { - partial class frmMain: MRU.IMRUClient + partial class FrmMain: MRU.IMRUClient { /// /// 必需的设计器变量。 @@ -30,7 +30,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmMain)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain)); this.字体OToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.字体颜色ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.新建NToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -64,6 +64,10 @@ private void InitializeComponent() this.字体颜色toolStripButton11 = new System.Windows.Forms.ToolStripButton(); this.字体toolStripButton10 = new System.Windows.Forms.ToolStripButton(); this.加粗toolStripButton7 = new System.Windows.Forms.ToolStripButton(); + this.倾斜toolStripButton8 = new System.Windows.Forms.ToolStripButton(); + this.下划线toolStripButton9 = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripButton1 = new System.Windows.Forms.ToolStripButton(); this.markdown语法介绍精简版ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.markdown语法介绍ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.markdown语法介绍二ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -73,10 +77,6 @@ private void InitializeComponent() this.关于MEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mEditor网站ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.检查最新版ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.倾斜toolStripButton8 = new System.Windows.Forms.ToolStripButton(); - this.下划线toolStripButton9 = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripButton1 = new System.Windows.Forms.ToolStripButton(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.自动转行ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.背景颜色ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -102,7 +102,7 @@ private void InitializeComponent() this.打开所在文件夹ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.tabControl2 = new System.Windows.Forms.TabControl(); this.tabBrowser = new System.Windows.Forms.TabPage(); - this.webBrowser1 = new System.Windows.Forms.WebBrowser(); + this.webControl1 = new Awesomium.Windows.Forms.WebControl(this.components); this.tabHtml = new System.Windows.Forms.TabPage(); this.rtbHtml = new System.Windows.Forms.RichTextBox(); this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components); @@ -432,6 +432,41 @@ private void InitializeComponent() this.加粗toolStripButton7.Text = "加粗"; this.加粗toolStripButton7.Click += new System.EventHandler(this.加粗toolStripButton7_Click); // + // 倾斜toolStripButton8 + // + this.倾斜toolStripButton8.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.倾斜toolStripButton8.Image = ((System.Drawing.Image)(resources.GetObject("倾斜toolStripButton8.Image"))); + this.倾斜toolStripButton8.ImageTransparentColor = System.Drawing.Color.Magenta; + this.倾斜toolStripButton8.Name = "倾斜toolStripButton8"; + this.倾斜toolStripButton8.Size = new System.Drawing.Size(23, 22); + this.倾斜toolStripButton8.Text = "倾斜"; + this.倾斜toolStripButton8.Click += new System.EventHandler(this.倾斜toolStripButton8_Click); + // + // 下划线toolStripButton9 + // + this.下划线toolStripButton9.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.下划线toolStripButton9.Image = ((System.Drawing.Image)(resources.GetObject("下划线toolStripButton9.Image"))); + this.下划线toolStripButton9.ImageTransparentColor = System.Drawing.Color.Magenta; + this.下划线toolStripButton9.Name = "下划线toolStripButton9"; + this.下划线toolStripButton9.Size = new System.Drawing.Size(23, 22); + this.下划线toolStripButton9.Text = "下划线"; + this.下划线toolStripButton9.Click += new System.EventHandler(this.下划线toolStripButton9_Click); + // + // toolStripSeparator10 + // + this.toolStripSeparator10.Name = "toolStripSeparator10"; + this.toolStripSeparator10.Size = new System.Drawing.Size(6, 25); + // + // toolStripButton1 + // + this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image"))); + this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButton1.Name = "toolStripButton1"; + this.toolStripButton1.Size = new System.Drawing.Size(76, 22); + this.toolStripButton1.Text = "html预览"; + this.toolStripButton1.ToolTipText = "快捷键 F5"; + this.toolStripButton1.Click += new System.EventHandler(this.toolStripButton1_Click); + // // markdown语法介绍精简版ToolStripMenuItem // this.markdown语法介绍精简版ToolStripMenuItem.Name = "markdown语法介绍精简版ToolStripMenuItem"; @@ -493,41 +528,6 @@ private void InitializeComponent() this.检查最新版ToolStripMenuItem.Text = "检查最新版"; this.检查最新版ToolStripMenuItem.Click += new System.EventHandler(this.检查最新版ToolStripMenuItem_Click); // - // 倾斜toolStripButton8 - // - this.倾斜toolStripButton8.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.倾斜toolStripButton8.Image = ((System.Drawing.Image)(resources.GetObject("倾斜toolStripButton8.Image"))); - this.倾斜toolStripButton8.ImageTransparentColor = System.Drawing.Color.Magenta; - this.倾斜toolStripButton8.Name = "倾斜toolStripButton8"; - this.倾斜toolStripButton8.Size = new System.Drawing.Size(23, 22); - this.倾斜toolStripButton8.Text = "倾斜"; - this.倾斜toolStripButton8.Click += new System.EventHandler(this.倾斜toolStripButton8_Click); - // - // 下划线toolStripButton9 - // - this.下划线toolStripButton9.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.下划线toolStripButton9.Image = ((System.Drawing.Image)(resources.GetObject("下划线toolStripButton9.Image"))); - this.下划线toolStripButton9.ImageTransparentColor = System.Drawing.Color.Magenta; - this.下划线toolStripButton9.Name = "下划线toolStripButton9"; - this.下划线toolStripButton9.Size = new System.Drawing.Size(23, 22); - this.下划线toolStripButton9.Text = "下划线"; - this.下划线toolStripButton9.Click += new System.EventHandler(this.下划线toolStripButton9_Click); - // - // toolStripSeparator10 - // - this.toolStripSeparator10.Name = "toolStripSeparator10"; - this.toolStripSeparator10.Size = new System.Drawing.Size(6, 25); - // - // toolStripButton1 - // - this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image"))); - this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripButton1.Name = "toolStripButton1"; - this.toolStripButton1.Size = new System.Drawing.Size(76, 22); - this.toolStripButton1.Text = "html预览"; - this.toolStripButton1.ToolTipText = "快捷键 F5"; - this.toolStripButton1.Click += new System.EventHandler(this.toolStripButton1_Click); - // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; @@ -728,10 +728,11 @@ private void InitializeComponent() this.tabControl2.SelectedIndex = 0; this.tabControl2.Size = new System.Drawing.Size(331, 435); this.tabControl2.TabIndex = 1; + this.tabControl2.SelectedIndexChanged += new System.EventHandler(this.tabControl2_SelectedIndexChanged); // // tabBrowser // - this.tabBrowser.Controls.Add(this.webBrowser1); + this.tabBrowser.Controls.Add(this.webControl1); this.tabBrowser.Location = new System.Drawing.Point(4, 22); this.tabBrowser.Name = "tabBrowser"; this.tabBrowser.Size = new System.Drawing.Size(323, 409); @@ -739,16 +740,13 @@ private void InitializeComponent() this.tabBrowser.Text = "预览"; this.tabBrowser.UseVisualStyleBackColor = true; // - // webBrowser1 + // webControl1 // - this.webBrowser1.CausesValidation = false; - this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill; - this.webBrowser1.Location = new System.Drawing.Point(0, 0); - this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20); - this.webBrowser1.Name = "webBrowser1"; - this.webBrowser1.Size = new System.Drawing.Size(323, 409); - this.webBrowser1.TabIndex = 0; - this.webBrowser1.Navigating += new System.Windows.Forms.WebBrowserNavigatingEventHandler(this.webBrowser1_Navigating); + this.webControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.webControl1.Location = new System.Drawing.Point(0, 0); + this.webControl1.NavigationInfo = Awesomium.Core.NavigationInfo.Normal; + this.webControl1.Size = new System.Drawing.Size(323, 409); + this.webControl1.TabIndex = 0; // // tabHtml // @@ -769,6 +767,7 @@ private void InitializeComponent() this.rtbHtml.EnableAutoDragDrop = true; this.rtbHtml.Location = new System.Drawing.Point(3, 3); this.rtbHtml.Name = "rtbHtml"; + this.rtbHtml.ReadOnly = true; this.rtbHtml.Size = new System.Drawing.Size(317, 403); this.rtbHtml.TabIndex = 0; this.rtbHtml.Text = ""; @@ -890,7 +889,7 @@ private void InitializeComponent() this.推出ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.推出ToolStripMenuItem.Text = "推出"; // - // frmMain + // FrmMain // this.AllowDrop = true; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); @@ -904,7 +903,7 @@ private void InitializeComponent() this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MainMenuStrip = this.menuStrip1; this.MinimumSize = new System.Drawing.Size(500, 300); - this.Name = "frmMain"; + this.Name = "FrmMain"; this.Text = "码德编辑器"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing); this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.frmMain_FormClosed); @@ -962,9 +961,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripButton 字体toolStripButton10; private System.Windows.Forms.ToolStripSeparator toolStripSeparator10; private System.Windows.Forms.ToolStripButton 字体颜色toolStripButton11; - private System.Windows.Forms.SplitContainer splitContainer1; - private System.Windows.Forms.WebBrowser webBrowser1; - private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.SplitContainer splitContainer1; private System.Windows.Forms.ToolStripMenuItem 最近打开的文件ToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem3; private System.Windows.Forms.ToolStripMenuItem 关闭ToolStripMenuItem; @@ -1017,6 +1014,8 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem 设置ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem 帮助ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem 测试ToolStripMenuItem; + private System.Windows.Forms.TabControl tabControl1; + private Awesomium.Windows.Forms.WebControl webControl1; } } diff --git a/frmMain.cs b/frmMain.cs index 2fca96a..7922d80 100644 --- a/frmMain.cs +++ b/frmMain.cs @@ -1,715 +1,586 @@ using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; using System.Drawing; -using System.Drawing.Printing; +using System.Globalization; using System.IO; -using System.Reflection; using System.Runtime.InteropServices; -using System.Text; using System.Windows.Forms; - +using Awesomium.Core; +using Awesomium.Core.Data; using ICSharpCode.AvalonEdit; - using MEditor.Processers; using MRU; namespace MEditor { - public partial class frmMain : Form - { - //private PrintDocument printDocument = new PrintDocument(); - - private MRUManager mruManager=null; - - - public frmMain() - { - InitializeComponent(); - } - - private void 新建NToolStripButton_Click(object sender, EventArgs e) - { - meditorManager.Open(""); - } - - private void 新建NToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.Open(""); - } - - private void 打开OToolStripButton_Click(object sender, EventArgs e) - { - openfile(); - } - - private void 打开OToolStripMenuItem_Click(object sender, EventArgs e) - { - openfile(); - } - - private void 保存SToolStripButton_Click(object sender, EventArgs e) - { - meditorManager.Save(); - } - - private void 保存SToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.Save(); - } - - private void 另存为AToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.SaveAs(); - } - - private void 剪切UToolStripButton_Click(object sender, EventArgs e) - { - if (HaveSelection()) - meditorManager.GetTextBox().Cut(); - } - - private void 剪切TToolStripMenuItem_Click(object sender, EventArgs e) - { - - if (HaveSelection()) - meditorManager.GetTextBox().Cut(); - } - - private void 剪切ToolStripMenuItem_Click(object sender, EventArgs e) - { - if (HaveSelection()) - meditorManager.GetTextBox().Cut(); - } - - private void 复制CToolStripButton_Click(object sender, EventArgs e) - { - if (HaveSelection()) - meditorManager.GetTextBox().Copy(); - } - - private void 复制CToolStripMenuItem_Click(object sender, EventArgs e) - { - if (HaveSelection()) - meditorManager.GetTextBox().Copy(); - } - - private void 复制ToolStripMenuItem_Click(object sender, EventArgs e) - { - if (HaveSelection()) - meditorManager.GetTextBox().Copy(); - } - - private void 粘贴PToolStripButton_Click(object sender, EventArgs e) - { - - meditorManager.GetTextBox().Paste(); - - } - - private void 粘贴PToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Paste(); - } - - private void 粘贴ToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Paste(); - } - - private void 撤销toolStripButton5_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Undo(); - } - - private void 撤消UToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Undo(); - } - - private void 撤销ToolStripMenuItem2_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Undo(); - } - - private void 重做toolStripButton6_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Redo(); - } - - private void 重复RToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().Redo(); - } - - private void 全选AToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().SelectAll(); - } - - private void 全选AToolStripMenuItem1_Click(object sender, EventArgs e) - { - meditorManager.GetTextBox().SelectAll(); - } - - private void 时间日期F5ToolStripMenuItem_Click(object sender, EventArgs e) - { - TextEditor rtb = meditorManager.GetTextBox(); - string dat=System.DateTime.Now.ToString(); - rtb.Document.Insert(rtb.CaretOffset,dat); - - } - - - private bool HaveSelection() - { - var editor = meditorManager.GetTextBox(); - return editor != null && - editor.SelectionLength>0; - } - - - - private void 字体toolStripButton10_Click(object sender, EventArgs e) - { - SelectFont(); - } - - private void 字体颜色ToolStripMenuItem_Click(object sender, EventArgs e) - { - SelectForeColor(); - } - - private void 字体颜色toolStripButton11_Click(object sender, EventArgs e) - { - SelectForeColor(); - } - - #region 格式设计辅助 - private void 加粗toolStripButton7_Click(object sender, EventArgs e) - { - ProcesserFactory.Processe(meditorManager.GetTextBox(), EMark.bold); - PreviewHtml(); - } - - private void 倾斜toolStripButton8_Click(object sender, EventArgs e) - { -// Font newFont = new Font(meditorManager.GetTextBox().SelectionFont, meditorManager.GetTextBox().SelectionFont.Italic ? -// meditorManager.GetTextBox().SelectionFont.Style & ~FontStyle.Italic : meditorManager.GetTextBox().SelectionFont.Style | FontStyle.Italic); -// meditorManager.GetTextBox().SelectionFont = newFont; - - } - - private void 下划线toolStripButton9_Click(object sender, EventArgs e) - { -// Font newFont = new Font(meditorManager.GetTextBox().SelectionFont, meditorManager.GetTextBox().SelectionFont.Underline ? -// meditorManager.GetTextBox().SelectionFont.Style & ~FontStyle.Underline : meditorManager.GetTextBox().SelectionFont.Style | FontStyle.Underline); -// meditorManager.GetTextBox().SelectionFont = newFont; - - } - - private void 左对齐toolStripButton3_Click(object sender, EventArgs e) - { -// meditorManager.GetTextBox().SelectionBullet = true; -// -// -// meditorManager.GetTextBox().SelectionIndent = 0; -// meditorManager.GetTextBox().SelectionHangingIndent = 0; -// meditorManager.GetTextBox().SelectionRightIndent = 0; - } - - private void 右对齐toolStripButton1_Click(object sender, EventArgs e) - { -// meditorManager.GetTextBox().SelectionIndent = 0; -// meditorManager.GetTextBox().SelectionHangingIndent = 0; -// meditorManager.GetTextBox().SelectionRightIndent =0; - } - - private void 居中toolStripButton2_Click(object sender, EventArgs e) - { -// meditorManager.GetTextBox().SelectionIndent = 8; -// meditorManager.GetTextBox().SelectionHangingIndent = 3; -// meditorManager.GetTextBox().SelectionRightIndent = 12; - } - - private void 两端对齐toolStripButton4_Click(object sender, EventArgs e) - { -// meditorManager.GetTextBox().SelectionIndent = 0; -// meditorManager.GetTextBox().SelectionHangingIndent = 3; -// meditorManager.GetTextBox().SelectionRightIndent = 0; - } - #endregion - - #region 打印控制还没有开放 - - ////打印控制开始 - //void printDocument_BeginPrint(object sender, PrintEventArgs e) - //{ - // //设置打印文本 - // text = meditorManager.GetTextBox().Text; - //} - - //void printDocument_PrintPage(object sender, PrintPageEventArgs e) - //{ - // //用DrawString方法输出字符串,在参数中可以设置打印的字体大小和颜色,此处设置为绿色 - // e.Graphics.DrawString(text, new Font("Arial", 10), Brushes.Green, 50, 50); - //} - //private void 打印PToolStripMenuItem_Click(object sender, EventArgs e) - //{ - // //关联打印预处理代码 - // printDocument.BeginPrint += new PrintEventHandler(printDocument_BeginPrint); - - // //关联打印代码 - // printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage); - - // //定义打印对话框 - // PrintDialog printDialog = new PrintDialog(); - - // //获得用户输入 - // DialogResult dr = printDialog.ShowDialog(); - - // //若确认则打印 - // if (dr == DialogResult.OK) - // { - // printDocument.Print(); - // } - // else - // { - // return; - // } - //} - - //private void 打印PToolStripButton_Click(object sender, EventArgs e) - //{ - // //关联打印预处理代码 - // printDocument.BeginPrint += new PrintEventHandler(printDocument_BeginPrint); - - // //关联打印代码 - // printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage); - - // //定义打印对话框 - // PrintDialog printDialog = new PrintDialog(); - - // //获得用户输入 - // DialogResult dr = printDialog.ShowDialog(); - - // //若确认则打印 - // if (dr == DialogResult.OK) - // { - // printDocument.Print(); - // } - // else - // { - // return; - // } - //} - ////打印控制结束 - - #endregion - - - - private void 打印预览VToolStripMenuItem_Click(object sender, EventArgs e) - { - PreviewHtml(); - ////页面设置对话框 - //PageSetupDialog psd = new PageSetupDialog(); - - ////定义所设置的文档 - //psd.Document = printDocument; - - ////页面设置 - //psd.PageSettings = new PageSettings(); - - ////打印机设置 - //psd.ShowNetwork = false; - - ////设置对话框 - //DialogResult dr = psd.ShowDialog(); - - ////确认时设置打印文档 - //if (dr == DialogResult.OK) - //{ - // printDocument.PrinterSettings = psd.PrinterSettings; - // printDocument.DefaultPageSettings = psd.PageSettings; - //} - } - - private void frmMain_FormClosed(object sender, FormClosedEventArgs e) - { - - } - - private void 退出XToolStripMenuItem_Click(object sender, EventArgs e) - { - //先保存 - meditorManager.SaveAll(); - - //关闭程序 - Close(); - } - - private void frmMain_DragOver(object sender, DragEventArgs e) - { - e.Effect = DragDropEffects.Move; - } - - public void frmMain_DragDrop(object sender, DragEventArgs e) - { - if(e.Data.GetDataPresent(DataFormats.FileDrop)) - { - string []data=(string [])e.Data.GetData(DataFormats.FileDrop); - openfiles(data);//, RichTextBoxStreamType.PlainText); - - } - } - - private void 关闭ToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.Close(); - } - - private void toolStripButton1_Click(object sender, EventArgs e) - { - PreviewHtml(); - - } - - private void 关闭所有ToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.CloseAll(); - } - - private void 保存所有ToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.SaveAll(); - } - - private void tabControl1_Selected(object sender, TabControlEventArgs e) - { - TabSelectRec.Rec(e.TabPageIndex); - PreviewHtml(); - } - - private void toolStripButton2_Click(object sender, EventArgs e) - { - meditorManager.SaveAll(); - } - - #region 无标题栏移动窗口代码 - [DllImport("User32.dll", EntryPoint = "SendMessage")] - private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam); - [DllImport("User32.dll", EntryPoint = "ReleaseCapture")] - private static extern int ReleaseCapture(); - - private void toolStrip1_MouseDown(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - ReleaseCapture(); - SendMessage(this.Handle.ToInt32(), 0x0112, 0xF012, 0); - } - - } - - #endregion - - private void 保存ToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.Save(); - } - - private void 关闭ToolStripMenuItem1_Click(object sender, EventArgs e) - { - meditorManager.Close(); - } - - private void 打开所在文件夹ToolStripMenuItem_Click(object sender, EventArgs e) - { - meditorManager.openDir(); - } - - private void markdown格式ToolStripMenuItem_Click(object sender, EventArgs e) - { - - } - - private void 自动转行ToolStripMenuItem_Click(object sender, EventArgs e) - { - if (自动转行ToolStripMenuItem.Checked) - meditorManager.SetWordWrap(true); - else - meditorManager.SetWordWrap(false); - } - - private void 背景颜色ToolStripMenuItem_Click(object sender, EventArgs e) - { - SelectBackColor(); - } - - private void toolStripButton3_Click(object sender, EventArgs e) - { - SelectBackColor(); - } - - private void 还原系统原设置ToolStripMenuItem_Click(object sender, EventArgs e) - { - //meditorManager.SetOldStyle(); - //meditorManager.SetStyle(rtbHtml); - } - - private void frmMain_Load(object sender, EventArgs e) - { - this.Text = Application.ProductName + " V" + Application.ProductVersion; - //初始化最近打开的文件 - mruManager = new MRUManager(); - mruManager.Initialize(this,文件ToolStripMenuItem, 最近打开的文件ToolStripMenuItem, // Recent Files menu item - "Software\\YihuiStudio\\MEditor"); // Registry path to keep MRU list - mruManager.CurrentDir = "....."; // default is current directory - mruManager.MaxMRULength = 10; // default is 10 - mruManager.MaxDisplayNameLength = 40; - - //定义编辑管理器 - meditorManager = new MarkdownEditorManager(this, tabControl1, mruManager,webBrowser1); - ReadCss(); - //webBrowser1.Navigate("about:blank"); - meditorManager.SetStyle(rtbHtml); - //webBrowser1.DocumentText = meditorManager.GetHTMLStyle(""); - - _filemonitor = new FileMonitor(fsw_Changed); - string command = Environment.CommandLine;//获取进程命令行参数 - if (!string.IsNullOrEmpty(command)) - { - string[] para = command.Split('\"'); - if (para.Length > 2) - { - string pathC = para[2];//获取打开的文件的路径 - if (pathC.Length > 3) - { - openfile(pathC); - } - else - { - meditorManager.Open(""); - } - } - } - else - { - meditorManager.Open(""); - } - - //this.timer1.Start(); - rtbHtml.EnableAutoDragDrop = false; - rtbHtml.AllowDrop = true; - -// rtbHtml.KeyDown += rtbHtml_KeyDown; - rtbHtml.DragDrop += new DragEventHandler(frmMain_DragDrop); - rtbHtml.DragEnter += new DragEventHandler(rtbHtml_DragEnter); - - tabControl1.MouseDown += new MouseEventHandler(tabControl1_MouseDown); - tabControl2.MouseDown+=new MouseEventHandler(tabControl1_MouseDown); - //tabControl1.GotFocus += new EventHandler(tabControl1_GotFocus); - - } - - - void tabControl1_GotFocus(object sender, EventArgs e) - { - SendKeys.Send("{tab}"); - } - - void tabControl1_MouseDown(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Right) - { - TabControl tabc = (TabControl)sender; - - for (int i = 0; i < tabc.TabCount; i++) - { - Rectangle recTab = tabc.GetTabRect(i); - if (recTab.Contains(e.X, e.Y)) - { - tabc.SelectedIndex = i; - } - } - } - } - - void rtbHtml_DragEnter(object sender, DragEventArgs e) - { - - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - e.Effect = DragDropEffects.Link; - } - else - { - e.Effect = DragDropEffects.None; - } - } - - private void 界面布局左右互换ToolStripMenuItem_Click(object sender, EventArgs e) - { - SwithFlaout(); - } - - private void 关联md扩展名ToolStripMenuItem_Click(object sender, EventArgs e) - { - regExtFile(); - } - - private void 转到行ToolStripMenuItem_Click(object sender, EventArgs e) - { - MarkdownEditor me= meditorManager.GetCurrEditor(); - if(me==null)return ; - - if (me.GetTextBox().Document.LineCount > 0) - { - //Show the dialog - GoToLineDialog gtl = new GoToLineDialog(me.GetTextBox()); - gtl.ShowDialog(); - } - } - - private void 转为大写ToolStripMenuItem_Click(object sender, EventArgs e) - { - MarkdownEditor me= meditorManager.GetCurrEditor(); - if(me==null)return ; - me.GetTextBox().SelectedText=me.GetTextBox().SelectedText.ToUpper(); - } - - private void 转为小写ToolStripMenuItem_Click(object sender, EventArgs e) - { - MarkdownEditor me = meditorManager.GetCurrEditor(); - if (me == null) return; - me.GetTextBox().SelectedText=me.GetTextBox().SelectedText.ToLower(); - } - - private void 替换ToolStripMenuItem_Click(object sender, EventArgs e) - { - MarkdownEditor me = meditorManager.GetCurrEditor(); - if (me == null) return; - - } - - private void 查找替换ToolStripMenuItem_Click(object sender, EventArgs e) - { - MarkdownEditor me = meditorManager.GetCurrEditor(); - if (me == null) return; - } - - private void splitContainer1_DoubleClick(object sender, EventArgs e) - { - if (isLeft) - { - - splitContainer1.Panel2Collapsed = !splitContainer1.Panel2Collapsed; - } - else - { - splitContainer1.Panel1Collapsed = !splitContainer1.Panel1Collapsed; - } - } - - private void 经典黑底白字ToolStripMenuItem_Click(object sender, EventArgs e) - { - - } - - private void 取消md文件关联ToolStripMenuItem_Click(object sender, EventArgs e) - { - UnRegExtfile(); - } - - #region MEditor links - private void markdown语法介绍ToolStripMenuItem_Click(object sender, EventArgs e) - { - //showSyntax("https://github.com/5d13cn/MEditor/blob/master/resoucesdocs/syntax.md"); - showSyntax("http://www.cnblogs.com/yihuiso/archive/2011/04/13/markdown.html"); - } - - private void markdown语法介绍精简版ToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("http://www.cnblogs.com/yihuiso/archive/2011/04/13/minimarkdown.html"); - } - - private void markdown语法介绍二ToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("https://github.com/othree/markdown-syntax-zhtw/blob/master/syntax.md"); - } - - private void markdownSytnxToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("http://daringfireball.net/projects/markdown/syntax"); - } - private void 关于MEditorToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("https://github.com/5d13cn/MEditor/blob/master/resoucesdocs/about.md"); - } - private void mEditor快捷键ToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("https://github.com/5d13cn/MEditor/blob/master/resoucesdocs/shortcut.md"); - } - private void mEditor网站ToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("https://github.com/5d13cn/MEditor"); - } - - private void 检查最新版ToolStripMenuItem_Click(object sender, EventArgs e) - { - showSyntax("https://github.com/5d13cn/MEditor/raw/master/lastver.txt"); - } - #endregion - - private void 字体OToolStripMenuItem_Click(object sender, EventArgs e) - { - SelectFont(); - } - - private void html预览样式设计ToolStripMenuItem_Click(object sender, EventArgs e) - { - editCss(); - } - - private void 通用选项ToolStripMenuItem_Click(object sender, EventArgs e) - { - editCss(); - } - - private void frmMain_FormClosing(object sender, FormClosingEventArgs e) - { - bool isCancel=!meditorManager.CloseAll(); - if (isCancel) - e.Cancel = true; - } - - private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e) - { - string url = e.Url.ToString(); - if (url == "about:blank") return; - - if (url.StartsWith("http://") || url.StartsWith("https://")) - { - return; - } - - //if (url.EndsWith(".md")) - //{ - url = url.Remove(0, 6); - MarkdownEditor me=meditorManager.GetCurrEditor(); - if(me==null) return ; - url=Path.Combine(Path.GetDirectoryName(me.FileName),url); - - if (_regexExtMarkdowns.IsMatch(url) || _regexExtOthertext.IsMatch(url)) - { - e.Cancel = true; - openfile(url); - } - //webBrowser1.Navigate(url); - //} - } - } + public partial class FrmMain : Form + { + //private PrintDocument printDocument = new PrintDocument(); + + private MRUManager mruManager; + private WebSession session; + + public FrmMain() + { + InitializeComponent(); + string dataPath = String.Format("{0}{1}Cache", Path.GetDirectoryName(Application.ExecutablePath), Path.DirectorySeparatorChar); + + session = WebCore.Sessions[dataPath] ?? WebCore.CreateWebSession(dataPath, WebPreferences.Default); + session.AddDataSource("local", new ResourceDataSource(ResourceType.Packed)); + this.webControl1.WebSession = session; + + } + + private void 新建NToolStripButton_Click(object sender, EventArgs e) + { + meditorManager.Open(""); + } + + private void 新建NToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.Open(""); + } + + private void 打开OToolStripButton_Click(object sender, EventArgs e) + { + openfile(); + } + + private void 打开OToolStripMenuItem_Click(object sender, EventArgs e) + { + openfile(); + } + + private void 保存SToolStripButton_Click(object sender, EventArgs e) + { + meditorManager.Save(); + } + + private void 保存SToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.Save(); + } + + private void 另存为AToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.SaveAs(); + } + + private void 剪切UToolStripButton_Click(object sender, EventArgs e) + { + if (HaveSelection()) + meditorManager.GetTextBox().Cut(); + } + + private void 复制CToolStripButton_Click(object sender, EventArgs e) + { + if (HaveSelection()) + meditorManager.GetTextBox().Copy(); + } + + private void 粘贴PToolStripButton_Click(object sender, EventArgs e) + { + meditorManager.GetTextBox().Paste(); + } + + private void 撤销toolStripButton5_Click(object sender, EventArgs e) + { + meditorManager.GetTextBox().Undo(); + } + + private void 重做toolStripButton6_Click(object sender, EventArgs e) + { + meditorManager.GetTextBox().Redo(); + } + + private void 时间日期F5ToolStripMenuItem_Click(object sender, EventArgs e) + { + TextEditor rtb = meditorManager.GetTextBox(); + string dat = DateTime.Now.ToString(CultureInfo.InvariantCulture); + rtb.Document.Insert(rtb.CaretOffset, dat); + } + + + private bool HaveSelection() + { + TextEditor editor = meditorManager.GetTextBox(); + return editor != null && + editor.SelectionLength > 0; + } + + + private void 字体toolStripButton10_Click(object sender, EventArgs e) + { + SelectFont(); + } + + private void 字体颜色ToolStripMenuItem_Click(object sender, EventArgs e) + { + SelectForeColor(); + } + + private void 字体颜色toolStripButton11_Click(object sender, EventArgs e) + { + SelectForeColor(); + } + + private void 打印预览VToolStripMenuItem_Click(object sender, EventArgs e) + { + ////页面设置对话框 + //PageSetupDialog psd = new PageSetupDialog(); + + ////定义所设置的文档 + //psd.Document = printDocument; + + ////页面设置 + //psd.PageSettings = new PageSettings(); + + ////打印机设置 + //psd.ShowNetwork = false; + + ////设置对话框 + //DialogResult dr = psd.ShowDialog(); + + ////确认时设置打印文档 + //if (dr == DialogResult.OK) + //{ + // printDocument.PrinterSettings = psd.PrinterSettings; + // printDocument.DefaultPageSettings = psd.PageSettings; + //} + } + + private void frmMain_FormClosed(object sender, FormClosedEventArgs e) + { + } + + private void 退出XToolStripMenuItem_Click(object sender, EventArgs e) + { + //先保存 + meditorManager.SaveAll(); + + //关闭程序 + Close(); + } + + private void frmMain_DragOver(object sender, DragEventArgs e) + { + e.Effect = DragDropEffects.Move; + } + + public void frmMain_DragDrop(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + var data = (string[])e.Data.GetData(DataFormats.FileDrop); + openfiles(data); //, RichTextBoxStreamType.PlainText); + } + } + + private void 关闭ToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.Close(); + } + + private void toolStripButton1_Click(object sender, EventArgs e) + { + } + + private void 关闭所有ToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.CloseAll(); + } + + private void 保存所有ToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.SaveAll(); + } + + private void tabControl1_Selected(object sender, TabControlEventArgs e) + { + MarkdownEditor markdownEditor = this.meditorManager.GetCurrEditor(); + if (markdownEditor!=null) + { + string markdown = markdownEditor.GetMarkdown(); + this.webControl1.Text = Utils.AppendValidHTMLTags(markdown); + } + + TabSelectRec.Rec(e.TabPageIndex); + } + + private void toolStripButton2_Click(object sender, EventArgs e) + { + meditorManager.SaveAll(); + } + + private void 保存ToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.Save(); + } + + private void 关闭ToolStripMenuItem1_Click(object sender, EventArgs e) + { + meditorManager.Close(); + } + + private void 打开所在文件夹ToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.openDir(); + } + + private void 自动转行ToolStripMenuItem_Click(object sender, EventArgs e) + { + meditorManager.SetWordWrap(自动转行ToolStripMenuItem.Checked); + } + + private void 背景颜色ToolStripMenuItem_Click(object sender, EventArgs e) + { + SelectBackColor(); + } + + private void toolStripButton3_Click(object sender, EventArgs e) + { + SelectBackColor(); + } + + private void 还原系统原设置ToolStripMenuItem_Click(object sender, EventArgs e) + { + //meditorManager.SetOldStyle(); + //meditorManager.SetStyle(rtbHtml); + } + + private void frmMain_Load(object sender, EventArgs e) + { + Text = Application.ProductName + " V" + Application.ProductVersion; + //初始化最近打开的文件 + mruManager = new MRUManager(); + mruManager.Initialize(this, 文件ToolStripMenuItem, 最近打开的文件ToolStripMenuItem, // Recent Files menu item + "Software\\YihuiStudio\\MEditor"); // Registry path to keep MRU list + mruManager.CurrentDir = "....."; // default is current directory + mruManager.MaxMRULength = 10; // default is 10 + mruManager.MaxDisplayNameLength = 40; + + //定义编辑管理器 + meditorManager = new MarkdownEditorManager(this, tabControl1, mruManager, webControl1); + ReadCss(); + meditorManager.SetStyle(rtbHtml); + + _filemonitor = new FileMonitor(fsw_Changed); + string command = Environment.CommandLine; //获取进程命令行参数 + if (!string.IsNullOrEmpty(command)) + { + string[] para = command.Split('\"'); + if (para.Length > 2) + { + string pathC = para[2]; //获取打开的文件的路径 + if (pathC.Length > 3) + { + openfile(pathC); + } + else + { + meditorManager.Open(""); + } + } + } + else + { + meditorManager.Open(""); + } + + //this.timer1.Start(); + rtbHtml.EnableAutoDragDrop = false; + rtbHtml.AllowDrop = true; + + // rtbHtml.KeyDown += rtbHtml_KeyDown; + rtbHtml.DragDrop += frmMain_DragDrop; + rtbHtml.DragEnter += rtbHtml_DragEnter; + + tabControl1.MouseDown += tabControl1_MouseDown; + tabControl2.MouseDown += tabControl1_MouseDown; + //tabControl1.GotFocus += new EventHandler(tabControl1_GotFocus); + } + + + private void tabControl1_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + { + var tabc = (TabControl)sender; + + for (int i = 0; i < tabc.TabCount; i++) + { + Rectangle recTab = tabc.GetTabRect(i); + if (recTab.Contains(e.X, e.Y)) + { + tabc.SelectedIndex = i; + } + } + } + } + + private void rtbHtml_DragEnter(object sender, DragEventArgs e) + { + e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Link : DragDropEffects.None; + } + + private void 界面布局左右互换ToolStripMenuItem_Click(object sender, EventArgs e) + { + SwithFlaout(); + } + + private void 关联md扩展名ToolStripMenuItem_Click(object sender, EventArgs e) + { + regExtFile(); + } + + private void 转到行ToolStripMenuItem_Click(object sender, EventArgs e) + { + MarkdownEditor me = meditorManager.GetCurrEditor(); + if (me == null) return; + + if (me.GetTextBox().Document.LineCount > 0) + { + //Show the dialog + var gtl = new GoToLineDialog(me.GetTextBox()); + gtl.ShowDialog(); + } + } + + private void 转为大写ToolStripMenuItem_Click(object sender, EventArgs e) + { + MarkdownEditor me = meditorManager.GetCurrEditor(); + if (me == null) return; + me.GetTextBox().SelectedText = me.GetTextBox().SelectedText.ToUpper(); + } + + private void 转为小写ToolStripMenuItem_Click(object sender, EventArgs e) + { + MarkdownEditor me = meditorManager.GetCurrEditor(); + if (me == null) return; + me.GetTextBox().SelectedText = me.GetTextBox().SelectedText.ToLower(); + } + + private void 替换ToolStripMenuItem_Click(object sender, EventArgs e) + { + MarkdownEditor me = meditorManager.GetCurrEditor(); + } + + private void 查找替换ToolStripMenuItem_Click(object sender, EventArgs e) + { + MarkdownEditor me = meditorManager.GetCurrEditor(); + } + + private void splitContainer1_DoubleClick(object sender, EventArgs e) + { + if (isLeft) + { + splitContainer1.Panel2Collapsed = !splitContainer1.Panel2Collapsed; + } + else + { + splitContainer1.Panel1Collapsed = !splitContainer1.Panel1Collapsed; + } + } + + private void 经典黑底白字ToolStripMenuItem_Click(object sender, EventArgs e) + { + } + + private void 取消md文件关联ToolStripMenuItem_Click(object sender, EventArgs e) + { + UnRegExtfile(); + } + + private void 字体OToolStripMenuItem_Click(object sender, EventArgs e) + { + SelectFont(); + } + + private void html预览样式设计ToolStripMenuItem_Click(object sender, EventArgs e) + { + editCss(); + } + + private void 通用选项ToolStripMenuItem_Click(object sender, EventArgs e) + { + editCss(); + } + + private void frmMain_FormClosing(object sender, FormClosingEventArgs e) + { + bool isCancel = !meditorManager.CloseAll(); + if (isCancel) + e.Cancel = true; + } + + + #region MEditor links + + private void markdown语法介绍ToolStripMenuItem_Click(object sender, EventArgs e) + { + //showSyntax("https://github.com/5d13cn/MEditor/blob/master/resoucesdocs/syntax.md"); + showSyntax("http://www.cnblogs.com/yihuiso/archive/2011/04/13/markdown.html"); + } + + private void markdown语法介绍精简版ToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("http://www.cnblogs.com/yihuiso/archive/2011/04/13/minimarkdown.html"); + } + + private void markdown语法介绍二ToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("https://github.com/othree/markdown-syntax-zhtw/blob/master/syntax.md"); + } + + private void markdownSytnxToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("http://daringfireball.net/projects/markdown/syntax"); + } + + private void 关于MEditorToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("https://github.com/5d13cn/MEditor/blob/master/resoucesdocs/about.md"); + } + + private void mEditor快捷键ToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("https://github.com/5d13cn/MEditor/blob/master/resoucesdocs/shortcut.md"); + } + + private void mEditor网站ToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("https://github.com/5d13cn/MEditor"); + } + + private void 检查最新版ToolStripMenuItem_Click(object sender, EventArgs e) + { + showSyntax("https://github.com/5d13cn/MEditor/raw/master/lastver.txt"); + } + + #endregion + + #region 无标题栏移动窗口代码 + + [DllImport("User32.dll", EntryPoint = "SendMessage")] + private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam); + + [DllImport("User32.dll", EntryPoint = "ReleaseCapture")] + private static extern int ReleaseCapture(); + + private void toolStrip1_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + ReleaseCapture(); + SendMessage(Handle.ToInt32(), 0x0112, 0xF012, 0); + } + } + + #endregion + + #region 格式设计辅助 + + private void 加粗toolStripButton7_Click(object sender, EventArgs e) + { + ProcesserFactory.Processe(meditorManager.GetTextBox(), EMark.bold); + } + + private void 倾斜toolStripButton8_Click(object sender, EventArgs e) + { + // Font newFont = new Font(meditorManager.GetTextBox().SelectionFont, meditorManager.GetTextBox().SelectionFont.Italic ? + // meditorManager.GetTextBox().SelectionFont.Style & ~FontStyle.Italic : meditorManager.GetTextBox().SelectionFont.Style | FontStyle.Italic); + // meditorManager.GetTextBox().SelectionFont = newFont; + } + + private void 下划线toolStripButton9_Click(object sender, EventArgs e) + { + // Font newFont = new Font(meditorManager.GetTextBox().SelectionFont, meditorManager.GetTextBox().SelectionFont.Underline ? + // meditorManager.GetTextBox().SelectionFont.Style & ~FontStyle.Underline : meditorManager.GetTextBox().SelectionFont.Style | FontStyle.Underline); + // meditorManager.GetTextBox().SelectionFont = newFont; + } + + + #endregion + + private void tabControl2_SelectedIndexChanged(object sender, EventArgs e) + { + TextEditor textEditor = meditorManager.GetTextBox(); + string text = Utils.ConvertTextToHTML(textEditor.Text); + this.rtbHtml.Text = text; + + } + /// + /// 获取源代码 + /// + /// + private string GrabSources() + { + return webControl1.ExecuteJavascriptWithResult("document.getElementsByTagName('html')[0].innerHTML"); + } + #region 打印控制还没有开放 + + ////打印控制开始 + //void printDocument_BeginPrint(object sender, PrintEventArgs e) + //{ + // //设置打印文本 + // text = meditorManager.GetTextBox().Text; + //} + + //void printDocument_PrintPage(object sender, PrintPageEventArgs e) + //{ + // //用DrawString方法输出字符串,在参数中可以设置打印的字体大小和颜色,此处设置为绿色 + // e.Graphics.DrawString(text, new Font("Arial", 10), Brushes.Green, 50, 50); + //} + //private void 打印PToolStripMenuItem_Click(object sender, EventArgs e) + //{ + // //关联打印预处理代码 + // printDocument.BeginPrint += new PrintEventHandler(printDocument_BeginPrint); + + // //关联打印代码 + // printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage); + + // //定义打印对话框 + // PrintDialog printDialog = new PrintDialog(); + + // //获得用户输入 + // DialogResult dr = printDialog.ShowDialog(); + + // //若确认则打印 + // if (dr == DialogResult.OK) + // { + // printDocument.Print(); + // } + // else + // { + // return; + // } + //} + + //private void 打印PToolStripButton_Click(object sender, EventArgs e) + //{ + // //关联打印预处理代码 + // printDocument.BeginPrint += new PrintEventHandler(printDocument_BeginPrint); + + // //关联打印代码 + // printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage); + + // //定义打印对话框 + // PrintDialog printDialog = new PrintDialog(); + + // //获得用户输入 + // DialogResult dr = printDialog.ShowDialog(); + + // //若确认则打印 + // if (dr == DialogResult.OK) + // { + // printDocument.Print(); + // } + // else + // { + // return; + // } + //} + ////打印控制结束 + + #endregion + } } \ No newline at end of file diff --git a/frmMain_code.cs b/frmMain_code.cs index ddedc05..e540956 100644 --- a/frmMain_code.cs +++ b/frmMain_code.cs @@ -1,579 +1,560 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.ComponentModel; -using System.Data; +using System.Diagnostics; using System.Drawing; -using System.Drawing.Printing; using System.IO; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; - -using MarkdownSharp; using MEditor.Properties; using MRU; - -namespace MEditor -{ - public partial class frmMain : Form, IMRUClient - { - private static string _myExtName = ".md"; - private string myExtName = "Markdown文件|*" + _myExtName + "|所有文件|*.*"; - private MarkdownEditorManager meditorManager=null; - FileMonitor _filemonitor = null; - - - private Color _bgColor = Color.FromArgb(0x4a, 0x52, 0x5a);//20,0x20,0x20; - private Color _foreColor = Color.FromArgb(0xff, 0xff, 0xff); //0xf2,0xf0,0xdf - private Font _font = new Font("微软雅黑",12); - - private string _extfileother = ""; - private Regex _regexExtMarkdowns = new Regex(@"\.md|\.markdown", RegexOptions.Compiled); - private Regex _regexExtOthertext = new Regex(@"\.txt|\.js|\.htm|\.xml|\.as|\.log|\.php|\.cs", RegexOptions.Compiled); - private Regex _regexExtHtml = new Regex(@"\.htm|\.xml", RegexOptions.Compiled); - - #region defaultCss - private string _defcss = @" -body,td,th {font-family:""微软雅黑"", Verdana, ""Bitstream Vera Sans"", sans-serif; } -body { - margin-top: 0; - padding: 0; - line-height: 1.5em; - color: #{1}; - background-color: #{0}; - text-align: left; - } -a em { - padding-bottom: 2px; - } - - -sup { - line-height: 0px; - } -sup a:link { - padding: 3px; - } -sup a:visited { - padding: 3px; - } - - -p { - margin: 0 0 1.6em 0; - padding: 0; - } - -h1 { - font-family: ""黑体"",""Gill Sans"", ""Gill Sans Std"", ""Gill Sans MT"", Georgia, serif; - font-size: 1.55em; - line-height: 1.5em; - text-align: left; - font-weight: bold; - margin: 0em 0px 1.25em 0px; - } - -h2 { - font-family:""黑体"", ""Gill Sans"", ""Gill Sans Std"", ""Gill Sans MT"", Verdana, ""Bitstream Vera Sans"", sans-serif; - font-size: 1.1em; /* 1 */ - text-align: left; - font-weight:bold; - line-height: 1.8em; - letter-spacing: .2em; - margin: 1em 0 1em 0; - text-transform: uppercase; - } - -h1 + h2 { - margin-top: 2em; - } -h2 + h3 { - margin-top: 1.5em; - } - -h3 { - font-family: ""黑体"",Gill Sans"", ""Gill Sans Std"", ""Gill Sans MT"", Verdana, ""Bitstream Vera Sans"", sans-serif; - font-size: .91em; - text-align: left; - font-weight: normal; - line-height: 1.8em; - letter-spacing: .2em; - margin-bottom: 0.4em; - margin-top: 0.5em; - text-transform: uppercase; - } - -p + h3 { - margin-top: 4em; - } -pre + h3 { - margin-top: 4em; - } - -h6 + h2 { - margin-top: 2em; - } - -h4, h5, h6 { - font-family: Verdana, ""Bitstream Vera Sans"", sans-serif; - font-size: 1em; - text-align: left; - font-weight: bold; - line-height: 1.5em; - margin: 1em 0 0 0; - } - -strong { - font-weight: bold; - font-size: .91em; - letter-spacing: .2em; - text-transform: uppercase; - } - -em { - font-style: normal; - } -blockquote { - font-size: 1em; - margin: 2em 2em 2em 1em; - padding: 0 .75em 0 1.25em; - border-left: 1px solid #777; - border-right: 0px solid #777; - } - -blockquote strong { - font-weight: bold; - font-size: 1em; - letter-spacing: normal; - text-transform: none; - } - - -img { - margin-top: 5px; - } - -thead { - font-weight: bold; - } - - -ul, ol { - padding-left: 1.25em; - margin: 0 0 2em 1em; - } - - -pre { - font-family: ""Bitstream Vera Sans Mono"", Courier, Monaco, ProFont, ""American Typewriter"", ""Andale Mono"", monospace; - line-height: 1.45em; - color: #{1}; - background-color: inherit; - margin: 0.5em 0 0.5em 0; - padding: 5px 0 5px 10px; - border-width: 1px 0 1px 0; - border-color: #6b6b6b; - border-style: dashed; - } - -code { - font-family: Monaco, ProFont, ""Bitstream Vera Sans Mono"", ""American Typewriter"", ""Andale Mono"", monospace; - font-size: 0.91em; /* 1.09em for Courier */ - } - - -ul { - list-style-type: square; - } - -ul ul { - list-style-type: disc; - } -ul ul ul { - list-style-type: circle; - } - -hr { - height: 1px; - margin: 1em 1em 1em 0; - text-align: center; - border-color: #777; - border-width: 0; - border-style: dotted; - } - -dt { - font-family: Verdana, ""Bitstream Vera Sans"", sans-serif; - font-size: 1em; - text-align: left; - font-weight: normal; - margin: 0 0 .4em 0; - letter-spacing: normal; - text-transform: none; - } -dd { - margin: auto auto 1.5em 1em; - } - -dd p { - margin: 0 0 1em 0; - } - -table{ - border:1px #CCC solid; -border-collapse: separate;border-spacing: 0; -} -th,td{padding:5px;border: 1px solid #CCC;} -"; - #endregion - - public void ReadCss() - { - _font = Settings.Default.font; - _foreColor = Settings.Default.color; - _bgColor = Settings.Default.bgcolor; - _defcss = Settings.Default.css; - _extfileother = Settings.Default.extfile; - - _regexExtOthertext = new Regex(_regexExtOthertext.Replace(".", @"\."), RegexOptions.Compiled); - - meditorManager.SetFont(_font); - meditorManager.SetForeColor(_foreColor); - meditorManager.SetBackColor(_bgColor ); - meditorManager.SetCss(_defcss); - - //MessageBox.Show(Settings.Default.appconfig.ToString()); - } - - public void OpenMRUFile(string fileName) - { - openfile(fileName); - } - - public void openfiles(string[] fileNames) - { - foreach (string s in fileNames) - openfile(s); - } - - private void openfile(string fileName) - { - if (meditorManager.Open(fileName)) - { - Add(fileName); - } - else - mruManager.Remove(fileName); // when Open File operation failed - } - - private SortedList _monitorList = new SortedList(); - public void Add(string fullpath) - { - string dir = System.IO.Path.GetDirectoryName(fullpath); - if (_monitorList.ContainsKey(dir)) - { - return; - } - _monitorList.Add(dir, true); - _filemonitor.Add(dir, "*.md"); - } - - delegate bool dirupdated(string filename); - void fsw_Changed(object sender, System.IO.FileSystemEventArgs e) - { - if (this.InvokeRequired) - { - this.Invoke(new dirupdated(meditorManager.RefrushOpen), e.Name); - return; - } - meditorManager.RefrushOpen(e.Name); - } - - private void openfile() - { - OpenFileDialog fileone = new OpenFileDialog(); - fileone.Filter = myExtName ; - fileone.FilterIndex = 1; - if (fileone.ShowDialog() == DialogResult.OK) - { - try - { - openfile(fileone.FileName); - } - catch (Exception ex) - { - MessageBox.Show("出现了错误:" + ex.Message); - mruManager.Remove(fileone.FileName); // when Open File operation failed - } - } - } - - private void PreviewHtml() - { - this.toolStripStatusLabel1.Text = " 正在转换。。。。 "; - - MarkdownEditor meditor = meditorManager.SetStyle(); - if (meditor == null) - return; - bool bhtml = filetypeConvert(meditor); - - tabBrowser.Text = meditor.MarkdownPage.Text; - this.toolStripStatusLabel1.Text = "当前文档:" + meditor.FileName; - - if (isLeft) - { - if (bhtml && splitContainer1.Panel2Collapsed) - splitContainer1.Panel2Collapsed = false; - } - else - { - if (bhtml && splitContainer1.Panel1Collapsed) - splitContainer1.Panel1Collapsed = false; - } - - //tabControl1.Focus(); - meditor.GetTextBox().Focus(); - } - - private bool filetypeConvert(MarkdownEditor meditor) - { - string marktext = meditor.GetMarkdown(); - if (string.IsNullOrEmpty(marktext)) - { - return false ; - } - - string ext = Path.GetExtension(meditor.FileName); - if (_regexExtMarkdowns.IsMatch(ext)) - { - string html=""; - Markdown mark = new Markdown(); - html = mark.Transform(marktext); - rtbHtml.Text = html; - webBrowser1.DocumentText = meditorManager.GetHTMLStyle(html); - return true; - } - - if (_regexExtHtml.IsMatch(ext)) - { - webBrowser1.DocumentText = marktext; - rtbHtml.Text = marktext; - return true; - } - - if (_regexExtOthertext.IsMatch(ext)) - { - webBrowser1.DocumentText = meditorManager.GetHTMLStyle("
    "+marktext+"
    "); - rtbHtml.Text = marktext; - return true; - } - return false; - } - - public void SelectForeColor() - { - ColorDialog color = new ColorDialog(); - if (color.ShowDialog() == DialogResult.OK) - { - _foreColor = color.Color; - meditorManager.SetForeColor(_foreColor); - meditorManager.SetStyle(rtbHtml); - - //Settings.Default.color = _foreColor; - //Settings.Default.Save(); - } - } - - public void SetOldStyle() - { - _bgColor = Color.FromArgb(0xff, 0xff, 0xff);//20,0x20,0x20; - _foreColor = Color.FromArgb(0x00, 0x00, 0x00); //0xf2,0xf0,0xdf - _font = new Font("微软雅黑",12); - - setstyle(); - //SaveSettings(); - } - - public void SetBlackWhiteStyle() - { - _bgColor = Color.FromArgb(0x4a, 0x52, 0x5a);//20,0x20,0x20; - _foreColor = Color.FromArgb(0xff, 0xff, 0xff); //0xf2,0xf0,0xdf - _font = new Font("微软雅黑", 12); - setstyle(); - //SaveSettings(); - } - - private void setstyle() - { - meditorManager.SetFont(_font); - meditorManager.SetForeColor(_foreColor); - meditorManager.SetBackColor(_bgColor); - - meditorManager.SetStyle(rtbHtml); - } - - private string convertColor(Color co) - { - return co.R.ToString() +","+ co.G.ToString() +","+ co.B.ToString(); - } - public void SaveSettings() - { - string appconfig = Settings.Default.appconfig; - - appconfig=appconfig.Replace("{font}", _font.ToString()); - appconfig = appconfig.Replace("{color}", convertColor(_foreColor)); - appconfig = appconfig.Replace("{bgcolor}", convertColor(_bgColor)); - appconfig = appconfig.Replace("{css}", _defcss); - appconfig = appconfig.Replace("{extfile}", _extfileother); - - string conffile = Application.UserAppDataPath; - conffile = Application.ExecutablePath+".config"; - using (StreamWriter sw = new StreamWriter(conffile, false, Encoding.UTF8)) - { - sw.Write(appconfig); - sw.Close(); - } - } - - public void SelectBackColor() - { - ColorDialog color = new ColorDialog(); - if (color.ShowDialog() == DialogResult.OK) - { - _bgColor = color.Color; - meditorManager.SetBackColor(_bgColor); - meditorManager.SetStyle(rtbHtml); - - //Settings.Default.bgcolor = _bgColor; - //Settings.Default.Save(); - } - } - public void SelectFont() - { - FontDialog font = new FontDialog(); - if (font.ShowDialog() == DialogResult.OK) - { - _font = font.Font; - meditorManager.SetFont(_font); - meditorManager.SetStyle(rtbHtml); - - //Settings.Default.font =_font; - //Settings.Default.Save(); - } - } - - public void SetCss(string css) - { - _defcss = css; - meditorManager.SetCss(_defcss); - PreviewHtml(); - //Settings.Default.css = _defcss; - //Settings.Default.Save(); - } - - public void SetExt(string ext) - { - _extfileother = ext; - _regexExtOthertext = new Regex(_extfileother.Replace(".", @"\."), RegexOptions.Compiled); - } - - private void editCss() - { - frmCss fcss = new frmCss(_defcss,this); - fcss.ShowDialog(); - } - - private void showSyntax(string url) - { - toolStripStatusLabel1.Text ="正在打开" +url+"..." ; - System.Diagnostics.Process.Start(url); - //webBrowser1.Navigate(url); - //webBrowser1.DocumentText = html; - - if (splitContainer1.Panel2Collapsed) - splitContainer1.Panel2Collapsed = false; - } - - private bool isLeft = true; - private void SwithFlaout() - { - if (isLeft) - { - this.splitContainer1.Panel2.Controls.Add(this.tabControl1); - this.splitContainer1.Panel1.Controls.Add(this.tabControl2); - if (splitContainer1.Panel2Collapsed) - { - splitContainer1.Panel2Collapsed = false; - splitContainer1.Panel1Collapsed = true; - } - isLeft = false; - return; - } - this.splitContainer1.Panel1.Controls.Add(this.tabControl1); - this.splitContainer1.Panel2.Controls.Add(this.tabControl2); - if (splitContainer1.Panel1Collapsed) - { - splitContainer1.Panel1Collapsed = false; - splitContainer1.Panel2Collapsed = true; - } - isLeft = true; - } - - private void UnRegExtfile() - { - bool rel= FileTypeRegister.UnRegister(_myExtName); - - if (!rel && IsWindowsVistaOrNewer) - { - MessageBox.Show("您是在windows7 下运行的此程序,如果执行完扩展名关联但没有成功,请您以“管理员权限方式再打开此程序再关联一次”!"); - } - - } - /// - /// Gets a value indicating if the operating system is a Windows Vista or a newer one. - /// - public static bool IsWindowsVistaOrNewer - { - get { return (Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major >= 6); } - } - private void regExtFile() - { - - Assembly asm = Assembly.GetExecutingAssembly(); - string resourceName = "MEditor.logo.ico"; - Stream stream = asm.GetManifestResourceStream(resourceName); - string icofile = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\markdown.ico"; - FileStream fs = new FileStream(icofile, FileMode.Create, FileAccess.Write); - byte[] bs = new byte[stream.Length]; - stream.Read(bs, 0, (int)stream.Length); - fs.Write(bs, 0, bs.Length); - fs.Flush(); - fs.Close(); - fs.Dispose(); - - //注册关联的文件扩展名 - FileTypeRegInfo fr = new FileTypeRegInfo(); - fr.Description = "markdown文档格式"; - fr.ExePath = Application.ExecutablePath; - fr.ExtendName = _myExtName; - fr.IcoPath = icofile; - - bool rel = true; - if (FileTypeRegister.CheckIfRegistered(fr.ExtendName)) - { - rel=FileTypeRegister.UpdateRegInfo(fr); - } - else{ - rel=FileTypeRegister.Register(fr); - } - - if (!rel && IsWindowsVistaOrNewer) - { - MessageBox.Show("您是在windows7 下运行的此程序,如果执行完扩展名关联但没有成功,请您以“管理员权限方式再打开此程序再关联一次”!"); - } - } - } -} - + + +namespace MEditor +{ + public partial class FrmMain : Form, IMRUClient + { + private static string _myExtName = ".md"; + private readonly SortedList _monitorList = new SortedList(); + private readonly Regex _regexExtHtml = new Regex(@"\.htm|\.xml", RegexOptions.Compiled); + private readonly Regex _regexExtMarkdowns = new Regex(@"\.md|\.markdown", RegexOptions.Compiled); + private readonly string myExtName = "Markdown文件|*" + _myExtName + "|所有文件|*.*"; + + + private Color _bgColor = Color.FromArgb(0x4a, 0x52, 0x5a); //20,0x20,0x20; + + private string _extfileother = ""; + private FileMonitor _filemonitor; + private Font _font = new Font("微软雅黑", 12); + private Color _foreColor = Color.FromArgb(0xff, 0xff, 0xff); //0xf2,0xf0,0xdf + + private Regex _regexExtOthertext = new Regex(@"\.txt|\.js|\.htm|\.xml|\.as|\.log|\.php|\.cs", + RegexOptions.Compiled); + + private bool isLeft = true; + private MarkdownEditorManager meditorManager; + + #region defaultCss + + private string _defcss = @" +body,td,th {font-family:""微软雅黑"", Verdana, ""Bitstream Vera Sans"", sans-serif; } +body { + margin-top: 0; + padding: 0; + line-height: 1.5em; + color: #{1}; + background-color: #{0}; + text-align: left; + } +a em { + padding-bottom: 2px; + } + + +sup { + line-height: 0px; + } +sup a:link { + padding: 3px; + } +sup a:visited { + padding: 3px; + } + + +p { + margin: 0 0 1.6em 0; + padding: 0; + } + +h1 { + font-family: ""黑体"",""Gill Sans"", ""Gill Sans Std"", ""Gill Sans MT"", Georgia, serif; + font-size: 1.55em; + line-height: 1.5em; + text-align: left; + font-weight: bold; + margin: 0em 0px 1.25em 0px; + } + +h2 { + font-family:""黑体"", ""Gill Sans"", ""Gill Sans Std"", ""Gill Sans MT"", Verdana, ""Bitstream Vera Sans"", sans-serif; + font-size: 1.1em; /* 1 */ + text-align: left; + font-weight:bold; + line-height: 1.8em; + letter-spacing: .2em; + margin: 1em 0 1em 0; + text-transform: uppercase; + } + +h1 + h2 { + margin-top: 2em; + } +h2 + h3 { + margin-top: 1.5em; + } + +h3 { + font-family: ""黑体"",Gill Sans"", ""Gill Sans Std"", ""Gill Sans MT"", Verdana, ""Bitstream Vera Sans"", sans-serif; + font-size: .91em; + text-align: left; + font-weight: normal; + line-height: 1.8em; + letter-spacing: .2em; + margin-bottom: 0.4em; + margin-top: 0.5em; + text-transform: uppercase; + } + +p + h3 { + margin-top: 4em; + } +pre + h3 { + margin-top: 4em; + } + +h6 + h2 { + margin-top: 2em; + } + +h4, h5, h6 { + font-family: Verdana, ""Bitstream Vera Sans"", sans-serif; + font-size: 1em; + text-align: left; + font-weight: bold; + line-height: 1.5em; + margin: 1em 0 0 0; + } + +strong { + font-weight: bold; + font-size: .91em; + letter-spacing: .2em; + text-transform: uppercase; + } + +em { + font-style: normal; + } +blockquote { + font-size: 1em; + margin: 2em 2em 2em 1em; + padding: 0 .75em 0 1.25em; + border-left: 1px solid #777; + border-right: 0px solid #777; + } + +blockquote strong { + font-weight: bold; + font-size: 1em; + letter-spacing: normal; + text-transform: none; + } + + +img { + margin-top: 5px; + } + +thead { + font-weight: bold; + } + + +ul, ol { + padding-left: 1.25em; + margin: 0 0 2em 1em; + } + + +pre { + font-family: ""Bitstream Vera Sans Mono"", Courier, Monaco, ProFont, ""American Typewriter"", ""Andale Mono"", monospace; + line-height: 1.45em; + color: #{1}; + background-color: inherit; + margin: 0.5em 0 0.5em 0; + padding: 5px 0 5px 10px; + border-width: 1px 0 1px 0; + border-color: #6b6b6b; + border-style: dashed; + } + +code { + font-family: Monaco, ProFont, ""Bitstream Vera Sans Mono"", ""American Typewriter"", ""Andale Mono"", monospace; + font-size: 0.91em; /* 1.09em for Courier */ + } + + +ul { + list-style-type: square; + } + +ul ul { + list-style-type: disc; + } +ul ul ul { + list-style-type: circle; + } + +hr { + height: 1px; + margin: 1em 1em 1em 0; + text-align: center; + border-color: #777; + border-width: 0; + border-style: dotted; + } + +dt { + font-family: Verdana, ""Bitstream Vera Sans"", sans-serif; + font-size: 1em; + text-align: left; + font-weight: normal; + margin: 0 0 .4em 0; + letter-spacing: normal; + text-transform: none; + } +dd { + margin: auto auto 1.5em 1em; + } + +dd p { + margin: 0 0 1em 0; + } + +table{ + border:1px #CCC solid; +border-collapse: separate;border-spacing: 0; +} +th,td{padding:5px;border: 1px solid #CCC;} +"; + + #endregion + + /// + /// Gets a value indicating if the operating system is a Windows Vista or a newer one. + /// + public static bool IsWindowsVistaOrNewer + { + get + { + return (Environment.OSVersion.Platform == PlatformID.Win32NT) && + (Environment.OSVersion.Version.Major >= 6); + } + } + + public void OpenMRUFile(string fileName) + { + openfile(fileName); + } + + public void ReadCss() + { + _font = Settings.Default.font; + _foreColor = Settings.Default.color; + _bgColor = Settings.Default.bgcolor; + _defcss = Settings.Default.css; + _extfileother = Settings.Default.extfile; + + _regexExtOthertext = new Regex(_regexExtOthertext.Replace(".", @"\."), RegexOptions.Compiled); + + meditorManager.SetFont(_font); + meditorManager.SetForeColor(_foreColor); + meditorManager.SetBackColor(_bgColor); + meditorManager.SetCss(_defcss); + + //MessageBox.Show(Settings.Default.appconfig.ToString()); + } + + public void openfiles(string[] fileNames) + { + foreach (string s in fileNames) + openfile(s); + } + + private void openfile(string fileName) + { + if (meditorManager.Open(fileName)) + { + Add(fileName); + } + else + mruManager.Remove(fileName); // when Open File operation failed + } + + public void Add(string fullpath) + { + string dir = Path.GetDirectoryName(fullpath); + if (_monitorList.ContainsKey(dir)) + { + return; + } + _monitorList.Add(dir, true); + _filemonitor.Add(dir, "*.md"); + } + + private void fsw_Changed(object sender, FileSystemEventArgs e) + { + if (InvokeRequired) + { + Invoke(new dirupdated(meditorManager.RefrushOpen), e.Name); + return; + } + meditorManager.RefrushOpen(e.Name); + } + + private void openfile() + { + var fileone = new OpenFileDialog(); + fileone.Filter = myExtName; + fileone.FilterIndex = 1; + if (fileone.ShowDialog() == DialogResult.OK) + { + try + { + openfile(fileone.FileName); + } + catch (Exception ex) + { + MessageBox.Show("出现了错误:" + ex.Message); + mruManager.Remove(fileone.FileName); // when Open File operation failed + } + } + } + + + + private bool filetypeConvert(MarkdownEditor meditor) + { + string marktext = meditor.GetMarkdown(); + if (string.IsNullOrEmpty(marktext)) + { + return false; + } + + string ext = Path.GetExtension(meditor.FileName); + if (_regexExtMarkdowns.IsMatch(ext)) + { + string html = ""; + html = Utils.ConvertTextToHTML(marktext); + rtbHtml.Text = html; + webControl1.LoadHTML(meditorManager.GetHTMLStyle(html)); + return true; + } + + if (_regexExtHtml.IsMatch(ext)) + { + webControl1.LoadHTML(marktext); + rtbHtml.Text = marktext; + return true; + } + + if (_regexExtOthertext.IsMatch(ext)) + { + webControl1.LoadHTML(meditorManager.GetHTMLStyle("
    " + marktext + "
    ")); + rtbHtml.Text = marktext; + return true; + } + return false; + } + + public void SelectForeColor() + { + var color = new ColorDialog(); + if (color.ShowDialog() == DialogResult.OK) + { + _foreColor = color.Color; + meditorManager.SetForeColor(_foreColor); + meditorManager.SetStyle(rtbHtml); + + //Settings.Default.color = _foreColor; + //Settings.Default.Save(); + } + } + + public void SetOldStyle() + { + _bgColor = Color.FromArgb(0xff, 0xff, 0xff); //20,0x20,0x20; + _foreColor = Color.FromArgb(0x00, 0x00, 0x00); //0xf2,0xf0,0xdf + _font = new Font("微软雅黑", 12); + + setstyle(); + //SaveSettings(); + } + + public void SetBlackWhiteStyle() + { + _bgColor = Color.FromArgb(0x4a, 0x52, 0x5a); //20,0x20,0x20; + _foreColor = Color.FromArgb(0xff, 0xff, 0xff); //0xf2,0xf0,0xdf + _font = new Font("微软雅黑", 12); + setstyle(); + //SaveSettings(); + } + + private void setstyle() + { + meditorManager.SetFont(_font); + meditorManager.SetForeColor(_foreColor); + meditorManager.SetBackColor(_bgColor); + + meditorManager.SetStyle(rtbHtml); + } + + private string convertColor(Color co) + { + return co.R.ToString() + "," + co.G.ToString() + "," + co.B.ToString(); + } + + public void SaveSettings() + { + string appconfig = Settings.Default.appconfig; + + appconfig = appconfig.Replace("{font}", _font.ToString()); + appconfig = appconfig.Replace("{color}", convertColor(_foreColor)); + appconfig = appconfig.Replace("{bgcolor}", convertColor(_bgColor)); + appconfig = appconfig.Replace("{css}", _defcss); + appconfig = appconfig.Replace("{extfile}", _extfileother); + + string conffile = Application.UserAppDataPath; + conffile = Application.ExecutablePath + ".config"; + using (var sw = new StreamWriter(conffile, false, Encoding.UTF8)) + { + sw.Write(appconfig); + sw.Close(); + } + } + + public void SelectBackColor() + { + var color = new ColorDialog(); + if (color.ShowDialog() == DialogResult.OK) + { + _bgColor = color.Color; + meditorManager.SetBackColor(_bgColor); + meditorManager.SetStyle(rtbHtml); + + //Settings.Default.bgcolor = _bgColor; + //Settings.Default.Save(); + } + } + + public void SelectFont() + { + var font = new FontDialog(); + if (font.ShowDialog() == DialogResult.OK) + { + _font = font.Font; + meditorManager.SetFont(_font); + meditorManager.SetStyle(rtbHtml); + + //Settings.Default.font =_font; + //Settings.Default.Save(); + } + } + + public void SetCss(string css) + { + _defcss = css; + meditorManager.SetCss(_defcss); + + } + + public void SetExt(string ext) + { + _extfileother = ext; + _regexExtOthertext = new Regex(_extfileother.Replace(".", @"\."), RegexOptions.Compiled); + } + + private void editCss() + { + var fcss = new frmCss(_defcss, this); + fcss.ShowDialog(); + } + + private void showSyntax(string url) + { + toolStripStatusLabel1.Text = "正在打开" + url + "..."; + Process.Start(url); + //webBrowser1.Navigate(url); + //webBrowser1.DocumentText = html; + + if (splitContainer1.Panel2Collapsed) + splitContainer1.Panel2Collapsed = false; + } + + private void SwithFlaout() + { + if (isLeft) + { + splitContainer1.Panel2.Controls.Add(tabControl1); + splitContainer1.Panel1.Controls.Add(tabControl2); + if (splitContainer1.Panel2Collapsed) + { + splitContainer1.Panel2Collapsed = false; + splitContainer1.Panel1Collapsed = true; + } + isLeft = false; + return; + } + splitContainer1.Panel1.Controls.Add(tabControl1); + splitContainer1.Panel2.Controls.Add(tabControl2); + if (splitContainer1.Panel1Collapsed) + { + splitContainer1.Panel1Collapsed = false; + splitContainer1.Panel2Collapsed = true; + } + isLeft = true; + } + + private void UnRegExtfile() + { + bool rel = FileTypeRegister.UnRegister(_myExtName); + + if (!rel && IsWindowsVistaOrNewer) + { + MessageBox.Show("您是在windows7 下运行的此程序,如果执行完扩展名关联但没有成功,请您以“管理员权限方式再打开此程序再关联一次”!"); + } + } + + private void regExtFile() + { + Assembly asm = Assembly.GetExecutingAssembly(); + string resourceName = "MEditor.logo.ico"; + Stream stream = asm.GetManifestResourceStream(resourceName); + string icofile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + + "\\markdown.ico"; + var fs = new FileStream(icofile, FileMode.Create, FileAccess.Write); + var bs = new byte[stream.Length]; + stream.Read(bs, 0, (int)stream.Length); + fs.Write(bs, 0, bs.Length); + fs.Flush(); + fs.Close(); + fs.Dispose(); + + //注册关联的文件扩展名 + var fr = new FileTypeRegInfo(); + fr.Description = "markdown文档格式"; + fr.ExePath = Application.ExecutablePath; + fr.ExtendName = _myExtName; + fr.IcoPath = icofile; + + bool rel = true; + if (FileTypeRegister.CheckIfRegistered(fr.ExtendName)) + { + rel = FileTypeRegister.UpdateRegInfo(fr); + } + else + { + rel = FileTypeRegister.Register(fr); + } + + if (!rel && IsWindowsVistaOrNewer) + { + MessageBox.Show("您是在windows7 下运行的此程序,如果执行完扩展名关联但没有成功,请您以“管理员权限方式再打开此程序再关联一次”!"); + } + } + + private delegate bool dirupdated(string filename); + } +} \ No newline at end of file diff --git a/frmReplace.cs b/frmReplace.cs index 8864e1f..8343f8f 100644 --- a/frmReplace.cs +++ b/frmReplace.cs @@ -1,22 +1,18 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; -using System.Windows.Forms; -using System.IO; using System.Text.RegularExpressions; +using System.Windows.Forms; namespace MEditor { - [System.ComponentModel.DesignerCategory("form")] - public partial class frmReplace : Form + [DesignerCategory("form")] + public partial class frmReplace : Form { + private readonly bool _isFind; + private readonly RichTextBox dab; public string result; - RichTextBox dab; - private bool _isFind=false; - public frmReplace(RichTextBox da, string txt,bool isFind) + + public frmReplace(RichTextBox da, string txt, bool isFind) { InitializeComponent(); result = da.Rtf; @@ -26,21 +22,20 @@ public frmReplace(RichTextBox da, string txt,bool isFind) _isFind = isFind; } - bool CheckEmp() - { + private bool CheckEmp() + { //If there's no text if (findbox.Text == "") { //MessageBox.Show("请输入需要查找的字符串.", "Empty TextBox", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } - //Otherwise, success! + //Otherwise, success! else return true; - - } + } /// - /// Replace all cases + /// Replace all cases /// private void ReplaceAll(object sender, EventArgs e) { @@ -67,24 +62,24 @@ private void ReplaceAll(object sender, EventArgs e) // then replace it dab.Text = replacedString; MessageBox.Show("替换所有完成. ", Application.ProductName, - MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBoxButtons.OK, MessageBoxIcon.Information); // restore the SelectionStart dab.SelectionStart = selectedPos; } - //If no matches found... - else + //If no matches found... + else { MessageBox.Show(String.Format("不能找到 '{0}'. ", - findbox.Text), - Application.ProductName, MessageBoxButtons.OK, - MessageBoxIcon.Information); + findbox.Text), + Application.ProductName, MessageBoxButtons.OK, + MessageBoxIcon.Information); } dab.Focus(); } } - + private void Replace(object sender, EventArgs e) { //Replace one instance @@ -99,9 +94,9 @@ private void Replace(object sender, EventArgs e) if (matchTemp.Value == dab.SelectedText) dab.SelectedText = repbox.Text; } - } } + private void find() { //Replace one instance @@ -135,7 +130,6 @@ private void find() } catch { - } } } @@ -151,9 +145,8 @@ private Regex GetRegExpression() if (useregex.Checked) { - } - // wild cards checkbox checked + // wild cards checkbox checked else if (usewild.Checked) { // multiple characters wildcard (*) @@ -194,8 +187,7 @@ private void frmReplace_Load(object sender, EventArgs e) private void button1_Click(object sender, EventArgs e) { - this.Close(); + Close(); } - } -} +} \ No newline at end of file diff --git a/lastver.txt b/lastver.txt index e8fadc6..bf9c7f8 100644 --- a/lastver.txt +++ b/lastver.txt @@ -1,4 +1,4 @@ -the last version:[0.9.2.0] +the last version:[1.0.2.0] https://github.com/5d13cn/MEditor/raw/master/exeoutput/MDEditor.exe diff --git a/libs/Awesomium.Core.dll b/libs/Awesomium.Core.dll new file mode 100644 index 0000000..f1e946c Binary files /dev/null and b/libs/Awesomium.Core.dll differ diff --git a/libs/Awesomium.Windows.Controls.dll b/libs/Awesomium.Windows.Controls.dll new file mode 100644 index 0000000..f2049be Binary files /dev/null and b/libs/Awesomium.Windows.Controls.dll differ diff --git a/libs/SundownLib.dll b/libs/SundownLib.dll new file mode 100644 index 0000000..c038e5a Binary files /dev/null and b/libs/SundownLib.dll differ diff --git a/obj/Release/DesignTimeResolveAssemblyReferences.cache b/obj/Release/DesignTimeResolveAssemblyReferences.cache index 36a1d3d..6c0d6ed 100644 Binary files a/obj/Release/DesignTimeResolveAssemblyReferences.cache and b/obj/Release/DesignTimeResolveAssemblyReferences.cache differ diff --git a/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache b/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache index 91397f0..3f0fa0b 100644 Binary files a/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache and b/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/obj/Release/MDEditor.csproj.FileListAbsolute.txt b/obj/Release/MDEditor.csproj.FileListAbsolute.txt index e8418d5..9e58d8d 100644 --- a/obj/Release/MDEditor.csproj.FileListAbsolute.txt +++ b/obj/Release/MDEditor.csproj.FileListAbsolute.txt @@ -35,3 +35,18 @@ D:\GitHub\MEditor\obj\Release\MEditor.frmCss.resources D:\GitHub\MEditor\obj\Release\MEditor.GoToLineDialog.resources D:\GitHub\MEditor\obj\Release\MEditor.frmReplace.resources D:\GitHub\MEditor\obj\Release\MDEditor.csproj.GenerateResource.Cache +G:\GitHub\MEditor\exeoutput\MDEditor.exe.config +G:\GitHub\MEditor\obj\Release\MDEditor.exe +G:\GitHub\MEditor\obj\Release\MDEditor.pdb +G:\GitHub\MEditor\exeoutput\MDEditor.exe +G:\GitHub\MEditor\exeoutput\MDEditor.pdb +G:\GitHub\MEditor\exeoutput\ICSharpCode.AvalonEdit.dll +G:\GitHub\MEditor\obj\Release\MEditor.frmMain.resources +G:\GitHub\MEditor\obj\Release\MEditor.Properties.Resources.resources +G:\GitHub\MEditor\obj\Release\MEditor.frmCss.resources +G:\GitHub\MEditor\obj\Release\MEditor.GoToLineDialog.resources +G:\GitHub\MEditor\obj\Release\MEditor.frmReplace.resources +G:\GitHub\MEditor\obj\Release\MDEditor.csproj.GenerateResource.Cache +G:\GitHub\MEditor\obj\Release\MEditor.TestForm.TestSundown.resources +G:\GitHub\MEditor\exeoutput\libs\SundownLib.dll +G:\GitHub\MEditor\obj\Release\MDEditor.g.resources diff --git a/obj/Release/MDEditor.csproj.GenerateResource.Cache b/obj/Release/MDEditor.csproj.GenerateResource.Cache index e3b6bb1..e10a391 100644 Binary files a/obj/Release/MDEditor.csproj.GenerateResource.Cache and b/obj/Release/MDEditor.csproj.GenerateResource.Cache differ diff --git a/obj/Release/MDEditor.csprojResolveAssemblyReference.cache b/obj/Release/MDEditor.csprojResolveAssemblyReference.cache deleted file mode 100644 index d39003c..0000000 Binary files a/obj/Release/MDEditor.csprojResolveAssemblyReference.cache and /dev/null differ diff --git a/obj/Release/MDEditor.exe b/obj/Release/MDEditor.exe index 64fe337..052ebd4 100644 Binary files a/obj/Release/MDEditor.exe and b/obj/Release/MDEditor.exe differ diff --git a/obj/Release/MDEditor.pdb b/obj/Release/MDEditor.pdb index c50eedc..7315596 100644 Binary files a/obj/Release/MDEditor.pdb and b/obj/Release/MDEditor.pdb differ diff --git a/obj/Release/MEditor.frmMain.resources b/obj/Release/MEditor.frmMain.resources index 29f9a7c..a7f1667 100644 Binary files a/obj/Release/MEditor.frmMain.resources and b/obj/Release/MEditor.frmMain.resources differ diff --git a/template/highlight.pack.js b/template/highlight.pack.js new file mode 100644 index 0000000..191c225 --- /dev/null +++ b/template/highlight.pack.js @@ -0,0 +1 @@ +var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(//gm,">")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("")}while(o!=u.node);r.splice(q,1);while(q'+L[0]+""}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return''+r.value+""}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+=""}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"
    ")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.bash=function(a){var g="true false";var e="if then else elif fi for break continue while in do done echo exit return set declare";var c={cN:"variable",b:"\\$[a-zA-Z0-9_#]+"};var b={cN:"variable",b:"\\${([^}]|\\\\})+}"};var h={cN:"string",b:'"',e:'"',i:"\\n",c:[a.BE,c,b],r:0};var d={cN:"string",b:"'",e:"'",c:[{b:"''"}],r:0};var f={cN:"test_condition",b:"",e:"",c:[h,d,c,b],k:{literal:g},r:0};return{k:{keyword:e,literal:g},c:[{cN:"shebang",b:"(#!\\/bin\\/bash)|(#!\\/bin\\/sh)",r:10},c,b,a.HCM,h,d,a.inherit(f,{b:"\\[ ",e:" \\]",r:0}),a.inherit(f,{b:"\\[\\[ ",e:" \\]\\]"})]}}(hljs);hljs.LANGUAGES.erlang=function(i){var c="[a-z'][a-zA-Z0-9_']*";var o="("+c+":"+c+"|"+c+")";var f={keyword:"after and andalso|10 band begin bnot bor bsl bzr bxor case catch cond div end fun let not of orelse|10 query receive rem try when xor",literal:"false true"};var l={cN:"comment",b:"%",e:"$",r:0};var e={cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0};var g={b:"fun\\s+"+c+"/\\d+"};var n={b:o+"\\(",e:"\\)",rB:true,r:0,c:[{cN:"function_name",b:o,r:0},{b:"\\(",e:"\\)",eW:true,rE:true,r:0}]};var h={cN:"tuple",b:"{",e:"}",r:0};var a={cN:"variable",b:"\\b_([A-Z][A-Za-z0-9_]*)?",r:0};var m={cN:"variable",b:"[A-Z][a-zA-Z0-9_]*",r:0};var b={b:"#",e:"}",i:".",r:0,rB:true,c:[{cN:"record_name",b:"#"+i.UIR,r:0},{b:"{",eW:true,r:0}]};var k={k:f,b:"(fun|receive|if|try|case)",e:"end"};k.c=[l,g,i.inherit(i.ASM,{cN:""}),k,n,i.QSM,e,h,a,m,b];var j=[l,g,k,n,i.QSM,e,h,a,m,b];n.c[1].c=j;h.c=j;b.c[1].c=j;var d={cN:"params",b:"\\(",e:"\\)",c:j};return{k:f,i:"(",rB:true,i:"\\(|#|//|/\\*|\\\\|:",c:[d,{cN:"title",b:c}],starts:{e:";|\\.",k:f,c:j}},l,{cN:"pp",b:"^-",e:"\\.",r:0,eE:true,rB:true,l:"-"+i.IR,k:"-module -record -undef -export -ifdef -ifndef -author -copyright -doc -vsn -import -include -include_lib -compile -define -else -endif -file -behaviour -behavior",c:[d]},e,i.QSM,b,a,m,h]}}(hljs);hljs.LANGUAGES.cs=function(a){return{k:"abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while ascending descending from get group into join let orderby partial select set value var where yield",c:[{cN:"comment",b:"///",e:"$",rB:true,c:[{cN:"xmlDocTag",b:"///|"},{cN:"xmlDocTag",b:""}]},a.CLCM,a.CBLCLM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},a.ASM,a.QSM,a.CNM]}}(hljs);hljs.LANGUAGES.brainfuck=function(a){return{c:[{cN:"comment",b:"[^\\[\\]\\.,\\+\\-<> \r\n]",eE:true,e:"[\\[\\]\\.,\\+\\-<> \r\n]",r:0},{cN:"title",b:"[\\[\\]]",r:0},{cN:"string",b:"[\\.,]"},{cN:"literal",b:"[\\+\\-]"}]}}(hljs);hljs.LANGUAGES.ruby=function(e){var a="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?";var j="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var g={keyword:"and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include"};var c={cN:"yardoctag",b:"@[A-Za-z]+"};var k=[{cN:"comment",b:"#",e:"$",c:[c]},{cN:"comment",b:"^\\=begin",e:"^\\=end",c:[c],r:10},{cN:"comment",b:"^__END__",e:"\\n$"}];var d={cN:"subst",b:"#\\{",e:"}",l:a,k:g};var i=[e.BE,d];var b=[{cN:"string",b:"'",e:"'",c:i,r:0},{cN:"string",b:'"',e:'"',c:i,r:0},{cN:"string",b:"%[qw]?\\(",e:"\\)",c:i},{cN:"string",b:"%[qw]?\\[",e:"\\]",c:i},{cN:"string",b:"%[qw]?{",e:"}",c:i},{cN:"string",b:"%[qw]?<",e:">",c:i,r:10},{cN:"string",b:"%[qw]?/",e:"/",c:i,r:10},{cN:"string",b:"%[qw]?%",e:"%",c:i,r:10},{cN:"string",b:"%[qw]?-",e:"-",c:i,r:10},{cN:"string",b:"%[qw]?\\|",e:"\\|",c:i,r:10}];var h={cN:"function",bWK:true,e:" |$|;",k:"def",c:[{cN:"title",b:j,l:a,k:g},{cN:"params",b:"\\(",e:"\\)",l:a,k:g}].concat(k)};var f=k.concat(b.concat([{cN:"class",bWK:true,e:"$|;",k:"class module",c:[{cN:"title",b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?",r:0},{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]}].concat(k)},h,{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:b.concat([{b:j}]),r:0},{cN:"symbol",b:a+":",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"number",b:"\\?\\w"},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:k.concat([{cN:"regexp",b:"/",e:"/[a-z]*",i:"\\n",c:[e.BE,d]}]),r:0}]));d.c=f;h.c[1].c=f;return{l:a,k:g,c:f}}(hljs);hljs.LANGUAGES.rust=function(b){var d={cN:"title",b:b.UIR};var c={cN:"number",b:"\\b(0[xb][A-Za-z0-9_]+|[0-9_]+(\\.[0-9_]+)?([uif](8|16|32|64)?)?)",r:0};var a="alt any as assert be bind block bool break char check claim const cont dir do else enum export f32 f64 fail false float fn for i16 i32 i64 i8 if iface impl import in int let log mod mutable native note of prove pure resource ret self str syntax true type u16 u32 u64 u8 uint unchecked unsafe use vec while";return{k:a,i:";",sL:"xml"}],r:0},{cN:"function",bWK:true,e:"{",k:"function",c:[{cN:"title",b:"[A-Za-z$_][0-9A-Za-z$_]*"},{cN:"params",b:"\\(",e:"\\)",c:[a.CLCM,a.CBLCLM],i:"[\"'\\(]"}],i:"\\[|%"}]}}(hljs);hljs.LANGUAGES.glsl=function(a){return{k:{keyword:"atomic_uint attribute bool break bvec2 bvec3 bvec4 case centroid coherent const continue default discard dmat2 dmat2x2 dmat2x3 dmat2x4 dmat3 dmat3x2 dmat3x3 dmat3x4 dmat4 dmat4x2 dmat4x3 dmat4x4 do double dvec2 dvec3 dvec4 else flat float for highp if iimage1D iimage1DArray iimage2D iimage2DArray iimage2DMS iimage2DMSArray iimage2DRect iimage3D iimageBuffer iimageCube iimageCubeArray image1D image1DArray image2D image2DArray image2DMS image2DMSArray image2DRect image3D imageBuffer imageCube imageCubeArray in inout int invariant isampler1D isampler1DArray isampler2D isampler2DArray isampler2DMS isampler2DMSArray isampler2DRect isampler3D isamplerBuffer isamplerCube isamplerCubeArray ivec2 ivec3 ivec4 layout lowp mat2 mat2x2 mat2x3 mat2x4 mat3 mat3x2 mat3x3 mat3x4 mat4 mat4x2 mat4x3 mat4x4 mediump noperspective out patch precision readonly restrict return sample sampler1D sampler1DArray sampler1DArrayShadow sampler1DShadow sampler2D sampler2DArray sampler2DArrayShadow sampler2DMS sampler2DMSArray sampler2DRect sampler2DRectShadow sampler2DShadow sampler3D samplerBuffer samplerCube samplerCubeArray samplerCubeArrayShadow samplerCubeShadow smooth struct subroutine switch uimage1D uimage1DArray uimage2D uimage2DArray uimage2DMS uimage2DMSArray uimage2DRect uimage3D uimageBuffer uimageCube uimageCubeArray uint uniform usampler1D usampler1DArray usampler2D usampler2DArray usampler2DMS usampler2DMSArray usampler2DRect usampler3D usamplerBuffer usamplerCube usamplerCubeArray uvec2 uvec3 uvec4 varying vec2 vec3 vec4 void volatile while writeonly",built_in:"gl_BackColor gl_BackLightModelProduct gl_BackLightProduct gl_BackMaterial gl_BackSecondaryColor gl_ClipDistance gl_ClipPlane gl_ClipVertex gl_Color gl_DepthRange gl_EyePlaneQ gl_EyePlaneR gl_EyePlaneS gl_EyePlaneT gl_Fog gl_FogCoord gl_FogFragCoord gl_FragColor gl_FragCoord gl_FragData gl_FragDepth gl_FrontColor gl_FrontFacing gl_FrontLightModelProduct gl_FrontLightProduct gl_FrontMaterial gl_FrontSecondaryColor gl_InstanceID gl_InvocationID gl_Layer gl_LightModel gl_LightSource gl_MaxAtomicCounterBindings gl_MaxAtomicCounterBufferSize gl_MaxClipDistances gl_MaxClipPlanes gl_MaxCombinedAtomicCounterBuffers gl_MaxCombinedAtomicCounters gl_MaxCombinedImageUniforms gl_MaxCombinedImageUnitsAndFragmentOutputs gl_MaxCombinedTextureImageUnits gl_MaxDrawBuffers gl_MaxFragmentAtomicCounterBuffers gl_MaxFragmentAtomicCounters gl_MaxFragmentImageUniforms gl_MaxFragmentInputComponents gl_MaxFragmentUniformComponents gl_MaxFragmentUniformVectors gl_MaxGeometryAtomicCounterBuffers gl_MaxGeometryAtomicCounters gl_MaxGeometryImageUniforms gl_MaxGeometryInputComponents gl_MaxGeometryOutputComponents gl_MaxGeometryOutputVertices gl_MaxGeometryTextureImageUnits gl_MaxGeometryTotalOutputComponents gl_MaxGeometryUniformComponents gl_MaxGeometryVaryingComponents gl_MaxImageSamples gl_MaxImageUnits gl_MaxLights gl_MaxPatchVertices gl_MaxProgramTexelOffset gl_MaxTessControlAtomicCounterBuffers gl_MaxTessControlAtomicCounters gl_MaxTessControlImageUniforms gl_MaxTessControlInputComponents gl_MaxTessControlOutputComponents gl_MaxTessControlTextureImageUnits gl_MaxTessControlTotalOutputComponents gl_MaxTessControlUniformComponents gl_MaxTessEvaluationAtomicCounterBuffers gl_MaxTessEvaluationAtomicCounters gl_MaxTessEvaluationImageUniforms gl_MaxTessEvaluationInputComponents gl_MaxTessEvaluationOutputComponents gl_MaxTessEvaluationTextureImageUnits gl_MaxTessEvaluationUniformComponents gl_MaxTessGenLevel gl_MaxTessPatchComponents gl_MaxTextureCoords gl_MaxTextureImageUnits gl_MaxTextureUnits gl_MaxVaryingComponents gl_MaxVaryingFloats gl_MaxVaryingVectors gl_MaxVertexAtomicCounterBuffers gl_MaxVertexAtomicCounters gl_MaxVertexAttribs gl_MaxVertexImageUniforms gl_MaxVertexOutputComponents gl_MaxVertexTextureImageUnits gl_MaxVertexUniformComponents gl_MaxVertexUniformVectors gl_MaxViewports gl_MinProgramTexelOffsetgl_ModelViewMatrix gl_ModelViewMatrixInverse gl_ModelViewMatrixInverseTranspose gl_ModelViewMatrixTranspose gl_ModelViewProjectionMatrix gl_ModelViewProjectionMatrixInverse gl_ModelViewProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixTranspose gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_Normal gl_NormalMatrix gl_NormalScale gl_ObjectPlaneQ gl_ObjectPlaneR gl_ObjectPlaneS gl_ObjectPlaneT gl_PatchVerticesIn gl_PerVertex gl_Point gl_PointCoord gl_PointSize gl_Position gl_PrimitiveID gl_PrimitiveIDIn gl_ProjectionMatrix gl_ProjectionMatrixInverse gl_ProjectionMatrixInverseTranspose gl_ProjectionMatrixTranspose gl_SampleID gl_SampleMask gl_SampleMaskIn gl_SamplePosition gl_SecondaryColor gl_TessCoord gl_TessLevelInner gl_TessLevelOuter gl_TexCoord gl_TextureEnvColor gl_TextureMatrixInverseTranspose gl_TextureMatrixTranspose gl_Vertex gl_VertexID gl_ViewportIndex gl_in gl_out EmitStreamVertex EmitVertex EndPrimitive EndStreamPrimitive abs acos acosh all any asin asinh atan atanh atomicCounter atomicCounterDecrement atomicCounterIncrement barrier bitCount bitfieldExtract bitfieldInsert bitfieldReverse ceil clamp cos cosh cross dFdx dFdy degrees determinant distance dot equal exp exp2 faceforward findLSB findMSB floatBitsToInt floatBitsToUint floor fma fract frexp ftransform fwidth greaterThan greaterThanEqual imageAtomicAdd imageAtomicAnd imageAtomicCompSwap imageAtomicExchange imageAtomicMax imageAtomicMin imageAtomicOr imageAtomicXor imageLoad imageStore imulExtended intBitsToFloat interpolateAtCentroid interpolateAtOffset interpolateAtSample inverse inversesqrt isinf isnan ldexp length lessThan lessThanEqual log log2 matrixCompMult max memoryBarrier min mix mod modf noise1 noise2 noise3 noise4 normalize not notEqual outerProduct packDouble2x32 packHalf2x16 packSnorm2x16 packSnorm4x8 packUnorm2x16 packUnorm4x8 pow radians reflect refract round roundEven shadow1D shadow1DLod shadow1DProj shadow1DProjLod shadow2D shadow2DLod shadow2DProj shadow2DProjLod sign sin sinh smoothstep sqrt step tan tanh texelFetch texelFetchOffset texture texture1D texture1DLod texture1DProj texture1DProjLod texture2D texture2DLod texture2DProj texture2DProjLod texture3D texture3DLod texture3DProj texture3DProjLod textureCube textureCubeLod textureGather textureGatherOffset textureGatherOffsets textureGrad textureGradOffset textureLod textureLodOffset textureOffset textureProj textureProjGrad textureProjGradOffset textureProjLod textureProjLodOffset textureProjOffset textureQueryLod textureSize transpose trunc uaddCarry uintBitsToFloat umulExtended unpackDouble2x32 unpackHalf2x16 unpackSnorm2x16 unpackSnorm4x8 unpackUnorm2x16 unpackUnorm4x8 usubBorrow gl_TextureMatrix gl_TextureMatrixInverse",literal:"true false"},i:'"',c:[a.CLCM,a.CBLCLM,a.CNM,{cN:"preprocessor",b:"#",e:"$"}]}}(hljs);hljs.LANGUAGES.rsl=function(a){return{k:{keyword:"float color point normal vector matrix while for if do return else break extern continue",built_in:"abs acos ambient area asin atan atmosphere attribute calculatenormal ceil cellnoise clamp comp concat cos degrees depth Deriv diffuse distance Du Dv environment exp faceforward filterstep floor format fresnel incident length lightsource log match max min mod noise normalize ntransform opposite option phong pnoise pow printf ptlined radians random reflect refract renderinfo round setcomp setxcomp setycomp setzcomp shadow sign sin smoothstep specular specularbrdf spline sqrt step tan texture textureinfo trace transform vtransform xcomp ycomp zcomp"},i:"]+"}]}]};return{cI:true,c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"",c:[{cN:"title",b:"[^ />]+"},b]}]}}(hljs);hljs.LANGUAGES.markdown=function(a){return{c:[{cN:"header",b:"^#{1,3}",e:"$"},{cN:"header",b:"^.+?\\n[=-]{2,}$"},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",b:"\\*.+?\\*"},{cN:"emphasis",b:"_.+?_",r:0},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",b:"`.+?`"},{cN:"code",b:"^ ",e:"$",r:0},{cN:"horizontal_rule",b:"^-{3,}",e:"$"},{b:"\\[.+?\\]\\(.+?\\)",rB:true,c:[{cN:"link_label",b:"\\[.+\\]"},{cN:"link_url",b:"\\(",e:"\\)",eB:true,eE:true}]}]}}(hljs);hljs.LANGUAGES.css=function(a){var b={cN:"function",b:a.IR+"\\(",e:"\\)",c:[a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",eE:true,k:"import page media charset",c:[b,a.ASM,a.QSM,a.NM]},{cN:"tag",b:a.IR,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[b,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"\\#[0-9A-F]+"},{cN:"important",b:"!important"}]}}]}]}]}}(hljs);hljs.LANGUAGES.lisp=function(i){var k="[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#]*";var l="(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s)(\\+|\\-)?\\d+)?";var a={cN:"literal",b:"\\b(t{1}|nil)\\b"};var d=[{cN:"number",b:l},{cN:"number",b:"#b[0-1]+(/[0-1]+)?"},{cN:"number",b:"#o[0-7]+(/[0-7]+)?"},{cN:"number",b:"#x[0-9a-f]+(/[0-9a-f]+)?"},{cN:"number",b:"#c\\("+l+" +"+l,e:"\\)"}];var h={cN:"string",b:'"',e:'"',c:[i.BE],r:0};var m={cN:"comment",b:";",e:"$"};var g={cN:"variable",b:"\\*",e:"\\*"};var n={cN:"keyword",b:"[:&]"+k};var b={b:"\\(",e:"\\)",c:["self",a,h].concat(d)};var e={cN:"quoted",b:"['`]\\(",e:"\\)",c:d.concat([h,g,n,b])};var c={cN:"quoted",b:"\\(quote ",e:"\\)",k:{title:"quote"},c:d.concat([h,g,n,b])};var j={cN:"list",b:"\\(",e:"\\)"};var f={cN:"body",eW:true,eE:true};j.c=[{cN:"title",b:k},f];f.c=[e,c,j,a].concat(d).concat([h,m,g,n]);return{i:"[^\\s]",c:d.concat([a,h,m,e,c,j])}}(hljs);hljs.LANGUAGES.profile=function(a){return{c:[a.CNM,{cN:"builtin",b:"{",e:"}$",eB:true,eE:true,c:[a.ASM,a.QSM],r:0},{cN:"filename",b:"[a-zA-Z_][\\da-zA-Z_]+\\.[\\da-zA-Z_]{1,3}",e:":",eE:true},{cN:"header",b:"(ncalls|tottime|cumtime)",e:"$",k:"ncalls tottime|10 cumtime|10 filename",r:10},{cN:"summary",b:"function calls",e:"$",c:[a.CNM],r:10},a.ASM,a.QSM,{cN:"function",b:"\\(",e:"\\)$",c:[{cN:"title",b:a.UIR,r:0}],r:0}]}}(hljs);hljs.LANGUAGES.http=function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}}(hljs);hljs.LANGUAGES.java=function(a){return{k:"false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws",c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",c:[{cN:"javadoctag",b:"@[A-Za-z]+"}],r:10},a.CLCM,a.CBLCLM,a.ASM,a.QSM,{cN:"class",bWK:true,e:"{",k:"class interface",i:":",c:[{bWK:true,k:"extends implements",r:10},{cN:"title",b:a.UIR}]},a.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}}(hljs);hljs.LANGUAGES.php=function(a){var e={cN:"variable",b:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var b=[a.inherit(a.ASM,{i:null}),a.inherit(a.QSM,{i:null}),{cN:"string",b:'b"',e:'"',c:[a.BE]},{cN:"string",b:"b'",e:"'",c:[a.BE]}];var c=[a.BNM,a.CNM];var d={cN:"title",b:a.UIR};return{cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return implements parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception php_user_filter default die require __FUNCTION__ enddeclare final try this switch continue endfor endif declare unset true false namespace trait goto instanceof insteadof __DIR__ __NAMESPACE__ __halt_compiler",c:[a.CLCM,a.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"}]},{cN:"comment",eB:true,b:"__halt_compiler.+?;",eW:true},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[a.BE]},{cN:"preprocessor",b:"<\\?php",r:10},{cN:"preprocessor",b:"\\?>"},e,{cN:"function",bWK:true,e:"{",k:"function",i:"\\$|\\[|%",c:[d,{cN:"params",b:"\\(",e:"\\)",c:["self",e,a.CBLCLM].concat(b).concat(c)}]},{cN:"class",bWK:true,e:"{",k:"class",i:"[:\\(\\$]",c:[{bWK:true,eW:true,k:"extends",c:[d]},d]},{b:"=>"}].concat(b).concat(c)}}(hljs);hljs.LANGUAGES.haskell=function(a){var d={cN:"type",b:"\\b[A-Z][\\w']*",r:0};var c={cN:"container",b:"\\(",e:"\\)",c:[{cN:"type",b:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},{cN:"title",b:"[_a-z][\\w']*"}]};var b={cN:"container",b:"{",e:"}",c:c.c};return{k:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance not as foreign ccall safe unsafe",c:[{cN:"comment",b:"--",e:"$"},{cN:"preprocessor",b:"{-#",e:"#-}"},{cN:"comment",c:["self"],b:"{-",e:"-}"},{cN:"string",b:"\\s+'",e:"'",c:[a.BE],r:0},a.QSM,{cN:"import",b:"\\bimport",e:"$",k:"import qualified as hiding",c:[c],i:"\\W\\.|;"},{cN:"module",b:"\\bmodule",e:"where",k:"module where",c:[c],i:"\\W\\.|;"},{cN:"class",b:"\\b(class|instance)",e:"where",k:"class where instance",c:[d]},{cN:"typedef",b:"\\b(data|(new)?type)",e:"$",k:"data type newtype deriving",c:[d,c,b]},a.CNM,{cN:"shebang",b:"#!\\/usr\\/bin\\/env runhaskell",e:"$"},d,{cN:"title",b:"^[_a-z][\\w']*"}]}}(hljs);hljs.LANGUAGES["1c"]=function(b){var f="[a-zA-Zа-яА-Я][a-zA-Z0-9_а-яА-Я]*";var c="возврат дата для если и или иначе иначеесли исключение конецесли конецпопытки конецпроцедуры конецфункции конеццикла константа не перейти перем перечисление по пока попытка прервать продолжить процедура строка тогда фс функция цикл число экспорт";var e="ansitooem oemtoansi ввестивидсубконто ввестидату ввестизначение ввестиперечисление ввестипериод ввестиплансчетов ввестистроку ввестичисло вопрос восстановитьзначение врег выбранныйплансчетов вызватьисключение датагод датамесяц датачисло добавитьмесяц завершитьработусистемы заголовоксистемы записьжурналарегистрации запуститьприложение зафиксироватьтранзакцию значениевстроку значениевстрокувнутр значениевфайл значениеизстроки значениеизстрокивнутр значениеизфайла имякомпьютера имяпользователя каталогвременныхфайлов каталогиб каталогпользователя каталогпрограммы кодсимв командасистемы конгода конецпериодаби конецрассчитанногопериодаби конецстандартногоинтервала конквартала конмесяца коннедели лев лог лог10 макс максимальноеколичествосубконто мин монопольныйрежим названиеинтерфейса названиенабораправ назначитьвид назначитьсчет найти найтипомеченныенаудаление найтиссылки началопериодаби началостандартногоинтервала начатьтранзакцию начгода начквартала начмесяца начнедели номерднягода номерднянедели номернеделигода нрег обработкаожидания окр описаниеошибки основнойжурналрасчетов основнойплансчетов основнойязык открытьформу открытьформумодально отменитьтранзакцию очиститьокносообщений периодстр полноеимяпользователя получитьвремята получитьдатута получитьдокументта получитьзначенияотбора получитьпозициюта получитьпустоезначение получитьта прав праводоступа предупреждение префиксавтонумерации пустаястрока пустоезначение рабочаядаттьпустоезначение рабочаядата разделительстраниц разделительстрок разм разобратьпозициюдокумента рассчитатьрегистрына рассчитатьрегистрыпо сигнал симв символтабуляции создатьобъект сокрл сокрлп сокрп сообщить состояние сохранитьзначение сред статусвозврата стрдлина стрзаменить стрколичествострок стрполучитьстроку стрчисловхождений сформироватьпозициюдокумента счетпокоду текущаядата текущеевремя типзначения типзначениястр удалитьобъекты установитьтана установитьтапо фиксшаблон формат цел шаблон";var a={cN:"dquote",b:'""'};var d={cN:"string",b:'"',e:'"|$',c:[a],r:0};var g={cN:"string",b:"\\|",e:'"|$',c:[a]};return{cI:true,l:f,k:{keyword:c,built_in:e},c:[b.CLCM,b.NM,d,g,{cN:"function",b:"(процедура|функция)",e:"$",l:f,k:"процедура функция",c:[{cN:"title",b:f},{cN:"tail",eW:true,c:[{cN:"params",b:"\\(",e:"\\)",l:f,k:"знач",c:[d,g]},{cN:"export",b:"экспорт",eW:true,l:f,k:"экспорт",c:[b.CLCM]}]},b.CLCM]},{cN:"preprocessor",b:"#",e:"$"},{cN:"date",b:"'\\d{2}\\.\\d{2}\\.(\\d{2}|\\d{4})'"}]}}(hljs);hljs.LANGUAGES.python=function(a){var f={cN:"prompt",b:"^(>>>|\\.\\.\\.) "};var c=[{cN:"string",b:"(u|b)?r?'''",e:"'''",c:[f],r:10},{cN:"string",b:'(u|b)?r?"""',e:'"""',c:[f],r:10},{cN:"string",b:"(u|r|ur)'",e:"'",c:[a.BE],r:10},{cN:"string",b:'(u|r|ur)"',e:'"',c:[a.BE],r:10},{cN:"string",b:"(b|br)'",e:"'",c:[a.BE]},{cN:"string",b:'(b|br)"',e:'"',c:[a.BE]}].concat([a.ASM,a.QSM]);var e={cN:"title",b:a.UIR};var d={cN:"params",b:"\\(",e:"\\)",c:["self",a.CNM,f].concat(c)};var b={bWK:true,e:":",i:"[${=;\\n]",c:[e,d],r:10};return{k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10",built_in:"None True False Ellipsis NotImplemented"},i:"(|\\?)",c:c.concat([f,a.HCM,a.inherit(b,{cN:"function",k:"def"}),a.inherit(b,{cN:"class",k:"class"}),a.CNM,{cN:"decorator",b:"@",e:"$"},{b:"\\b(print|exec)\\("}])}}(hljs);hljs.LANGUAGES.smalltalk=function(a){var b="[a-z][a-zA-Z0-9_]*";var d={cN:"char",b:"\\$.{1}"};var c={cN:"symbol",b:"#"+a.UIR};return{k:"self super nil true false thisContext",c:[{cN:"comment",b:'"',e:'"',r:0},a.ASM,{cN:"class",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},{cN:"method",b:b+":"},a.CNM,c,d,{cN:"localvars",b:"\\|\\s*(("+b+")\\s*)+\\|"},{cN:"array",b:"\\#\\(",e:"\\)",c:[a.ASM,d,a.CNM,c]}]}}(hljs);hljs.LANGUAGES.tex=function(a){var d={cN:"command",b:"\\\\[a-zA-Zа-яА-я]+[\\*]?"};var c={cN:"command",b:"\\\\[^a-zA-Zа-яА-я0-9]"};var b={cN:"special",b:"[{}\\[\\]\\&#~]",r:0};return{c:[{b:"\\\\[a-zA-Zа-яА-я]+[\\*]? *= *-?\\d*\\.?\\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?",rB:true,c:[d,c,{cN:"number",b:" *=",e:"-?\\d*\\.?\\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?",eB:true}],r:10},d,c,b,{cN:"formula",b:"\\$\\$",e:"\\$\\$",c:[d,c,b],r:0},{cN:"formula",b:"\\$",e:"\\$",c:[d,c,b],r:0},{cN:"comment",b:"%",e:"$",r:0}]}}(hljs);hljs.LANGUAGES.actionscript=function(a){var d="[a-zA-Z_$][a-zA-Z0-9_$]*";var c="([*]|[a-zA-Z_$][a-zA-Z0-9_$]*)";var e={cN:"rest_arg",b:"[.]{3}",e:d,r:10};var b={cN:"title",b:d};return{k:{keyword:"as break case catch class const continue default delete do dynamic each else extends final finally for function get if implements import in include instanceof interface internal is namespace native new override package private protected public return set static super switch this throw try typeof use var void while with",literal:"true false null undefined"},c:[a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{cN:"package",bWK:true,e:"{",k:"package",c:[b]},{cN:"class",bWK:true,e:"{",k:"class interface",c:[{bWK:true,k:"extends implements"},b]},{cN:"preprocessor",bWK:true,e:";",k:"import include"},{cN:"function",bWK:true,e:"[{;]",k:"function",i:"\\S",c:[b,{cN:"params",b:"\\(",e:"\\)",c:[a.ASM,a.QSM,a.CLCM,a.CBLCLM,e]},{cN:"type",b:":",e:c,r:10}]}]}}(hljs);hljs.LANGUAGES.sql=function(a){return{cI:true,c:[{cN:"operator",b:"(begin|start|commit|rollback|savepoint|lock|alter|create|drop|rename|call|delete|do|handler|insert|load|replace|select|truncate|update|set|show|pragma|grant)\\b(?!:)",e:";",eW:true,k:{keyword:"all partial global month current_timestamp using go revoke smallint indicator end-exec disconnect zone with character assertion to add current_user usage input local alter match collate real then rollback get read timestamp session_user not integer bit unique day minute desc insert execute like ilike|2 level decimal drop continue isolation found where constraints domain right national some module transaction relative second connect escape close system_user for deferred section cast current sqlstate allocate intersect deallocate numeric public preserve full goto initially asc no key output collation group by union session both last language constraint column of space foreign deferrable prior connection unknown action commit view or first into float year primary cascaded except restrict set references names table outer open select size are rows from prepare distinct leading create only next inner authorization schema corresponding option declare precision immediate else timezone_minute external varying translation true case exception join hour default double scroll value cursor descriptor values dec fetch procedure delete and false int is describe char as at in varchar null trailing any absolute current_time end grant privileges when cross check write current_date pad begin temporary exec time update catalog user sql date on identity timezone_hour natural whenever interval work order cascade diagnostics nchar having left call do handler load replace truncate start lock show pragma exists number",aggregate:"count sum min max avg"},c:[{cN:"string",b:"'",e:"'",c:[a.BE,{b:"''"}],r:0},{cN:"string",b:'"',e:'"',c:[a.BE,{b:'""'}],r:0},{cN:"string",b:"`",e:"`",c:[a.BE]},a.CNM]},a.CBLCLM,{cN:"comment",b:"--",e:"$"}]}}(hljs);hljs.LANGUAGES.vala=function(a){return{k:{keyword:"char uchar unichar int uint long ulong short ushort int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double bool struct enum string void weak unowned owned async signal static abstract interface override while do for foreach else switch case break default return try catch public private protected internal using new this get set const stdout stdin stderr var",built_in:"DBus GLib CCode Gee Object",literal:"false true null"},c:[{cN:"class",bWK:true,e:"{",k:"class interface delegate namespace",c:[{bWK:true,k:"extends implements"},{cN:"title",b:a.UIR}]},a.CLCM,a.CBLCLM,{cN:"string",b:'"""',e:'"""',r:5},a.ASM,a.QSM,a.CNM,{cN:"preprocessor",b:"^#",e:"$",r:2},{cN:"constant",b:" [A-Z_]+ ",r:0}]}}(hljs);hljs.LANGUAGES.ini=function(a){return{cI:true,i:"[^\\s]",c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM]}]}]}}(hljs);hljs.LANGUAGES.d=function(x){var b={keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"};var c="(0|[1-9][\\d_]*)",q="(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)",h="0[bB][01_]+",v="([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)",y="0[xX]"+v,p="([eE][+-]?"+q+")",o="("+q+"(\\.\\d*|"+p+")|\\d+\\."+q+q+"|\\."+c+p+"?)",k="(0[xX]("+v+"\\."+v+"|\\.?"+v+")[pP][+-]?"+q+")",l="("+c+"|"+h+"|"+y+")",n="("+k+"|"+o+")";var z="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};";var m={cN:"number",b:"\\b"+l+"(L|u|U|Lu|LU|uL|UL)?",r:0};var j={cN:"number",b:"\\b("+n+"([fF]|L|i|[fF]i|Li)?|"+l+"(i|[fF]i|Li))",r:0};var s={cN:"string",b:"'("+z+"|.)",e:"'",i:"."};var r={b:z,r:0};var w={cN:"string",b:'"',c:[r],e:'"[cwd]?',r:0};var f={cN:"string",b:'[rq]"',e:'"[cwd]?',r:5};var u={cN:"string",b:"`",e:"`[cwd]?"};var i={cN:"string",b:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',r:10};var t={cN:"string",b:'q"\\{',e:'\\}"'};var e={cN:"shebang",b:"^#!",e:"$",r:5};var g={cN:"preprocessor",b:"#(line)",e:"$",r:5};var d={cN:"keyword",b:"@[a-zA-Z_][a-zA-Z_\\d]*"};var a={cN:"comment",b:"\\/\\+",c:["self"],e:"\\+\\/",r:10};return{l:x.UIR,k:b,c:[x.CLCM,x.CBLCLM,a,i,w,f,u,t,j,m,s,e,g,d]}}(hljs);hljs.LANGUAGES.axapta=function(a){return{k:"false int abstract private char interface boolean static null if for true while long throw finally protected extends final implements return void enum else break new catch byte super class case short default double public try this switch continue reverse firstfast firstonly forupdate nofetch sum avg minof maxof count order group by asc desc index hint like dispaly edit client server ttsbegin ttscommit str real date container anytype common div mod",c:[a.CLCM,a.CBLCLM,a.ASM,a.QSM,a.CNM,{cN:"preprocessor",b:"#",e:"$"},{cN:"class",bWK:true,e:"{",i:":",k:"class interface",c:[{cN:"inheritance",bWK:true,k:"extends implements",r:10},{cN:"title",b:a.UIR}]}]}}(hljs);hljs.LANGUAGES.perl=function(e){var a="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when";var d={cN:"subst",b:"[$@]\\{",e:"\\}",k:a,r:10};var b={cN:"variable",b:"\\$\\d"};var i={cN:"variable",b:"[\\$\\%\\@\\*](\\^\\w\\b|#\\w+(\\:\\:\\w+)*|[^\\s\\w{]|{\\w+}|\\w+(\\:\\:\\w*)*)"};var f=[e.BE,d,b,i];var h={b:"->",c:[{b:e.IR},{b:"{",e:"}"}]};var g={cN:"comment",b:"^(__END__|__DATA__)",e:"\\n$",r:5};var c=[b,i,e.HCM,g,{cN:"comment",b:"^\\=\\w",e:"\\=cut",eW:true},h,{cN:"string",b:"q[qwxr]?\\s*\\(",e:"\\)",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\[",e:"\\]",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\{",e:"\\}",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\|",e:"\\|",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\<",e:"\\>",c:f,r:5},{cN:"string",b:"qw\\s+q",e:"q",c:f,r:5},{cN:"string",b:"'",e:"'",c:[e.BE],r:0},{cN:"string",b:'"',e:'"',c:f,r:0},{cN:"string",b:"`",e:"`",c:[e.BE]},{cN:"string",b:"{\\w+}",r:0},{cN:"string",b:"-?\\w+\\s*\\=\\>",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"("+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,g,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"sub",bWK:true,e:"(\\s*\\(.*?\\))?[;{]",k:"sub",r:5},{cN:"operator",b:"-\\w\\b",r:0}];d.c=c;h.c[1].c=c;return{k:a,c:c}}(hljs);hljs.LANGUAGES.scala=function(a){var c={cN:"annotation",b:"@[A-Za-z]+"};var b={cN:"string",b:'u?r?"""',e:'"""',r:10};return{k:"type yield lazy override def with val var false true sealed abstract private trait object null if for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws",c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",c:[{cN:"javadoctag",b:"@[A-Za-z]+"}],r:10},a.CLCM,a.CBLCLM,a.ASM,a.QSM,b,{cN:"class",b:"((case )?class |object |trait )",e:"({|$)",i:":",k:"case class trait object",c:[{bWK:true,k:"extends with",r:10},{cN:"title",b:a.UIR},{cN:"params",b:"\\(",e:"\\)",c:[a.ASM,a.QSM,b,c]}]},a.CNM,c]}}(hljs);hljs.LANGUAGES.cmake=function(a){return{cI:true,k:"add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_minimum_required cmake_policy configure_file create_test_sourcelist define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile execute_process export find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install link_directories load_cache load_command macro mark_as_advanced message option output_required_files project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_link_libraries try_compile try_run unset variable_watch while build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file",c:[{cN:"envvar",b:"\\${",e:"}"},a.HCM,a.QSM,a.NM]}}(hljs);hljs.LANGUAGES.objectivec=function(a){var b={keyword:"int float while private char catch export sizeof typedef const struct for union unsigned long volatile static protected bool mutable if public do return goto void enum else break extern class asm case short default double throw register explicit signed typename try this switch continue wchar_t inline readonly assign property protocol self synchronized end synthesize id optional required implementation nonatomic interface super unichar finally dynamic IBOutlet IBAction selector strong weak readonly",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"NSString NSDictionary CGRect CGPoint UIButton UILabel UITextView UIWebView MKMapView UISegmentedControl NSObject UITableViewDelegate UITableViewDataSource NSThread UIActivityIndicator UITabbar UIToolBar UIBarButtonItem UIImageView NSAutoreleasePool UITableView BOOL NSInteger CGFloat NSException NSLog NSMutableString NSMutableArray NSMutableDictionary NSURL NSIndexPath CGSize UITableViewCell UIView UIViewController UINavigationBar UINavigationController UITabBarController UIPopoverController UIPopoverControllerDelegate UIImage NSNumber UISearchBar NSFetchedResultsController NSFetchedResultsChangeType UIScrollView UIScrollViewDelegate UIEdgeInsets UIColor UIFont UIApplication NSNotFound NSNotificationCenter NSNotification UILocalNotification NSBundle NSFileManager NSTimeInterval NSDate NSCalendar NSUserDefaults UIWindow NSRange NSArray NSError NSURLRequest NSURLConnection class UIInterfaceOrientation MPMoviePlayerController dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"};return{k:b,i:""}]},{cN:"preprocessor",b:"#",e:"$"},{cN:"class",bWK:true,e:"({|$)",k:"interface class protocol implementation",c:[{cN:"id",b:a.UIR}]},{cN:"variable",b:"\\."+a.UIR}]}}(hljs);hljs.LANGUAGES.avrasm=function(a){return{cI:true,k:{keyword:"adc add adiw and andi asr bclr bld brbc brbs brcc brcs break breq brge brhc brhs brid brie brlo brlt brmi brne brpl brsh brtc brts brvc brvs bset bst call cbi cbr clc clh cli cln clr cls clt clv clz com cp cpc cpi cpse dec eicall eijmp elpm eor fmul fmuls fmulsu icall ijmp in inc jmp ld ldd ldi lds lpm lsl lsr mov movw mul muls mulsu neg nop or ori out pop push rcall ret reti rjmp rol ror sbc sbr sbrc sbrs sec seh sbi sbci sbic sbis sbiw sei sen ser ses set sev sez sleep spm st std sts sub subi swap tst wdr",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 r27 r28 r29 r30 r31 x|0 xh xl y|0 yh yl z|0 zh zl ucsr1c udr1 ucsr1a ucsr1b ubrr1l ubrr1h ucsr0c ubrr0h tccr3c tccr3a tccr3b tcnt3h tcnt3l ocr3ah ocr3al ocr3bh ocr3bl ocr3ch ocr3cl icr3h icr3l etimsk etifr tccr1c ocr1ch ocr1cl twcr twdr twar twsr twbr osccal xmcra xmcrb eicra spmcsr spmcr portg ddrg ping portf ddrf sreg sph spl xdiv rampz eicrb eimsk gimsk gicr eifr gifr timsk tifr mcucr mcucsr tccr0 tcnt0 ocr0 assr tccr1a tccr1b tcnt1h tcnt1l ocr1ah ocr1al ocr1bh ocr1bl icr1h icr1l tccr2 tcnt2 ocr2 ocdr wdtcr sfior eearh eearl eedr eecr porta ddra pina portb ddrb pinb portc ddrc pinc portd ddrd pind spdr spsr spcr udr0 ucsr0a ucsr0b ubrr0l acsr admux adcsr adch adcl porte ddre pine pinf"},c:[a.CBLCLM,{cN:"comment",b:";",e:"$"},a.CNM,a.BNM,{cN:"number",b:"\\b(\\$[a-zA-Z0-9]+|0o[0-7]+)"},a.QSM,{cN:"string",b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"},{cN:"label",b:"^[A-Za-z0-9_.$]+:"},{cN:"preprocessor",b:"#",e:"$"},{cN:"preprocessor",b:"\\.[a-zA-Z]+"},{cN:"localvars",b:"@[0-9]+"}]}}(hljs);hljs.LANGUAGES.vhdl=function(a){return{cI:true,k:{keyword:"abs access after alias all and architecture array assert attribute begin block body buffer bus case component configuration constant context cover disconnect downto default else elsif end entity exit fairness file for force function generate generic group guarded if impure in inertial inout is label library linkage literal loop map mod nand new next nor not null of on open or others out package port postponed procedure process property protected pure range record register reject release rem report restrict restrict_guarantee return rol ror select sequence severity shared signal sla sll sra srl strong subtype then to transport type unaffected units until use variable vmode vprop vunit wait when while with xnor xor",typename:"boolean bit character severity_level integer time delay_length natural positive string bit_vector file_open_kind file_open_status std_ulogic std_ulogic_vector std_logic std_logic_vector unsigned signed boolean_vector integer_vector real_vector time_vector"},i:"{",c:[a.CBLCLM,{cN:"comment",b:"--",e:"$"},a.QSM,a.CNM,{cN:"literal",b:"'(U|X|0|1|Z|W|L|H|-)'",c:[a.BE]},{cN:"attribute",b:"'[A-Za-z](_?[A-Za-z0-9])*",c:[a.BE]}]}}(hljs);hljs.LANGUAGES.coffeescript=function(c){var b={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off ",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf"};var a="[A-Za-z$_][0-9A-Za-z$_]*";var e={cN:"title",b:a};var d={cN:"subst",b:"#\\{",e:"}",k:b,c:[c.BNM,c.CNM]};return{k:b,c:[c.BNM,c.CNM,c.ASM,{cN:"string",b:'"""',e:'"""',c:[c.BE,d]},{cN:"string",b:'"',e:'"',c:[c.BE,d],r:0},{cN:"comment",b:"###",e:"###"},c.HCM,{cN:"regexp",b:"///",e:"///",c:[c.HCM]},{cN:"regexp",b:"//[gim]*"},{cN:"regexp",b:"/\\S(\\\\.|[^\\n])*/[gim]*"},{b:"`",e:"`",eB:true,eE:true,sL:"javascript"},{cN:"function",b:a+"\\s*=\\s*(\\(.+\\))?\\s*[-=]>",rB:true,c:[e,{cN:"params",b:"\\(",e:"\\)"}]},{cN:"class",bWK:true,k:"class",e:"$",i:":",c:[{bWK:true,k:"extends",eW:true,i:":",c:[e]},e]},{cN:"property",b:"@"+a}]}}(hljs);hljs.LANGUAGES.nginx=function(b){var c=[{cN:"variable",b:"\\$\\d+"},{cN:"variable",b:"\\${",e:"}"},{cN:"variable",b:"[\\$\\@]"+b.UIR}];var a={eW:true,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[b.HCM,{cN:"string",b:'"',e:'"',c:[b.BE].concat(c),r:0},{cN:"string",b:"'",e:"'",c:[b.BE].concat(c),r:0},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:true,eE:true},{cN:"regexp",b:"\\s\\^",e:"\\s|{|;",rE:true,c:[b.BE].concat(c)},{cN:"regexp",b:"~\\*?\\s+",e:"\\s|{|;",rE:true,c:[b.BE].concat(c)},{cN:"regexp",b:"\\*(\\.[a-z\\-]+)+",c:[b.BE].concat(c)},{cN:"regexp",b:"([a-z\\-]+\\.)+\\*",c:[b.BE].concat(c)},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0}].concat(c)};return{c:[b.HCM,{b:b.UIR+"\\s",e:";|{",rB:true,c:[{cN:"title",b:b.UIR,starts:a}]}],i:"[^\\s\\}]"}}(hljs);hljs.LANGUAGES["erlang-repl"]=function(a){return{k:{special_functions:"spawn spawn_link self",reserved:"after and andalso|10 band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse|10 query receive rem try when xor"},c:[{cN:"prompt",b:"^[0-9]+> ",r:10},{cN:"comment",b:"%",e:"$"},{cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},a.ASM,a.QSM,{cN:"constant",b:"\\?(::)?([A-Z]\\w*(::)?)+"},{cN:"arrow",b:"->"},{cN:"ok",b:"ok"},{cN:"exclamation_mark",b:"!"},{cN:"function_or_atom",b:"(\\b[a-z'][a-zA-Z0-9_']*:[a-z'][a-zA-Z0-9_']*)|(\\b[a-z'][a-zA-Z0-9_']*)",r:0},{cN:"variable",b:"[A-Z][a-zA-Z0-9_']*",r:0}]}}(hljs);hljs.LANGUAGES.r=function(a){var b="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{c:[a.HCM,{b:b,l:b,k:{keyword:"function if in break next repeat else for return switch while try tryCatch|10 stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...|10",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{b:"`",e:"`",r:0},{cN:"string",b:'"',e:'"',c:[a.BE],r:0},{cN:"string",b:"'",e:"'",c:[a.BE],r:0}]}}(hljs);hljs.LANGUAGES.json=function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}(hljs);hljs.LANGUAGES.django=function(c){function e(h,g){return(g==undefined||(!h.cN&&g.cN=="tag")||h.cN=="value")}function f(l,k){var g={};for(var j in l){if(j!="contains"){g[j]=l[j]}var m=[];for(var h=0;l.c&&h"},a.QSM]}}(hljs);hljs.LANGUAGES.applescript=function(a){var b=a.inherit(a.QSM,{i:""});var e={cN:"title",b:a.UIR};var d={cN:"params",b:"\\(",e:"\\)",c:["self",a.CNM,b]};var c=[{cN:"comment",b:"--",e:"$",},{cN:"comment",b:"\\(\\*",e:"\\*\\)",c:["self",{b:"--",e:"$"}]},a.HCM];return{k:{keyword:"about above after against and around as at back before beginning behind below beneath beside between but by considering contain contains continue copy div does eighth else end equal equals error every exit fifth first for fourth from front get given global if ignoring in into is it its last local me middle mod my ninth not of on onto or over prop property put ref reference repeat returning script second set seventh since sixth some tell tenth that the then third through thru timeout times to transaction try until where while whose with without",constant:"AppleScript false linefeed return pi quote result space tab true",type:"alias application boolean class constant date file integer list number real record string text",command:"activate beep count delay launch log offset read round run say summarize write",property:"character characters contents day frontmost id item length month name paragraph paragraphs rest reverse running time version weekday word words year"},c:[b,a.CNM,{cN:"type",b:"\\bPOSIX file\\b"},{cN:"command",b:"\\b(clipboard info|the clipboard|info for|list (disks|folder)|mount volume|path to|(close|open for) access|(get|set) eof|current date|do shell script|get volume settings|random number|set volume|system attribute|system info|time to GMT|(load|run|store) script|scripting components|ASCII (character|number)|localized string|choose (application|color|file|file name|folder|from list|remote application|URL)|display (alert|dialog))\\b|^\\s*return\\b"},{cN:"constant",b:"\\b(text item delimiters|current application|missing value)\\b"},{cN:"keyword",b:"\\b(apart from|aside from|instead of|out of|greater than|isn't|(doesn't|does not) (equal|come before|come after|contain)|(greater|less) than( or equal)?|(starts?|ends|begins?) with|contained by|comes (before|after)|a (ref|reference))\\b"},{cN:"property",b:"\\b(POSIX path|(date|time) string|quoted form)\\b"},{cN:"function_start",bWK:true,k:"on",i:"[${=;\\n]",c:[e,d]}].concat(c)}}(hljs);hljs.LANGUAGES.cpp=function(a){var b={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long throw volatile static protected bool template mutable if public friend do return goto auto void enum else break new extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr"};return{k:b,i:"",k:b,r:10,c:["self"]}]}}(hljs);hljs.LANGUAGES.matlab=function(a){var b=[a.CNM,{cN:"string",b:"'",e:"'",c:[a.BE,{b:"''"}],r:0}];return{k:{keyword:"break case catch classdef continue else elseif end enumerated events for function global if methods otherwise parfor persistent properties return spmd switch try while",built_in:"sin sind sinh asin asind asinh cos cosd cosh acos acosd acosh tan tand tanh atan atand atan2 atanh sec secd sech asec asecd asech csc cscd csch acsc acscd acsch cot cotd coth acot acotd acoth hypot exp expm1 log log1p log10 log2 pow2 realpow reallog realsqrt sqrt nthroot nextpow2 abs angle complex conj imag real unwrap isreal cplxpair fix floor ceil round mod rem sign airy besselj bessely besselh besseli besselk beta betainc betaln ellipj ellipke erf erfc erfcx erfinv expint gamma gammainc gammaln psi legendre cross dot factor isprime primes gcd lcm rat rats perms nchoosek factorial cart2sph cart2pol pol2cart sph2cart hsv2rgb rgb2hsv zeros ones eye repmat rand randn linspace logspace freqspace meshgrid accumarray size length ndims numel disp isempty isequal isequalwithequalnans cat reshape diag blkdiag tril triu fliplr flipud flipdim rot90 find sub2ind ind2sub bsxfun ndgrid permute ipermute shiftdim circshift squeeze isscalar isvector ans eps realmax realmin pi i inf nan isnan isinf isfinite j why compan gallery hadamard hankel hilb invhilb magic pascal rosser toeplitz vander wilkinson"},i:'(//|"|#|/\\*|\\s+/\\w+)',c:[{cN:"function",bWK:true,e:"$",k:"function",c:[{cN:"title",b:a.UIR},{cN:"params",b:"\\(",e:"\\)"},{cN:"params",b:"\\[",e:"\\]"}]},{cN:"transposed_variable",b:"[a-zA-Z_][a-zA-Z_0-9]*('+[\\.']*|[\\.']+)",e:""},{cN:"matrix",b:"\\[",e:"\\]'*[\\.']*",c:b},{cN:"cell",b:"\\{",e:"\\}'*[\\.']*",c:b},{cN:"comment",b:"\\%",e:"$"}].concat(b)}}(hljs);hljs.LANGUAGES.parser3=function(a){return{sL:"xml",c:[{cN:"comment",b:"^#",e:"$"},{cN:"comment",b:"\\^rem{",e:"}",r:10,c:[{b:"{",e:"}",c:["self"]}]},{cN:"preprocessor",b:"^@(?:BASE|USE|CLASS|OPTIONS)$",r:10},{cN:"title",b:"@[\\w\\-]+\\[[\\w^;\\-]*\\](?:\\[[\\w^;\\-]*\\])?(?:.*)$"},{cN:"variable",b:"\\$\\{?[\\w\\-\\.\\:]+\\}?"},{cN:"keyword",b:"\\^[\\w\\-\\.\\:]+"},{cN:"number",b:"\\^#[0-9a-fA-F]+"},a.CNM]}}(hljs);hljs.LANGUAGES.clojure=function(l){var e={built_in:"def cond apply if-not if-let if not not= = < < > <= <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for doseq dosync dotimes and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import intern refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! import use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if throw printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time ns assert re-find re-groups rand-int rand mod locking assert-valid-fdecl alias namespace resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! memfn to-array future future-call into-array aset gen-class reduce merge map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"};var f="[a-zA-Z_0-9\\!\\.\\?\\-\\+\\*\\/\\<\\=\\>\\&\\#\\$';]+";var a="[\\s:\\(\\{]+\\d+(\\.\\d+)?";var d={cN:"number",b:a,r:0};var j={cN:"string",b:'"',e:'"',c:[l.BE],r:0};var o={cN:"comment",b:";",e:"$",r:0};var n={cN:"collection",b:"[\\[\\{]",e:"[\\]\\}]"};var c={cN:"comment",b:"\\^"+f};var b={cN:"comment",b:"\\^\\{",e:"\\}"};var h={cN:"attribute",b:"[:]"+f};var m={cN:"list",b:"\\(",e:"\\)",r:0};var g={eW:true,eE:true,k:{literal:"true false nil"},r:0};var i={k:e,l:f,cN:"title",b:f,starts:g};m.c=[{cN:"comment",b:"comment"},i];g.c=[m,j,c,b,o,h,n,d];n.c=[m,j,c,o,h,n,d];return{i:"\\S",c:[o,m]}}(hljs);hljs.LANGUAGES.go=function(a){var b={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer",constant:"true false iota nil",typename:"bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{k:b,i:")[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=at(),k=at(),N=at(),E=!1,S=function(){return 0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],H=L.pop,q=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){q.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=vt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+xt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return St(e.replace(z,"$1"),t,r,i)}function st(e){return Q.test(e+"")}function at(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function ut(e){return e[v]=!0,e}function lt(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t,n){e=e.split("|");var r,o=e.length,s=n?null:t;while(o--)(r=i.attrHandle[e[o]])&&r!==t||(i.attrHandle[e[o]]=s)}function pt(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function ft(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function ht(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:undefined}function dt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function gt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function mt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function yt(e){return ut(function(t){return t=+t,ut(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.parentWindow;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.frameElement&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=lt(function(e){return e.innerHTML="",ct("type|href|height|width",ft,"#"===e.firstChild.getAttribute("href")),ct(R,pt,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),n.input=lt(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),ct("value",ht,n.attributes&&n.input),n.getElementsByTagName=lt(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=lt(function(e){return e.innerHTML="
    ",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=lt(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=st(t.querySelectorAll))&&(lt(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),lt(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=st(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&<(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=st(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},n.sortDetached=lt(function(e){return 1&e.compareDocumentPosition(t.createElement("div"))}),S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return dt(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?dt(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:ut,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=vt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ut(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ut(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?ut(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ut(function(e){return function(t){return ot(e,t).length>0}}),contains:ut(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ut(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:yt(function(){return[0]}),last:yt(function(e,t){return[t-1]}),eq:yt(function(e,t,n){return[0>n?n+t:n]}),even:yt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:yt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:yt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:yt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=gt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=mt(t);function vt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function xt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function bt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function wt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Tt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function Ct(e,t,n,r,i,o){return r&&!r[v]&&(r=Ct(r)),i&&!i[v]&&(i=Ct(i,o)),ut(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Et(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:Tt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=Tt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=Tt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function kt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=bt(function(e){return e===t},a,!0),p=bt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[bt(wt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return Ct(l>1&&wt(f),l>1&&xt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&kt(e.slice(l,r)),o>r&&kt(e=e.slice(r)),o>r&&xt(e))}f.push(n)}return wt(f)}function Nt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=H.call(f));y=Tt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?ut(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=vt(e)),n=t.length;while(n--)o=kt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Nt(i,r))}return o};function Et(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function St(e,t,r,o){var s,u,l,c,p,f=vt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&xt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}i.pseudos.nth=i.pseudos.eq;function jt(){}jt.prototype=i.filters=i.pseudos,i.setFilters=new jt,n.sortStable=v.split("").sort(S).join("")===v,c(),[0,0].sort(S),n.detectDuplicates=E,x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!a||n&&!u||(r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,H,q=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){return t===undefined||t&&"string"==typeof t&&n===undefined?this.get(e,t):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,H=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||H.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return H.access(e,t,n)},_removeData:function(e,t){H.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!H.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));H.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:q.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=H.get(e,t),n&&(!r||x.isArray(n)?r=H.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire() +},_queueHooks:function(e,t){var n=t+"queueHooks";return H.get(e,n)||H.access(e,n,{empty:x.Callbacks("once memory").add(function(){H.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=H.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,i="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,s=0,a=x(this),u=t,l=e.match(w)||[];while(o=l[s++])u=i?u:!a.hasClass(o),a[u?"addClass":"removeClass"](o)}else(n===r||"boolean"===n)&&(this.className&&H.set(this,"__className__",this.className),this.className=this.className||e===!1?"":H.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=H.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=H.hasData(e)&&H.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,H.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(H.get(a,"events")||{})[t.type]&&H.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(H.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*\s*$/g,ct={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!H.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1>")+a[2],l=a[0];while(l--)o=o.firstChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[H.expando],o&&(t=H.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);H.cache[o]&&delete H.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)H.set(e[r],"globalEval",!t||H.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(H.hasData(e)&&(o=H.access(e),s=H.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function Ht(t){return e.getComputedStyle(t,null)}function qt(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=H.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=H.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&H.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=Ht(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return qt(this,!0)},hide:function(){return qt(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:Lt(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||Ht(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Ht(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("