All Stories

磨刀也费时

  俗话说,磨刀不误砍柴功。对于这句话,我一直都自认为是辩证地看待的,在某些工作前,先做些准备工作可以极大地提高之后的效率,好比Kunth老爹的TeX。不过很多时候,磨刀也是件很费时费力的事情,好比Kunth老爹的TeX。   这几天一直在考虑实现ZenHTML,这是一种极大提高hard coding效率的code snippet方法。其中有一种可以认为是一种“小语言”,呃,这是《UNIX程序设计艺术》中的说法,用GoF的《设计模式》中的说法应该算是interpreter模式。不管怎么说,反正就是有一项任务是要解释字符串,根据字符串的不同表达式来作出不同的响应。   刚开始的时候我是觉得这个解析工作似乎非常简单,没有必要把它提高到“语言”这种层面对待,只要识别出两三个操作符就可以了。不过后来马上发现,实现起来并不轻松。我意识到,用Lua实现的话,用LPeg将是最合适的解决方案。今天又翻出LPeg的manual来看,还是看得有点糊里糊涂。明天继续。   所以说,磨刀也费时啊!

故事已经开始

  我不知道该给这篇文章取个什么题目,半个小时前,是先想好题目,然后决定要写这篇文章的,可是当我开始写的时候,觉得那个题目不合适,不能完全表达出我的心情、我的感受。   昨天从家里出发的时候,我看了一眼时间,那是清晨的8:14,当时只是为了计一下时,看我全程需要多久。最后停在上海的小区楼下时,时间是11点半左右,我没记清,我当时发出两条短信,分别给我当前我以为应该是对我来说最重要的两个女人。一个是我妈,还有一个……是她,因为她,我才决定来上海。   这是一个还没有开始,就已经曲折的故事。   我和她认识有5年半了,那这5年多来,一直只是在重要的节假日时互相发个祝福短信。直到今年元旦,她又发来祝福短信。然后很偶然地开始在网上聊天,真的很奇怪,为什么在那5年中,我们就没这么聊过。在网上,我们聊得很开心,至少我是非常开心。于是渐渐地,我沦陷了。我已经不能忍受没有她一起聊天的时光了。   我鼓起自己所有的勇气,我决定向她表白。那是愚人节后的第3天,那天她从上海回家去。本来说好是我去接她的,结果被她姑妈接走了。在那天晚上10点多的时候,我终于忍不住了,我一直认为表白应该是当面才显得有诚意,但是我已经没有办法继续等待,我在电话中跟她说,我喜欢她,请她做我的女朋友。无论是表白的场景,还是表白后的各种情况,都被我在脑海中预演过很多次。但果然现实是没有在我的预料中的,她说太突然了,都没有过渡的,感觉我像在开玩笑。我有点小郁闷,觉得委屈。我都已经沦陷在其中了,为什么仍会被说成像开玩笑。最后我实在没办法了,就说你就考虑下吧。   那是一个奇怪的情景,双鱼的优柔寡断从此可见一斑,于是她说就考虑下吧。挂掉电话,我觉得我应该再做些什么,躺在床上,最后想到一个很老土很容易想到的事情——写情书。恨当年,没多读些诗词古文,挖空心思总算花了一上午时间凑出几百字的小文,通过email发了出去,并用短信叫她去检查一下邮箱。她一直没理我。直到那晚上,才用短信说了下她在干吗。   之后的两天都是在浑浑噩噩中度过的。直到她要回上海的那天下午,我直接告诉她我去接她了。在车站,我们还是像往常一样的聊着,我仍然不敢在聊天的时候看她的眼睛。我像一个羞涩的小男生,我鄙视自己。送她上车后,她发短信给我,说要真实地相处一下,才有真实的感觉,嗯,我华丽丽地在真实的感觉前露出了原形。   因为要真实的相处,要真实的感觉,所以我决定,我要尽快到上海去,这样才能更多地和她在一起。我跟她约好,周六我去上海找房子,她陪我去找。那一周时间里,我觉得像是煎熬,双鱼的多疑充分发挥,我觉得她开始与我保持距离。   好不容易周六了,我乘长途汽车到了上海,然后坐地铁,直到淞鸿路跟她会面。我觉得我熟悉的那个她还在,她仍然对我很热情。我们在永和豆浆吃过中饭,开始去中介租房子。这是悲剧的开始。因为又要价格实惠,又要装修不差,这要的房子不好找,我们跑来跑去近一个下午,最后总算是搞定了。后来回忆中间的一些细节,我发现我经常会有些得意忘形。这是一个很不好的习惯,男人需要沉着并内敛,但我经常忘记,所以我不够成熟。具体一点的事说来,她总是为了房子中的各种设备、条件跟房东、中介讨价还价,而我却不时地打断她,说些不合时宜的话。照一个推友的说法,我的情商够低的。   后来晚上又让她陪着去逛了一些地方,直到晚上10来点的时候,她说膝弯的地方痛得不行了,说下午找房子的时候就已经开始痛了。我说我没感觉呀!她回到屋,我躺在酒店的床上给她发短信,我说如果明天还痛,我们就不走了,找个地方喝喝茶聊聊天。她却说,相信睡一觉会恢复的。   第二天10点钟,我从她小区等她出来,一起去买导航。我只是单纯想要买个导航,却没做过任何前期的调查工作。她问我有没有事先看过要什么牌子的,我说没有。然后两个人像无头苍蝇一样到处乱转。最后看了两家后,导航是买好了,时间也不早了,雨下得很大,我们就在一旁的真功夫吃了,然后她送我到长途汽车站。   回到家,我发现她对我似乎更加冷淡。每一天,我都试图给自己找些事情,填充自己的大脑,转移注意力。一旦停下来,又会想她为什么会这样。我回忆着我在上海时跟她一起的每一件事情,尝试从中找出一些蛛丝马迹。但是成效不大,我很无奈,我不知道我哪里做错了。父母得知我周六就要搬到上海,浓浓的不舍之情从言语、表情和行动上不停流露。我狠下心对自己说,我要勇敢,我不可能一辈子生活在父母的羽翼下。每天早上,我都是在焦虑和不安中醒来,为事业,也为爱情。她说觉得我浮夸,夸夸其谈,不踏实。我很难过,但我想知道我哪里做得不对,我问afei和王同学,结果吃惊的是afei说我对人不真诚。afei告诉我,跟人说话的时候,眼睛不要乱飘。我知道了,我跟她聊天的时候不敢看她的眼睛,以后跟她说话,我一定会注视着她的双眼。其实我经常反省自己,却发现自己仍然经常高估自己的能力,低估现实的难度。   昨天,就是我来上海的日子。来上海,我不迷茫,却充满了不安。我想我太理性,做一件事情总是会试图量化其成本和收益,从而判断是否值得。但是双鱼的感性,让我实际上做事往往只凭着一时冲动。我到达后发给她短信,却一直没收到回复。我是有点生气的,虽说是我在追求你,但你回条短信应付一下也是可以的吧。把东西都拿到屋里后,一件一件发出来,才体会到“儿行千里母担忧”的心情。我忍不住有点痛恨自己,想想我这二十几年,过得实在太失败了,既不能呆在父母身边敬孝,又没能力让父母在物质上过上比较富足的生活,甚至连传宗接代这种事都要父母操心着急,我真太没用了。   晚饭是一起吃的,还有她的室友。我在阿玛尼店门口见到她,一个陌生的她。我的心有点凉。吃饭的时候,我竭尽所能地表现得风趣幽默,结果是个杯具,一个上面刻满了“自以为是”的杯具。   今天她在网上问我,昨天为什么要讲那些恐怖的事情。我说我的出发点,是为了让你们平时多注意安全。她说,谢谢,我们会注意的。很平静,很客套。我的心很凉。她说她不能接受一个麻木的人。我理解,很理解。但我不愿放弃。我求她给我机会,让我慢慢改好,给我表现的机会。她说她是个被宠惯了的人,上次找房子和买东西,让她很无语。她还说我是被女孩子们照顾惯了,不懂照顾人。我很委屈,我打电话告诉她,这些我都会改,但得给我机会,还得在适当的时候提醒我,哪些地方做得不对做得不好。   是的,我真的从没这么委屈过,但所谓一物降一物吧。既然我决定投入了,就要认真地走下去,也许那条路有坎坷,但我仍要继续走下去。也许我会被摔得鼻青脸肿,甚至遍体鳞伤,但等以后回头来看,至少会少些遗憾。   故事已经开始,期待结局的圆满。

