支持已在https://github.com/sourcelair/xterm.js/pull/938中删除
当然,仍然有可能,渲染器需要知道要加入哪些字符。
我认为我们对常规的连字不感兴趣(实际上,对于li
等启用连字会很不好),但是对于==
, !==
, =>
,依此类推。 这是fira代码等宽字体支持的连字的不错列表:
https://github.com/tonsky/FiraCode/blob/master/showcases/all_ligatures.png
如果一半的连字是不同的颜色会怎样? 您将如何处理?
@LoganDark甚至可以使用常规连字吗? 还是当它们是不同的颜色时它们会分开吗?
不,不。
我想知道是否可以从txtjs中提取渲染代码,因为他们已经找到了如何渲染连字的方法,尽管我认为他们是手动绘制文本的。 http://txtjs.com/examples/Text/ligatures.html
@devsnek我认为实际上渲染文本不是问题。 问题在于知道哪个字符可以联接在一起,以便可以将它们绘制在一起(当前将“ ==”绘制为“ =”和“ =”,而不是“ ==“)。
@Tyriar如果没有我们的干预,字体渲染器不会解决这个问题
@devsnek是的,但是网格中的每个单元格都是单独绘制的,但有一些例外(表情符号,宽Unicode字符)。 连接需要以某种方式包括在该列表中。 查看https://github.com/sourcelair/xterm.js/pull/938了解更多背景信息
@devsnek就是你
免责声明:完全没有话题,只是一个随机评论
@LoganDark甚至可以使用常规连字吗? 还是当它们是不同的颜色时它们会分开吗?
如果我们要看看其他仿真器是如何处理它们的,那么,如果它们是不同的颜色,它们的确会分裂,就像人们期望的那样。 这几乎是必需的,因为例如,这允许符号由ViM中的某些语言突出显示正确地表示。
我认为,如果所有基本字符的渲染模式都不相同,则显示单个符号是完全可以接受的。
@ Qix-然后我的建议是立即绘制所有文本,然后在后期进行着色。 这将消除连字的任何问题,并且不需要检测连字对(尽管这会破坏与可变宽度字体的兼容性,甚至破坏稍有/没有整数宽度的等宽字体)
@LoganDark多色的连字看起来很奇怪,并且没有为IMO着色的明确方法。
是的,我认为多色连字不起作用。 它还与它们在下面的工作方式背道而驰,在开始时只绘制一个字形,而不是多个。
为了澄清起见,这正在等待一种好的解决方案,用于检测哪些字符序列具有连字。 要正确执行此操作,可能会涉及检查字体文件的低级代码(因此,它必须是本机节点模块,不适用于Web使用者),我认为此信息不会暴露给Web平台。
既然Hyper 2.0.0稳定了,也许连字解决方法需要更高的优先级。
手动确定字形映射是一个难以克服的难题。 据我所知,要从中获得体面的体验将需要以下几点:
我已经对Fira Code (特别是它的书呆子字体变体)进行了一些初步研究,以试图弄清楚每个步骤可能有多困难。 我还没有决定我是否有足够的野心(或者足够关心字体的连字)来进行这项工作,但是这是我发现的,因此不会丢失这些知识:
我无法找到使用浏览器API来获取字体数据的方法,因此,这不能作为xterm.js的直接功能,而更可能是作为单独的带有xterm.js公开的钩子的程序包/扩展名
在Windows中将字体的CSS font-family
名称映射回其字体文件很麻烦,但似乎可行。 到目前为止,我发现的唯一方法是获取%WINDIR%\Fonts
并解析我找到的每个文件(更糟:这确实很慢)。 尚未尝试其他平台。 (注意:我也尝试过从注册表中提取名称,但是某些字体的命名没有对齐,例如书呆子字体的字体。它们使用“首选”家族和子家族,但不在注册表名称中但用于css font-family
。如果您很好奇,注册表项在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
)
有一个叫库opentype.js这确实OpenType字体表的完全解析,甚至有一个font.stringToGlyphs(str)
函数处理基本连字,但费拉码的连字(和几个如果不是全部的其他常见结扎字体)使用一种称为上下文替代的功能,opentype.js(在Planned下列出)尚不支持该功能。 不过,必要的GSUB表会为您解析为JSON,因此从理论上讲,缺少的只是表数据的解释。
Fira代码连字(以及我认为其他人)实际上用相等数量的字形代替了原始字形,而不是单个超宽字形(以保持等宽字体的属性)。 对于像==>
这样的字符串,字体最终会告诉您将其替换为两个“ LIG”字符(基本上是一个空白),然后是实际的连字字形,从技术上讲,它仍然是一个等宽字符字符宽。 尽管表面上看起来是单个宽度,但是最后一个字符的路径超出了字符边界框的左侧,以覆盖之前的两个LIG字符所占据的空间。 视觉效果请参见下文(0和600是角色框的侧面)。 我不知道这是否会使渲染器的任务复杂化,或者在传递给xterm.js之前是否必须对其进行转换,但是需要注意一些事情。
另一个难题是确定何时重新评估连字。 例如,如果我连续四次键入=
,则期望的行为是让我看到单个等号,然后是两个等号连字,然后是三个等号连字,然后是四个单独的等号。 上下文替代规则中实际上有一些映射用于清除连字(即,如果当前输入为'=',并且前三个字符为'===',则根本不要重新映射它),但是我们必须找出如何应用这些规则。
OpenType很复杂。 诚然,我不是字体渲染专家,但是导致不同类型的渲染的可能变化数量非常多。 没有内置的库为我们做映射,我认为最合理的方法是逐步进行攻击。 Fira Code特别使用Chaining Context Substitution Format 3 ,但是我敢肯定还有其他流行的字体使用不同的字体。 由于每种语言的语义略有不同,因此从一种语言开始并从那里开始可能很有意义。
@princjef感谢您分享您的探索,真的很有帮助! 几天前,我也一直在对该主题进行一些思考,得出以下结论:
li
)TBH,我认为在当前状态下支持连字不值得付出努力😔
@mofux我实际上认为我已经找到了一种(有点可口)的方法,可以通过从另一个角度来处理来使连字在xterm.js中呈现。 我不知何故在最初的调查中画布会自动为您渲染连字。 支持连字成为确保相关字符一起呈现的问题。
为此,我调整了文本渲染器以将具有相同属性(fg,bg等)的字符作为单个组进行渲染。 这不会完全正确地渲染所有连字(并且可能会渲染不应该的连字),但是应该在有人希望看到的任何地方渲染连字。 这是使用Fira Code的演示应用程序中NeoVIM的屏幕截图(显示在Firefox中,也可以在Chrome中使用,但不能在Edge中使用):
如果人们想看看,这里是分支机构: https :
关于此的一些注意事项:
Infinity
以确保避免任何缓存。如何使用字符图集渲染文本,然后在空闲时将其作为文本块重新渲染在背景中呢? 如果两者导致的图像相同,则可以丢弃合并的文本并切换回地图集。 通过在后台拆分文本字符串,可能可以了解连字的文本字符串。
棘手的是,连字的渲染不仅取决于被连字替换的字符,还取决于其上下文。 例如,“ === 1”应将三个等号呈现为连字,但“ ====”应将相同的三个等号呈现为单独的字符。 对于此上下文的大小没有限制,因此仅从其输出中确定连字何时绘制的规则就很难而且很容易出错。
一种更可靠的方法(但移植性较差)是由知道字体元数据的单独功能提供有关连字范围的提示。 然后,除了外部函数提供的范围之外的所有内容都可以使用图集进行呈现,而给定的组可以使用上述方法。 确定给定一行文本的替换位置应该很快,但是存在我前面详细介绍的一些问题(主要是在初始化时查找正确字体的速度/可靠性以及处理OpenType上下文替代项的复杂性)。
设置启用连字的设置合理吗?
一次到终端的整行? 好像这样
保证正确的渲染,而性能命中率将成为
人们更关心连字而不是速度。
在2018年4月22日星期日,16:21 Jeff Principe [email protected]写道:
棘手的部分是连字的渲染是依赖的
不仅是被连字替换的字符,还包括它们的上下文。
例如,“ === 1”应将三个等号呈现为连字,但
'===='应该将相同的三个等号呈现为单独的字符。
对于此上下文的大小没有限制,因此这将很困难并且
可能容易出错,以确定何时渲染连字的规则
仅从其输出。一种更可靠(但不那么便携)的方法是具有以下提示
由知道字体的单独函数提供的连字范围
元数据。 然后,除了外部功能提供的范围之外的所有内容
可以使用地图集进行渲染,而给定的组可以使用
类似于上面的方法。 确定替代位置
给一行文本应该很快,但是有一些问题
更详细的内容(主要是在以下位置找到合适字体的速度/可靠性)
初始化和处理OpenType上下文替代项的复杂性)。-
您收到此消息是因为您已订阅此线程。
直接回复此电子邮件,在GitHub上查看
https://github.com/xtermjs/xterm.js/issues/958#issuecomment-383420281 ,
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAKyryMlayIQijY32GpWBmpvCUi13Wfbks5trRBigaJpZM4PRej6
。
@princjef哇,您的编辑非常容易遵循,而且看起来xterm可以支持渲染器的连字。 诀窍只是弄清楚如何映射规则。 这给了我希望。
@princjef很棒的调查!
我无法找到使用浏览器API来获取字体数据的方法,因此,这不能作为xterm.js的直接功能,而更可能是作为单独的带有xterm.js公开的钩子的程序包/扩展名
@princjef我看到最终的连字支持生活为:
some-magical-package
:本地节点模块获取本地字体信息,并在可能的情况下将Web字体字符串映射到文件。 可以在AsyncWorker
完成此操作以减少性能xtermjs/xterm-ligature-support
:一个依赖于节点并使用some-magical-package
获取和缓存字体信息的插件。 每当在fonts目录中检测到无法识别的字体时,此插件即可进行扫描,并在删除字体时逐出该字体。 我期望这样的东西作为粗糙的API:
/** Returns a list of characters to be drawn together */
export function getLigatures(fontFamily: string): string[] { ... }
即使字体支持,某些连字在终端中也没有意义(例如li)
@mofux我不确定我们是否需要为此担心吗? 如果用户请求连字,我们不应该全部渲染吗?
使用当前基于单字符的渲染方法(CharAtlas),很难实现对绘制和清除跨越多个单元格的字符的支持。
@mofux我们应该能够很容易地添加一个函数,以将一组相邻的字符绘制在一起。
@princjef :我还没有做过任何基准测试,但是我
@wavebeem :具有启用连字的设置是否合理,该设置一次将一整行写入终端?
我希望它几乎完全抵消使用画布所带来的性能改进。 另外,我想将选项的数量保持在最低限度,当包含一个插件来增加支持时,我们应该尝试使用连字功能。
此外,在性能方面,由于Chromium中对GPU的支持可能会出错,因此我可能会在未来几个月内尝试添加后备DOM渲染选项。 参见https://github.com/xtermjs/xterm.js/issues/1360。 在这种模式下,连接器可以直接使用。
如何使用字符图集渲染文本,然后在空闲时将其作为文本块重新渲染在背景中呢? 如果两者导致的图像相同,则可以丢弃合并的文本并切换回地图集。
@ j-f1这比看起来要困难。 即使字符呈现相同,第二个字符也会有所不同,因为字符集中的间距是不同的(字符总是绘制在整数上)。 我们需要做更多的渲染才能工作,并且需要扩散像素,这是很昂贵的。
@Tyriar我认为您所描述的总体设计是合理的。 我们可以摆脱不依赖于本机代码的东西来找到some-magical-package
的字体,但是它肯定取决于平台/文件系统。 我已经开始尝试解析上下文替代项,但是很难说要完成它需要花费多少。
我还认为我们最终将需要一个与some-magical-package
稍微不同的接口:
export function getSubstitutionRanges(fontFamily: string, text: string): Promise<[number, number][]>;
确定连字本身的规则既复杂又深入字体本身。 与其传递字体数据本身并将解释的负担放在xterm.js上,不如将其交给另一个库,让它告诉xterm.js哪些字符应一起呈现。 上下文的超前/后退方面也使解析变得复杂。 例如,“ ===”映射为连字,但如果后面紧跟另一个等号则不会映射。
关于替换范围概念的另一条注释:我无法分辨出至少一个连字的边界(至少在使用上下文替换时)。 仅将替换序列应用于单个字符。 如果您有连续的连字,我发现了一些技巧来找出界限,但这可能并非万无一失。 我可能会误以为将两个连字视为一个连字,而不是不小心将它们分开,因为如果将它们全部组合为一个组,它们仍应正确呈现。 唯一真正的问题是对它应用异构样式。
唯一真正的问题是对它应用异构样式。
只是不要。 将连续样式的每个字符串分别传递给函数。 如果下划线是单独绘制的,则您可能可以为下划线的文本设置例外。
我们也许可以摆脱不依赖于本机代码的问题
👍
确定连字本身的规则既复杂又深入字体本身。 与其传递字体数据本身并将解释的负担放在xterm.js上,不如将其交给另一个库,让它告诉xterm.js哪些字符应一起呈现。
@princjef听起来更好,xterm.js在这方面要做的越少越好。
唯一真正的问题是对它应用异构样式。
我认为没有其他尝试这样做,我们应该只为使用相同样式的文本添加连字。
这看起来在字体方面可行。 我有一些代码可以成功解析所有Fira代码连字,并为组合字符提供正确的范围。 如果人们在寻求其他一种或两种字体的支持,我也可以尝试检查这些字体。 到目前为止,我只实现了Fira Code所需的替代类型,因此欢迎使用其他替代类型。
仍然需要弄清楚字体查找部分。 接下来将重点关注。 那里有一些软件包,但是它们似乎都存在错误或维护不善
@princjef如果要检查其他字体,我正在使用Iosevka 。
好了,我已经创建了一个名为font-ligatures
(又名some-magical-package
)的包和一些相关的包,以便我们可以有效地找到正确的字体,然后找出给定文本输入的连字位置。
我花了一些时间来优化查找字体的过程。 在具有〜150 ttf / otf字体的Surface Pro 4上,我可以在300-400ms内获取所有字体的字体元数据。 它主要受I / O约束,可以在加载时的前几个渲染周期中被踢到后台,但是应该足够快,以便在pty启动并吐出一些文本时加载。 加载后,我们可以触发渲染以更新可能已经存在的任何文本。 每当字体更改时,都可以重复此操作,或者我们可以第一次缓存完整列表(无论如何,我还是从开头开始获取完整列表)。
至于连字映射本身,该库将接收一个字符串并返回有关字体连字的元数据,包括应一起呈现的字符组。 CI包含Fira Code,Iosevka和Monoid中每个连字的测试,因此我有足够的信心对它执行的替换类型进行正确处理(尽管我敢肯定有些字体会使用其他类型的字体)我还没有实施)。
但是,我没有花时间优化/调整连字解析。 我做了一些快速测试,看起来对于中等长度的字符串(连读:1行),解析连字需要2-20ms。 还有很多优化空间,因此我现在并不担心。 我主要是想通过这个来演示界面,让人们愿意的话。
看起来很酷@princjef! 您如何考虑将测试添加到Fira代码中的0xc0ffee
, 0x1234
和17x32
? ( x
变成了那些符号)
@princjef太棒了!
我做了一些快速测试,看起来对于中等长度的字符串,解析连字需要2-20ms(阅读:1行)
您能否指出一些检查此内容的关键代码?
@ j-f1也可以进行这些工作: https :
@Tyriar我刚刚添加了可以使用的基本基准。 呼叫模式看起来像node bench/lines.js <font-name> <input-text> [iterations]
。 您还可以传递多行字符串或扩展文本的输入文件,它将在各行之间循环,以尝试避免不切实际的优化重复运行完全相同的输入。
在撰写本文时,我注意到即使我使用多个不同的输入行,它在第一次运行后仍会显着提高性能。 对于大约10个字符的输入,我看到Iosevka的平均时间为一毫秒的一部分,而Fira Code的平均时间为半毫秒多一点。 我遇到了特殊情况,或者涡轮风扇正在工作,这很神奇。 它仍然不能按原样使用,但接下来我将开始关注性能优化(在这一点上,我可能还会添加更好的基准以了解改进之处)。
几个注意事项:
我已经开始在我创建的包(https://github.com/princjef/font-ligatures/issues/2)中的一个问题中跟踪性能方面。 这是从那里复制的一些配置的初始数字(所有数字都是以毫秒为单位的时间)。 前五个数字列是每行输入,后两列是每个字符。 第二列是我最关注的列。 我每个角色的拍摄时间约为0.5微秒(毫秒为0.0005):
NAME | AVG | STDEV | 5%| 50%| 95%| AVG(CHAR)| STDEV(字符)
----------------------- | ------- | --------- | ------ | -------- | ------- | ------------- | ----------------
Fira代码:code.txt | 5.9570 | 12.6951 | 0.5270 | 5.1020 | 12.2330 | 0.1443531 | 0.2091743
Fira代码:noLigatures.txt | 12.1932 | 3.4402 | 8.1420 | 12.1205 | 15.5900 | 0.1321094 | 0.0334362
Iosevka:code.txt | 0.5571 | 1.4722 | 0.0485 | 0.3215 | 1.6155 | 0.0135005 | 0.0333483
Iosevka:noLigatures.txt | 0.7476 | 0.4230 | 0.4365 | 0.6030 | 1.7725 | 0.0080998 | 0.0044501
Monoid:code.txt | 0.8896 | 1.6637 | 0.0910 | 0.6625 | 1.9225 | 0.0215566 | 0.0482166
Monoid:noLigatures.txt | 1.6661 | 0.6935 | 1.0695 | 1.4450 | 2.6910 | 0.0180521 | 0.0071922
Ubuntu Mono:code.txt | 0.0402 | 0.3935 | 0.0080 | 0.0220 | 0.0605 | 0.0009735 | 0.0090228
Ubuntu Mono:noLigatures.txt | 0.0356 | 0.0644 | 0.0120 | 0.0280 | 0.0805 | 0.0003858 | 0.0006891
现在有了良好的基准数据,我们将更好地了解每次性能调整带来的收益。
@Tyriar您是否偏爱xterm-ligature-support
软件包的住处以及如何到达那里?
似乎您认为它应该属于xtermjs org(对我来说合理),但我无法在org中创建/推送到存储库。 您是希望将它放在迁移到组织中的用户下的回购中,还是要创建我可以针对其提交PR的存根回购?
从审查的角度来看,首先完成#1460是有意义的,所以不要着急,但是我想弄清楚一旦准备好就可以在哪里转储代码。
@princjef我创建了https://github.com/xtermjs/xterm-ligature-support,并为您提供了管理员访问权限。 我假设您已经看过其他插件的工作原理,但这将是第一个正式的外部插件。 因此,请使用内部插件和https://github.com/CoderPad/xterm-webfont作为实现的参考😄
我会尽快检查PR👍
在https://github.com/microsoft/vscode/issues/34103的vscode存储库中发布了更新,这是在xterm.js中将其关闭之前的剩余工作:
谢谢大家的辛勤工作! 👍
如果我要问@Tyriar ,是否有计划支持Web浏览器?
我还看到这可以在浏览器中工作,但是速度会非常慢。 如果我想问一下,这个版本在浏览器中的运行速度有多慢?
谢谢!
@ torch2424我不认为渲染器的工作方式是可行的,因为连字支持依赖于解析字体文件(没有像用户提供的连字一样的硬编码)。
@Tyriar感谢您的快速回复!
不幸的是,这真是太好了。 我们一直在考虑电子版本,所以也许我们会将其作为附带功能😄谢谢!
嗯,我认为应该有可能,方法是使用webfont并将相同的字体文件(urgh)加载到JS领域中以提取连字数据。 不确定这样做是否可行/值得这样做,因为结扎提取对性能的影响很大。 不确定内存使用情况,字体文件可能会很大,也许@princjef在此处提供了一些有关运行时行为的信息?
自从我研究它已经有一段时间了,但是我的回忆是,没有内置的API可以在浏览器中提取原始字体信息,甚至对于Web字体也是如此。
如果要从文件中手动加载自己的Web字体,并将同一个文件的内容分别注入代码中以分析连字,那么从理论上讲它是可行的,而不必放弃渲染器中的字形缓存优化。 也就是说,现有的插件在设计时就没有考虑到该用例,因为与非浏览器用例相比,它需要更多的协调和手动接线。
不确定这样做是否可行/值得这样做,因为结扎提取对性能的影响很大。 不确定内存使用情况,字体文件可能会变得很大
对于某些字体,这绝对是一个问题。 连字处理程序包已针对查找/检测效率进行了优化,目前以较长的加载时间和内存消耗为代价。 字体因字体而异,但是请牢记这一点。
即使可以提取连字信息,Web API也会使用文本/字符代码点,而字体内的连字则使用特定于字体的字形索引,这些字形索引无法直接传递给Web API进行绘图。
@princjef Thx要
@khaledhosny这个想法更多的是关于从JS中的字体获取连字信息,同时仍使用代码点并让浏览器字体渲染器执行低级操作(假设它使用相同的字体)。 不知道是否也可以仅在JS中完成字形提取和自己的渲染(大声笑,一个基于JS的字体渲染器?即使这样做可行,恕我直言,它的性能也会很差)。
对此进行更新,我只是将连字插件合并到代码库中(https://github.com/xtermjs/xterm.js/pull/2847),它可能仍然有些破损,但是如果没有集成测试设置,很难分辨( https://github.com/xtermjs/xterm.js/issues/2896)。
当前,该插件仅在浏览器+节点运行时(即电子)中运行,我提出了一个建议,我希望仅在浏览器中工作,这将使我们删除节点deps并将其带入VS Code(https:/ /github.com/microsoft/vscode/issues/34103)。 如果有人想给它一个镜头,它上面贴着想要帮助的标签,网址为https://github.com/xtermjs/xterm.js/issues/2897。
我们应该研究将Font Access API (当前在原始语言试用版中)用于连字插件。
我正在使用ttyd ,它通过网络共享终端,并使用xterm.js。 正如您在下图中看到的,图标未正确加载。 它们在原始终端中可见。 但在网络上却不见了。
@UziTech哦,哇,太棒了! 我认为在此领域完成的任何工作都应向前看,以便我们可以将其与字体访问API结合使用。
@UziTech @泰里亚尔@princjef
我认为字体访问API的代码可以放在font-ligatures
包中。
在检测到进程是在浏览器中还是在节点/电子中之后,它可以决定是调用字体访问API还是使用当前方法。
我创建了一个hacky概念证明,并在我的fork (localFonts分支)的演示中运行了它。
您可以在chrome://flags
启用#font-access
后尝试一下(允许访问字体后刷新一次)
如果您觉得不错,我可以尝试打开公关公司。
在检测到进程是在浏览器中还是在节点/电子中之后,它可以决定是调用字体访问API还是使用当前方法。
我们最终将遇到该解决方案的问题,因为仅Web项目会在捆绑节点部门时遇到问题。 我没有答案,但是我也认为如果功能检测成功,我们应该翻转默认设置(最终是?),并且默认使用字体访问,否则回退。
让它正常工作也很棒! 太棒了😍
仅当需要时,我们才能在特征检测之后将它们设置require
。
依赖于Web的项目可以在捆绑期间将其标记为外部。
我想,一旦跨浏览器都可以使用字体访问API,我们便可以将其作为默认设置。
you当您提到存在解决方法时,我可能对捆绑程序的关注有所考虑。 我希望一旦在Electron中打开字体访问功能,我们将弃用/淘汰Electron选项。
我们@Tyriar可以得到连写插件用的版本更新中字体取景器快?
@UziTech [email protected]
应该有这个功能,我创建了一个提醒来修改4.10的版本https://github.com/xtermjs/xterm.js/issues/3220
我已打开pr princjef / font-ligatures#22作为完成此操作的第一步
最有用的评论
我认为我们对常规的连字不感兴趣(实际上,对于
li
等启用连字会很不好),但是对于==
,!==
,=>
,依此类推。 这是fira代码等宽字体支持的连字的不错列表:https://github.com/tonsky/FiraCode/blob/master/showcases/all_ligatures.png