其实也并非
Emacs
专有,像
Vim
或者
UE
也有类似的功能,只是我用
Emacs
比较多,所以才取了这个题目。总之,就是将在编辑的一个文本框分割为垂直或者水平的两个相同大小的文本,对于同一个编辑目标,两者保持相同的内容变更,但两者又可分别显示不同的编辑对象,被分割出来的两个文本框又可自行再次分割,以此类推。如果看的迷糊的,自己试试
Emacs
去,“
Control x 2
(
3
)”就行。
这么做的好处在于可以同时观察到两个相关的代码段,有助于查找需要的信息,或者其中一个编辑另一个执行某个如
tclsh
的命令,等等。差不多就是一个多任务的形式,思维比较活跃的人多是喜欢这样开好几个窗口干活。
这个看似简单易用的玩意儿,实现起来却有点让人无从下手。首先,要让两个同编辑目标的文本框保持同步更新;第二,同一个文本框中切换不同编辑对象时,需要保证如语法渲染之类的操作不影响切换速度;第三,保证分割出来的文本框不会改变父窗体的大小。也许还有别的问题,但这三个是让我有点茫然的东西。
经过一番思量,对于第一个问题,应该可以用
rename
注入代码完成。这在我之前写的文章里有很多涉及,这里就具体不讲。只是需要判断一下两个文本框的编辑对象是否一致。如此一来,对于第二个问题,则需要在每次切换的时候将涉及到渲染或者计算的部分以一定结构的数据形式将结果存储起来以备后用,比如将用于作色渲染的
tag
标记都
dump
出来,还有复制内容,当前插入点等等。
不过,在这里我采用了另一种更加优雅的方式,其实是使用了在
Tk8.5
中新加入的
text
组件命令:
peer
,在
actovetcl
的
demo
中也可以看到相关的例子。就是对于一个已建的
text
组件,通过
peer
命令生成它的镜像对象,这两个对象是完全相同的,对任一个的才做都会影响其他对象的变现。事实上,对于一个新建的文本编辑对象,我都首先生成了一个不被
geometry
的
text
对象,用术语说就是
buffer
,再针对这个
buffer
来
peer
出所有需要显示的文本框窗体。那么对于第二个问题,就不是某个
text
组件中内容之间的切换了,而是不同
text
组件之间的切换,可以通过
forget
来完成。这么做的好处在于,我肯本不用考虑切换时状态存储,而且
peer
可以更好地保证编辑对象的一致性要求。
而第三个问题的解决让我对
geometry
中的
place
命令有了全新的认识。众所周知,
geometry
的三种方法中,最被广泛使用的是
pack
,其次是
grid
,最后才是
place
。无论那本介绍
Tk
的书籍,都是按照这个顺寻来编写的。也许是应为
pack
的命令最短,也更通俗易懂一些。但在这里,我不得不使用
place
。对于一个需要被分割的文本框,以下的代码很难控制父窗体的大小。
package require Tk
text .t1
text .t2
pack .t1 –fill both –expand 1
pack forget .t1
pack .t1 .t2 -side left –fill both –expand 1
事实上,这么做的结果是使父窗体加宽了一倍。即使你小心地设定了
text
组件的
width
,一旦
fill
开来就面目全非了。在这里只能使用
place
,结合相对起点与相对长宽,精确设定分割窗体大小。以下是一个实现类以上所讲到和没讲到的功能的完整
demo
,有兴趣的可以看看。其中还包含了切换和关闭
buffer
的快捷键。
split.tcl文件下载