专栏首页明年我18Word中使用代码高亮插件

Word中使用代码高亮插件

一年前我写了一个word2010的代码高亮插件,但当时那个版本有一个问题:在用word发布博客的时候,高亮的代码在博客中的格式乱了。今天有空改了一下这个插件,虽然还是有些瑕疵,但至少发布到博客后,格式不会乱了。主要改进是用ol和li代替了pre,虽然发布到博客后,ol中设置的style和class依然会被改动,但可以在博客中用css来纠正。

下载插件和源代码:SyntaxHighlighter4Word.zip

下面说一下这个插件的用法。

下载文件后,解压,然后双击bin\word2010\Kong.SyntaxHighlighter.Word2010.vsto或bin\word2007\Kong.SyntaxHighlighter.Word2007.vsto,即可完成安装,当然前提是你装了.net framework 4.0。安装成功后的提示如下:

安装插件后,会在word中多一个功能区(支持word2007和word2010):

点击"设置"按钮,弹出设置界面:

这里简化了配置,去掉了前一个版本中的一些设置。

点击"插入代码"按钮,弹出如下界面:

可以选择C#、Java、Xml、Javascript等多种语言。

在word效果如下:

发布到博客后的效果如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Forms;
  6. using Kong.SyntaxHighlighter.Winform;
  7. using Microsoft.Office.Tools.Ribbon;
  8. namespace Kong.SyntaxHighlighter.Word
  9. {
  10. public partial class Ribbon1
  11. {
  12. private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
  13. {
  14. }
  15. }
  16. }

我在Word中生成这段代码的时候,用了ol和li,并且设置了ol以及li的style,这样在word中就可以显示边框以及交替行的颜色,同时给ol设了一个class=codeBlock,妄想在发布到博客后可以通过这个样式名codeBlock来自定义自己喜欢的样式。我在word中生成的代码大概是这个样子:

  1. <ol class="codeBlock" ...

但是word把这段代码发布到博客后,会去除掉这个class,无语。。。

所以我们在博客中,不得设置所有ol的style,幸好博客园的文章都是在一个id为cnblogs_post_body的div下的,所以我在我博客中加了下面的style:

  1. #cnblogs_post_body ol
  2. {
  3. border: 1px dotted #000066;
  4. line-height: 150%;
  5. word-break: break-word;
  6. font-family: Consolas, Verdana !important;
  7. border-radius: 5px;
  8. width: 90%;
  9. background-color: #E3E3FF;
  10. list-style-position: outside;
  11. margin-left: 0px;
  12. }
  13. #cnblogs_post_body ol font
  14. {
  15. font-size: 12px !important;
  16. }
  17. #cnblogs_post_body ol li
  18. {
  19. background-color: #fff;
  20. padding-left: 5px;
  21. border-left: 1px solid #8A8AFF;
  22. margin-left: 5px !important;
  23. }
  24. #cnblogs_post_body ol li:nth-child(even)
  25. {
  26. background-color: #f5f5f5;
  27. }

补充一下,这段文本是加在这里的:

插件的使用就介绍到这里,下面简单介绍一下插件的实现。

如何开发office的add in,园子里已经有很多文章了,我就不介绍了,因为我自己也不懂。

如何实现代码高亮?我用的是Wilco.SyntaxHighlighting,有兴趣的同学可以google一下,我提供的下载包里也有它的源码。

代码高亮后,如何粘帖到word里?原理就是把代码高亮后的文本以html格式复制到剪贴板里,然后调用word的方法去粘帖:

  1. private void InsertButton_Click(object sender, RibbonControlEventArgs e)
  2. {
  3. var dialog = new MainForm();
  4. if (dialog.ShowDialog() == DialogResult.OK)
  5. {
  6. dialog.CopyToClipboard();
  7. Globals.ThisAddIn.Application.Selection.Paste();
  8. }
  9. }