LuaJIT2与Luabind打架了

  其实这个问题老早就有了,当时还在Lua的maillist上提过,不过当时我只是发现LuaJIT2在执行Lua脚本时,如果Lua脚本调用了不存在的C函数时会使宿主崩溃,Mike Pall同学(LuaJIT的作者)倒是很爽快地解决了这个问题。后来发现,Mike Pall解决的只是一部分,我这里因为用到了Luabind,通过Luabind来调用执行Lua函数,如果Lua脚本又调用到不存在的C++函数,进程就会无声无息地退出,而如果是官方Lua的话,则是会老老实实地打印那些出错信息出来。   昨天忍无可忍了,就又向Lua maillist发了封邮件,今天发现Mike Pall和Daniel Wallin(Luabind的作者)争起来了,呵呵。Mike Pall说问题在Linux上和Windows/x64上都没能重现,不知道Windows/x86出了什么问题,可能是Luabind重复抛出异常了,Daniel Wallin则说Luabind只是简单地调用了lua_error,他倒是能在虚拟机的Windows环境下重现问题,最后他又给出了一段简化后的代码,只要lua_error调用后面有C++对象的析构,LuaJIT就会出问题。   我倒是偶然看到今年1月份的Lua maillist上的邮件,Mike Pall曾经说过Windows/x86上MSVC实现try/catch是用SEH实现的,这个LuaJIT处理可能有点问题。但他后来的邮件中好像又说在新代码中已经解决这个问题了。我于是用MinGW试了试,GCC 4.4.0编译出来的,确实是没问题的呢!   不过最后,又看到Mike Pall好大一篇解释,最终结论是建议所有用户都升级使用x64,囧!

