一年前我写了一个word2010的代码高亮插件,但当时那个版本有一个问题:在用word发布博客的时候,高亮的代码在博客中的格式乱了。今天有空改了一下这个插件,虽然还是有些瑕疵,但至少发布到博客后,格式不会乱了。主要改进是用ol和li代替了pre,虽然发布到博客后,ol中设置的style和class依然会被改动,但可以在博客中用css来纠正。
下载插件和源代码:SyntaxHighlighter4Word.zip
下面说一下这个插件的用法。
下载文件后,解压,然后双击binword2010Kong.SyntaxHighlighter.Word2010.vsto或binword2007Kong.SyntaxHighlighter.Word2007.vsto,即可完成安装,当然前提是你装了.net framework 4.0。安装成功后的提示如下:
安装插件后,会在word中多一个功能区(支持word2007和word2010):
点击"设置"按钮,弹出设置界面:
这里简化了配置,去掉了前一个版本中的一些设置。
点击"插入代码"按钮,弹出如下界面:
可以选择C#、Java、Xml、Javascript等多种语言。
在word效果如下:
发布到博客后的效果如下:
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Text;
-
using System.Windows.Forms;
-
using Kong.SyntaxHighlighter.Winform;
-
using Microsoft.Office.Tools.Ribbon;
-
-
namespace Kong.SyntaxHighlighter.Word
-
{
-
public partial class Ribbon1
-
{
-
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
-
{
-
-
}
-
}
-
}
我在Word中生成这段代码的时候,用了ol和li,并且设置了ol以及li的style,这样在word中就可以显示边框以及交替行的颜色,同时给ol设了一个class=codeBlock,妄想在发布到博客后可以通过这个样式名codeBlock来自定义自己喜欢的样式。我在word中生成的代码大概是这个样子:
-
<ol class="codeBlock" ...
但是word把这段代码发布到博客后,会去除掉这个class,无语。。。
所以我们在博客中,不得设置所有ol的style,幸好博客园的文章都是在一个id为cnblogs_post_body的div下的,所以我在我博客中加了下面的style:
-
#cnblogs_post_body ol
-
{
-
border: 1px dotted #000066;
-
line-height: 150%;
-
word-break: break-word;
-
font-family: Consolas, Verdana !important;
-
border-radius: 5px;
-
width: 90%;
-
background-color: #E3E3FF;
-
list-style-position: outside;
-
margin-left: 0px;
-
}
-
#cnblogs_post_body ol font
-
{
-
font-size: 12px !important;
-
}
-
#cnblogs_post_body ol li
-
{
-
background-color: #fff;
-
padding-left: 5px;
-
border-left: 1px solid #8A8AFF;
-
margin-left: 5px !important;
-
}
-
#cnblogs_post_body ol li:nth-child(even)
-
{
-
background-color: #f5f5f5;
-
}
补充一下,这段文本是加在这里的:
插件的使用就介绍到这里,下面简单介绍一下插件的实现。
如何开发office的add in,园子里已经有很多文章了,我就不介绍了,因为我自己也不懂。
如何实现代码高亮?我用的是Wilco.SyntaxHighlighting,有兴趣的同学可以google一下,我提供的下载包里也有它的源码。
代码高亮后,如何粘帖到word里?原理就是把代码高亮后的文本以html格式复制到剪贴板里,然后调用word的方法去粘帖:
-
private void InsertButton_Click(object sender, RibbonControlEventArgs e)
-
{
-
var dialog = new MainForm();
-
if (dialog.ShowDialog() == DialogResult.OK)
-
{
-
dialog.CopyToClipboard();
-
Globals.ThisAddIn.Application.Selection.Paste();
-
}
-
}
以html格式复制到剪贴板的实现,我是从网上找了一段代码来做的,核心逻辑如下:
-
public static void CopyToClipboard(string htmlFragment, string title, Uri sourceUrl)
-
{
-
if (title == null) title = "From Clipboard";
-
-
System.Text.StringBuilder sb = new System.Text.StringBuilder();
-
-
string header =
-
@"Format:HTML Format
-
Version:1.0
-
StartHTML:<<<<<<<1
-
EndHTML:<<<<<<<2
-
StartFragment:<<<<<<<3
-
EndFragment:<<<<<<<4
-
StartSelection:<<<<<<<3
-
EndSelection:<<<<<<<3
-
";
-
-
string pre =
-
@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">
-
<HTML><HEAD><TITLE>" + title + @"</TITLE></HEAD><BODY><!--StartFragment-->";
-
-
string post = @"<!--EndFragment--></BODY></HTML>";
-
-
sb.Append(header);
-
if (sourceUrl != null)
-
{
-
sb.AppendFormat("SourceURL:{0}", sourceUrl);
-
}
-
var enc = Encoding.UTF8; //中文乱码问题
-
int startHTML = enc.GetByteCount(sb.ToString());
-
-
sb.Append(pre);
-
int fragmentStart = enc.GetByteCount(sb.ToString());
-
-
sb.Append(htmlFragment);
-
int fragmentEnd = enc.GetByteCount(sb.ToString());
-
-
sb.Append(post);
-
int endHTML = enc.GetByteCount(sb.ToString());
-
-
// Backpatch offsets
-
sb.Replace("<<<<<<<1", To8DigitString(startHTML));
-
sb.Replace("<<<<<<<2", To8DigitString(endHTML));
-
sb.Replace("<<<<<<<3", To8DigitString(fragmentStart));
-
sb.Replace("<<<<<<<4", To8DigitString(fragmentEnd));
-
-
Clipboard.Clear();
-
var dataObj = new DataObject();
-
dataObj.SetData(DataFormats.Html, new MemoryStream(enc.GetBytes(sb.ToString())));
-
Clipboard.SetDataObject(dataObj, true);
-
}
-
-
#endregion // Write to Clipboard
-
}
这个类名叫做HtmlFragment,可以在我提供的下载包里找到。
另外,我这个插件在生成高亮代码时,可以清除掉代码段首尾的空行,也可以清除掉每一行的公共空格,比如下面的代码:
在插入后会变成这个样子:
-
private void Test()
-
{
-
var i = 0;
-
//do something
-
}
我用了几条正则表达式来实现这个功能,代码如下:
-
private string GetHtml(string content)
-
{
-
_highlighter.Parser = _htmlParser;
-
string html = _highlighter.Parse(content);
-
_highlighter.Parser = _parser;
-
if (html != null)
-
{
-
html = html.Replace(" ", " ");
-
//清除首尾空行
-
html = Regex.Replace(html, @"(^s* )|( s*$)", "", RegexOptions.Singleline);
-
-
//清除掉公共的空格
-
MatchCollection matches = Regex.Matches(html, @"^ *(?=S)", RegexOptions.Multiline);
-
int len = matches.OfType<Match>().Select(m => m.Value.Length).Min();
-
html = Regex.Replace(html, @"^ {" + len + "}", "", RegexOptions.Multiline);
-
-
//把每一行开头的空格变成
-
html = Regex.Replace(html, @"^ +(?=S)",
-
new MatchEvaluator(
-
m => string.Join("", new string[m.Length].Select(s => " "))),
-
RegexOptions.Multiline);
-
}
-
return html;
-
}
有兴趣的同学可以下载源码看一下。
作者:明年我18
出处:http://www.cnblogs.com/default
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。