深入剖析vscode工具函数(七)range模块
VSCode的range模块
range
模块是VSCode中的一个基础的模块,用来处理编辑器中的范围。这个范围可以是一个抽象的区间,可以是区域的宽高,可以是字符的长度等等,应用场景不一。位于 common
的 range
是一个非常通用的模块,在 editor
里面还有专门为编辑器设计的专用API。
IRange的定义
export interface IRange {
start: number;
end: number;
}
IRange
接口只有两个属性:start
和 end
。这两个属性都是数字类型,可以理解为区间的起点和终点。在实际应用中,IRange
接口可以用于表示各种文本范围,例如单个字符、单词、行、段落等。IRange
接口可以被用于实现各种文本操作,例如搜索、高亮、选择、拖拽等。IRange 接口的简单定义使其易于使用,并且可以根据具体需求进行扩展和定制。
区间的交集
export function intersect(one: IRange, other: IRange): IRange {
if (one.start >= other.end || other.start >= one.end) {
return { start: 0, end: 0 };
}
const start = Math.max(one.start, other.start);
const end = Math.min(one.end, other.end);
if (end - start <= 0) {
return { start: 0, end: 0 };
}
return { start, end };
}
这段算法实现了区间的交集,我们给个图示:
区间 one: |-----| (start: 2, end: 7)
区间 other: |-----| (start: 6, end: 11)
交集结果: | (start: 6, end: 7)
这个交集的实现就是找到 start
的最大值和 end
的最小值,它们这个区间就是交集。
在VSCode这个实现版本中,我认为两个判断条件其实有一个是冗余的:
one.start >= other.end || other.start >= one.end
这个排除了不相交的情况end - start <= 0
其实也是排除了不相交的情况
这两个判断条件理论上只需要一个,如果写了第一个判断条件,应该下面的判断条件是不可能会走到的。(如果真的有这个情况恳请斧正)。
区间的相对差集
export function relativeComplement(one: IRange, other: IRange): IRange[] {
const result: IRange[] = [];
const first = { start: one.start, end: Math.min(other.start, one.end) };
const second = { start: Math.max(other.end, one.start), end: one.end };
if (!isEmpty(first)) {
result.push(first);
}
if (!isEmpty(second)) {
result.push(second);
}
return result;
}
这个算法表示的是计算相对差集(relative complement),即计算区间 one(IRange)中不在区间 other(IRange)内的部分。以下是一个简单的图示,显示了两个区间的相对补集算法:
区间 one: |-----| (start: 2, end: 7)
区间 other: |-----| (start: 4, end: 6)
相对补集: |--| |-| (start: 2, end: 4) 和 (start: 6, end: 7)
这个函数的实现也比较简单,它首先将一个范围按照另一个范围进行分割,得到两个子范围。然后,函数检查两个子范围是否为空,如果不为空,则将它们添加到一个数组中,最后返回这个数组。
在VSCode中的应用
其实 range
里定义的算法都是通用的,我们可以将区间看成是代码的行列数,那么它们的交集和补集就是代码区块的重叠,如果将它看成元素的宽高区域,那么交集和补集就是元素的分割与重叠。
image
可以看到在VSCode的 listview
布局中就大量使用 range
中的算法去计算列表的可视范围和动态区域。
小结
在本文中,我们讨论了 VS Code 中 range
模块非常常用的两个函数:intersect
和 relativeComplement
。这些函数是编辑器操作中非常基础而实用的函数,它们的实现也非常简单易懂。
intersect
函数用于计算两个范围的交集,并返回一个新的范围对象。这个函数可以帮助我们在实现文本编辑功能时,计算出选中范围和操作范围的交集,从而只操作交集部分的文本。
relativeComplement
函数用于计算一个范围相对于另一个范围的差集,并返回一个范围对象数组。这个函数可以帮助我们在实现文本编辑功能时,计算出要操作的范围和要排除的范围之间的差集,从而只操作差集部分的文本。
这两个函数的实现非常简单,但在实际的编辑器操作中非常实用。掌握这两个函数的使用,可以使得我们在理解VSCode关于列表布局、编辑器相关核心代码的时候更加清晰。