入沪通行证

  刚才有那么一刹那,突然很害怕,不知道今天做了什么,几秒钟后反应过来,今天出门了,去办入沪车辆通行证了,现在这记性,真让人无语。   总的说来是比较顺利的,昨天在网上看过大致的要求,今天先跑去东关派出所,这是离我们家最近的派出所了,顺便试了试前天买的导航,除了我们村认不出来外,其他的都不错。到了东关派出所,结果被告知,因为车主是我妈,而我妈的户口是在百官的,所以得去百官派出所办,而且因为授权给我开,所以我得有临时居住证。有点出乎我的意料的是,临时居住证的办理非常快捷,只要填一张表,交两张一寸照就可以了。而我没有一寸照,就跑到东关街上那家主人本来是棉纺厂里跟我们是邻居的照相馆里立马拍了照。话说现在的拍照也太方便了,拍完后直接拷到电脑上用Photoshop改了一把,再用打印机打出来就行了。然后再折回派出所,那里的姐姐动作麻利地把其他事情一会儿就搞好了,临时居住证也是从打印机里打出来的。接着就直奔百官派出所,这时导航就比较傻了,我估计是地图没有更新,一直指向另一个派出所了。到了百官派出所,人也不多,那里的mm拿出三张纸来让我填,然后去旁边的复印店里复印了一下相关证件,就被告知等3天后就可以取到入沪通行证了。还是很顺利的啊!   我真的投入进去了,不顾一切地投入进去了,不怕遍体鳞伤,不怕鲜血淋漓,为了爱,我要勇敢!