以html格式复制到剪贴板的实现,我是从网上找了一段代码来做的,核心逻辑如下:

  1. public static void CopyToClipboard(string htmlFragment, string title, Uri sourceUrl)
  2. {
  3. if (title == null) title = "From Clipboard";
  4. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  5. string header =
  6. @"Format:HTML Format
  7. Version:1.0
  8. StartHTML:<<<<<<<1
  9. EndHTML:<<<<<<<2
  10. StartFragment:<<<<<<<3
  11. EndFragment:<<<<<<<4
  12. StartSelection:<<<<<<<3
  13. EndSelection:<<<<<<<3
  14. ";
  15. string pre =
  16. @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">
  17. <HTML><HEAD><TITLE>" + title + @"</TITLE></HEAD><BODY><!--StartFragment-->";
  18. string post = @"<!--EndFragment--></BODY></HTML>";
  19. sb.Append(header);
  20. if (sourceUrl != null)
  21. {
  22. sb.AppendFormat("SourceURL:{0}", sourceUrl);
  23. }
  24. var enc = Encoding.UTF8; //中文乱码问题
  25. int startHTML = enc.GetByteCount(sb.ToString());
  26. sb.Append(pre);
  27. int fragmentStart = enc.GetByteCount(sb.ToString());
  28. sb.Append(htmlFragment);
  29. int fragmentEnd = enc.GetByteCount(sb.ToString());
  30. sb.Append(post);
  31. int endHTML = enc.GetByteCount(sb.ToString());
  32. // Backpatch offsets
  33. sb.Replace("<<<<<<<1", To8DigitString(startHTML));
  34. sb.Replace("<<<<<<<2", To8DigitString(endHTML));
  35. sb.Replace("<<<<<<<3", To8DigitString(fragmentStart));
  36. sb.Replace("<<<<<<<4", To8DigitString(fragmentEnd));
  37. Clipboard.Clear();
  38. var dataObj = new DataObject();
  39. dataObj.SetData(DataFormats.Html, new MemoryStream(enc.GetBytes(sb.ToString())));
  40. Clipboard.SetDataObject(dataObj, true);
  41. }
  42. #endregion // Write to Clipboard
  43. }

这个类名叫做HtmlFragment,可以在我提供的下载包里找到。

另外,我这个插件在生成高亮代码时,可以清除掉代码段首尾的空行,也可以清除掉每一行的公共空格,比如下面的代码:

在插入后会变成这个样子:

  1. private void Test()
  2. {
  3. var i = 0;
  4. //do something
  5. }

我用了几条正则表达式来实现这个功能,代码如下:

  1. private string GetHtml(string content)
  2. {
  3. _highlighter.Parser = _htmlParser;
  4. string html = _highlighter.Parse(content);
  5. _highlighter.Parser = _parser;
  6. if (html != null)
  7. {
  8. html = html.Replace("\t", " ");
  9. //清除首尾空行
  10. html = Regex.Replace(html, @"(^\s*\n)|(\n\s*$)", "", RegexOptions.Singleline);
  11. //清除掉公共的空格
  12. MatchCollection matches = Regex.Matches(html, @"^ *(?=\S)", RegexOptions.Multiline);
  13. int len = matches.OfType<Match>().Select(m => m.Value.Length).Min();
  14. html = Regex.Replace(html, @"^ {" + len + "}", "", RegexOptions.Multiline);
  15. //把每一行开头的空格变成&nbsp;
  16. html = Regex.Replace(html, @"^ +(?=\S)",
  17. new MatchEvaluator(
  18. m => string.Join("", new string[m.Length].Select(s => "&nbsp;"))),
  19. RegexOptions.Multiline);
  20. }
  21. return html;
  22. }

有兴趣的同学可以下载源码看一下。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • (翻译)LearnVSXNow!-#7 创建我们第一个工具集-完成这个示例

    在上一篇文章中,我们创建了一个例子:我们为一个空的package添加了一个菜单命令,并且在这个过程中了解了Visual Studio Command ...

    明年我18
  • (转)WPF Custom Control Dependency Property Gotcha

    原文地址:http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-de...

    明年我18
  • (翻译)LearnVSXNow!-#4 创建一个带有工具窗的Package

    上一次我们实现了一个带有命令(Command)的package,这一次让我们更进一步:创建一个被称为工具窗(Tool Window)的界面。那么,什么是工具窗...

    明年我18
  • Go by Example 中文:组合函数

    我们经常需要程序在数据集上执行操作,比如选择满足给定条件的所有项,或者将所有的项通过一个自定义函数映射到一个新的集合上。

    ccf19881030
  • asp.net生成静态页

    做个生成静态页示例: 采用替换模版页的形式生成静态页 第一步:新建项目,创建一个简单模版页:TemplatePage.htm <!DOCTYPE html PU...

    Porschev
  • webapi文档描述-swagger

      最近做的项目使用mvc+webapi,采取前后端分离的方式,后台提供API接口给前端开发人员。这个过程中遇到一个问题后台开发人员怎么提供接口说明文档给前端开...

    用户1168362
  • C#/.NET Web 部分复习总结(面试常问)

    .NET一般指 .NET FrameWork框架,它是一种平台,一种技术。理论上,各种语言都可以编译成它的IL,在上面运行。.NET开发,就是把它当作目标平台的...

    李郑
  • std::string的拷贝赋值研究

    说明:以下涉及的std::string的源代码摘自4.8.2版本。 结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相...

    一见
  • LeetCode 208. Implement Trie (Prefix Tree)

    ShenduCC
  • cf444E. DZY Loves Planting(并查集)

    然后cf正解居然是网络流??出给NOIP模拟赛T1???¥%……&((……%&((

    attack

扫码关注云+社区

领取腾讯云代金券