增强Code Snippet

  本来这是打算在上周五完成的,结果上周五又开小差搞界面去了,周六周日又跑去魔都了,于是就拖到这周了。今天刚开始的时候还有点惧怕的,怕是实现难点有点高,甚至又冒出过放弃的念头的。后来还是硬着头皮做一点是一点,结果还不错,比想像的要容易一些,已经能达到90%的计划中的程度了,剩下的10%么,从个人感情上还是从策略上,都应该放到后面的版本中实现了。   下面先说一下最终的表现吧。   前一个版本,code snippet使用的展开缩写的快捷键是Ctrl+,,这次把这个快捷键换到Ctrl+;了,那是因为另外又增加了两个操作,这两个操作是正反对应的,于是分别占用了Ctrl+,和Ctrl+.。正常的操作方法是,假设在编辑Lua源代码时,输入for,这时光标停在最后一个字母r的后面,按快捷键Ctrl+,,会自动将for展开为比较完整的for i = 1,10 do…(省略号表示后面还有些内容,这里不影响说明,就不列出来了)并选中for后面的循环变量i。到这步为止,相比上个版本的实现,只是增加了选中循环变量i的这步操作,但也已经方便了用户可以不再手动移动光标位置来修改变量名称。接下了,就是新增的两个占用了快捷键的操作,即Ctrl+,和Ctrl+.,分别是向左或向右跳动选中1和10。也就是说,在这次for展开后,共有3处可能被自动选中,即i、1、10,至于每次选中哪处,可以通过快捷键Ctrl+,和Ctrl+.来修改。这是基于这样的应用场景:在for循环中,基本的循环结构是自动补完了,但实际上循环变量和变量的初始值和终结值是最可能需要根据情况修改的,于是编辑器就可以通过快捷键快速选中这些部分,而不用再通过鼠标或方向键等常规方法移动输入光标进行修改。这就是最终的表现。   接着简单记一下实现的过程。   因为从整个程序的实现架构上的原因,此功能的实现一部分由Lua脚本完成,一部分由C++完成。首先是修改了code snippet的模板,如上例中的for,在模板中的定义是for ${1:i} = ${2:1}, ${3:10} do…(省略号表示后面还有些内容,这里不影响说明,就不列出来了)可以看到有3处用${}包括的内容,这些内容的都用一个冒号分隔,冒号前面是一个编号,冒号后面是最终展开后填入到编辑器中的内容。编号用于按快捷键Ctrl+,和Ctrl+.时进行排序,Ctrl+,则从大到小跳转,Ctrl+.从小大到跳转,初始状态时选中编号为1的部分。在for后展开snippet,是用Lua脚本完成的,那会先从模板配置文件中找到缩写对应的模板,然后将${}部分全都提取出来并替换成冒号后面的部分内容,并根据当前编辑器的插入位置重新计算和修正每个${}的位置信息。这些位置信息用于后面的选中功能。然后把所有这些信息都存入C++实现的编辑器对象中,在C++实现的编辑器类中会有几处事件通知处理。一处是刷新UI时,更新当前光标位置,如果当前光标位置已经不在任何一个${}的范围内,那么本次code snippet展开就算完成任务了。另一处是编辑器内的文本修改,如果有新增或减少文本,那么要修改当前光标所在的${}的长度(这个长度在选中文本时需要用到),并修改该${}位置后面的所有其他${}的起始位置。只有这样,才能在修改了一处${}后,仍能继续正常地在各处${}间来回跳转。好了,基本的思路就是这样了。   题外话,想说一下,在文本处理方面,脚本语言确实比C++要方便一些,比如查找替换${}部分,在Lua中实现的模式匹配就很好用。

新工具栏

  昨天偶然发现CodeLite已经升级到2.5版本了,作者还真是孜孜不倦啊。下载下来看了一下,发现最明显的是界面上的变化,工具栏变漂亮了。于是我又好奇心起来了,找来它的源代码看看,原来是用wxAuiToolBar类而不是原来的wxToolBar。于是昨天我先在自己的程序里把主工具栏也换了一下,感觉是很爽。昨天还加了最近打开的历史文件记录和解决方案记录,一直弄到晚上9点才基本搞定,一开始没搞清楚怎么处理2个wxFileHistory对象。   今天开始着手增强Code Snippet。前天已经想通了,现在的插件机制基本上算得上强悍,就不用完全照搬TextMate的Bundle了,只是Tab trigger还是不错的。我的决定只要把code snippet部分做得跟Tab trigger差不多就行了,以后再完善一个插件机制,提供一个插件开发包就行了。   今天写代码,看着焕然一新的工具栏,以及方便的最近打开文件菜单,心情非常好,code snippet的预处理部分基本上完成了,明天只要加上快捷键,可以进行跳转就OK了!后来又觉得应该把TeX的符号工具栏也用新式的wxAuiToolBar,由于它跟wxToolBar的接口有点区别,所以自己从wxAuiToolBar继承下来创建了个新类,主工具栏和符号工具栏都可以使用新界面了,感觉不错!   看来得多找些更新积极的开源的项目,多学习学习那些源代码啊。

两个月计划

  想到实现Bundle,是个比较大的挑战,有些部分必然会跟编辑器核心结合得比较紧密,对于我这种直接使用Scintilla控件实现的方式,很有可能需要修改Scintilla的源代码提供必要的支持。今天一想,其实如果基于我现在的Code Snippet的思路做下去,是很难做到TextMate的地步的,因为Bundle能完成的功能很多,输入输出条件也有好几种,而code snippet只是其中的一种而已。如果只是沿着把Code Snippet强化这个方向发展,最多实现到TextMate中Tab trigger的那种地步,而这些正是我之前一直在考虑的以为是Bundle的东西。小瞧了啊!没办法了,一步一步来吧。   昨天在QQ上跟人交流,知道一个诺基亚的手机应用开发大赛,到6月10日截止提交作品,到9月评出结果。现在算来还有足足2个月,不过我并没有好的题材。他是做图像处理方向的,而且是用QT的,所以移植到Nokia的手机上应该工作量比其他人小多了吧。另外他还给我看了一个老外做的画图软件,那界面真是赞啊!如果不是做像IDE这种严肃型的软件,其他的大众类软件真的得好好设计一下界面。   前些天Firefox自动升级到3.6.2后,看到Firefox也用twitter/facebook/blog进行推广了,看来这是大势所趋啊。之前试过几次想创建一个组织型的Facebook账号,结果一直没成功,今天发现原来是创建错类型了,Facebook有专门的为产品/组织等非个人形式的个体创建页面的入口。于是今天就在网站上加了twitter和facebook的链接,至于blog嘛,众所周知世界上最成功的blog营销案例,在软件行业应该算Joel on Software,不过Joel在那篇宣布以后不再写blog的文章中提到过,要靠blog聚集人气,不光要写自己公司的产品,还要写关于软件开发的方方面面,这样才会吸引各种相关读者的讨论。可是,我现在的致命缺陷是,我当前的英文水平完全不够用来写blog,真郁闷啊!

准备实现Bundles

  昨天晚上咬牙把所有的图片都修正了一遍,基本处于可用的状态了,终于撑过这段繁琐枯燥的工作了。今天又添加了几个新建项,上次发布的时候把这个忘掉了,这次补上。不过实现得有点儿问题,在第一次显示的list view中只要是有多个图标的,总是会在最开始留出那个数目的图标的位置,真郁闷,心烦意乱地调了一下午,也没进展,先不管了。   接下来的任务是实现一个类似TextMate的Bundles机制,这需要好好设计一下,实现成什么样,怎么实现。最近在纠结的问题是,快捷键要不要换掉。TextMate和e都是用Tab的,而且不支持Shift+Tabe。我在之前的版本实现code snippet时,用了Ctrl+,这组快捷键,而且我觉得支持反向跳转似乎很炫,呃,目前确实只能用“炫”来形容,因为不知道实际使用过程中到底有没有用。

自动化,自动化!

  昨天提到从抠图片,到添加到程序中,一共要处理500多个图标,很大的工作量,而且太枯燥机械了。今天看到MiloYip大大的留言,恍然大悟,我怎么就一直没想到把这个过程自动化一下呢!   今天上午的时候还在老老实实地把图标一个一个加入到程序中,这有两步操作,一步是添加XML描述,另一步是添加Lua响应函数。一上午,总共添加了53个图标,到吃中饭的时候自己都觉得效率太低了。在MiloYip大大的提示后,下午用Lua写了几行代码,花了2个小时左右,把剩下300多个图标全都添加进去了。以前真是太傻了,多花了不少时间啊!   剩下的工作就是把那些图标稍微都修正一下。   从这次事件可以看出,我的相关技术敏感性还不够,缺少自我改进意识。