Xterm.js: Prise en charge des ligatures de polices

Créé le 8 sept. 2017  ·  54Commentaires  ·  Source: xtermjs/xterm.js

Support en cours de suppression dans https://github.com/sourcelair/xterm.js/pull/938

C'est certainement encore possible, le moteur de rendu doit cependant savoir quels personnages rejoindre.

areapi arerenderer help wanted typenhancement

Commentaire le plus utile

Je pense que nous ne sommes pas intéressés par les ligatures régulières (en fait, ce serait mal d'activer les ligatures pour li et autres), mais pour des choses comme == , !== , => et ainsi de suite. Voici une belle liste de ligatures supportées par la police fira code monospace:
https://github.com/tonsky/FiraCode/blob/master/showcases/all_ligatures.png

Tous les 54 commentaires

Je pense que nous ne sommes pas intéressés par les ligatures régulières (en fait, ce serait mal d'activer les ligatures pour li et autres), mais pour des choses comme == , !== , => et ainsi de suite. Voici une belle liste de ligatures supportées par la police fira code monospace:
https://github.com/tonsky/FiraCode/blob/master/showcases/all_ligatures.png

Que se passerait-il si la moitié de la ligature était d'une couleur différente? Comment géreriez-vous cela?

@LoganDark est-ce que cela fonctionne même avec des ligatures régulières? Ou sont-ils séparés quand ils sont de couleurs différentes?

Non et non.

Je me demande s'il serait possible d'extraire le code de rendu de txtjs, car ils ont compris comment rendre les ligatures, bien que je pense qu'ils dessinent manuellement le texte. http://txtjs.com/examples/Text/ligatures.html

@devsnek Je ne pense pas que ce soit un problème pour le rendu du texte. Le problème est de savoir quel caractère se joint pour pouvoir être dessiné ensemble (actuellement, "==" est dessiné comme "=" et "=", pas "==").

@Tyriar ne serait pas le moteur de rendu des polices sans notre intervention

@devsnek oui, mais chaque cellule de la grille est dessinée individuellement à quelques exceptions près (emojis, caractères unicode larges). Les ligatures doivent en quelque sorte être incluses dans cette liste. Regardez https://github.com/sourcelair/xterm.js/pull/938 pour plus de contexte

@devsnek C'EST VOUS

avertissement: complètement hors sujet, juste un commentaire aléatoire

@LoganDark est-ce que cela fonctionne même avec des ligatures régulières? Ou sont-ils séparés quand ils sont de couleurs différentes?

Si nous allons par la façon dont les autres émulateurs les manipuler, ils se séparer si elles sont différentes couleurs, comme on pouvait s'y attendre. C'est presque une exigence car cela permet aux symboles d'être correctement représentés par certains surligneurs de langue dans ViM, par exemple.

Je pense qu'il est tout à fait acceptable d'afficher les symboles individuels si le mode de rendu n'est pas le même pour tous les caractères sous-jacents.

@ Qix- Ma suggestion serait alors de dessiner tout le texte à la fois, puis de colorier en post. Cela éliminerait tout problème avec les ligatures et ne nécessiterait pas de détecter les paires de ligatures (bien que cela briserait la compatibilité avec les polices à largeur variable, ou même les polices à espacement unique qui sont légèrement décalées / n'ont pas de largeurs entières)

Les ligatures multicolores

Ouais, je ne pense pas que les ligatures multicolores fonctionneraient. Cela va également à l'encontre de la façon dont ils fonctionnent en dessous, où un seul glyphe est dessiné au début, pas plusieurs.

Pour clarifier, cela attend une bonne solution pour détecter quelles séquences de caractères ont des ligatures. Pour faire cela correctement, cela impliquerait probablement un code de bas niveau qui vérifie les fichiers de polices (et devrait donc être un module de nœud natif et ne pas fonctionner pour les consommateurs Web), je ne pense pas que ces informations soient exposées à la plate-forme Web.

Maintenant que la version 2.0.0 est stable, les solutions de contournement de ligature ont peut-être besoin d'une priorité plus élevée.

Déterminer manuellement les mappages de glyphes est un problème difficile à résoudre. D'après ce que je peux dire, en faire une expérience décente, il faudrait ce qui suit:

  1. Mappez la famille de polices sélectionnée vers le fichier / tampon contenant les données de police réelles (otf / ttf / woff / etc)
  2. Analysez les données de la table GSUB de la police et traduisez-les en un ensemble judicieux de règles pour le remplacement des glyphes
  3. Passez une sorte de mappage ou de fonction de mappage à xterm pour déterminer ce qu'il faut rendre pour une séquence de caractères donnée

J'ai fait quelques recherches initiales avec Fira Code (en particulier sa variante de police nerd) pour essayer de comprendre à quel point chaque étape pourrait être difficile. Je n'ai pas encore décidé si je me sens suffisamment ambitieux (ou si je me soucie suffisamment des ligatures de polices) pour accepter cela, mais voici ce que j'ai trouvé pour que les connaissances ne soient pas perdues:

  • Il n'y a aucun moyen que je puisse trouver pour récupérer les données de police à l'aide des API de navigateur, donc cela ne fonctionnera pas comme une fonctionnalité directe de xterm.js, mais plus probablement comme un package / extension séparé avec un hook exposé par xterm.js

  • Mapper le nom CSS font-family d'une police à son fichier de police dans Windows est douloureux mais semble faisable. Jusqu'à présent, le seul moyen que j'ai trouvé est de tout récupérer dans %WINDIR%\Fonts et d'analyser tous les fichiers que je trouve (spoiler: c'est vraiment lent). Je n'ai pas encore essayé d'autres plates-formes. (Remarque: j'ai également essayé de supprimer le nom du registre, mais le nom ne correspond pas à certaines polices telles que celles des polices nerd. Elles utilisent une famille et une sous-famille "préférées" qui ne sont pas reprises dans le nom du registre. mais est utilisée dans le css font-family . Si vous êtes curieux, la clé de registre se trouve dans HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts )

  • Il existe une bibliothèque appelée opentype.js qui effectue une analyse complète des tables de polices OpenType et a même une fonction font.stringToGlyphs(str) qui gère les ligatures de base, mais les ligatures pour Fira Code (et plusieurs sinon toutes les autres polices de ligatures courantes) utilisez une fonctionnalité appelée alternatives contextuelles qui n'est pas encore prise en charge par opentype.js (répertoriée sous Planifié ). La table GSUB nécessaire est cependant analysée en JSON pour vous, donc théoriquement, tout ce qui manque est l'interprétation des données de la table.

  • Les ligatures Fira Code (et je pense que d'autres) remplacent en fait les glyphes d'origine par un nombre égal de glyphes, plutôt qu'un seul extra large (pour conserver les propriétés de la police monospace). Pour une chaîne comme ==> , la police finira par vous dire de la remplacer par deux caractères "LIG" (essentiellement un espace vide), suivis du glyphe réel pour la ligature, qui n'est techniquement encore qu'un seul monospace caractère large. Bien qu'il soit apparemment de largeur unique, le chemin du dernier caractère s'étend au-delà du côté gauche de la boîte englobante du personnage pour couvrir l'espace occupé par les deux caractères LIG avant lui. Voir ci-dessous pour un visuel (0 et 600 sont les côtés de la boîte du personnage). Je ne sais pas si cela complique la tâche du moteur de rendu ou s'il devrait être transformé avant d'être passé à xterm.js, mais il faut en être conscient.

image

  • Un autre problème est de déterminer quand réévaluer la ligature. Par exemple, si je tape = quatre fois de suite, le comportement souhaité serait pour moi de voir un simple égal, puis une double ligature égale, puis une triple ligature égale, puis quatre signes égaux séparés. Il y a en fait des mappages dans les règles alternatives contextuelles pour effacer la ligature (c'est-à-dire si l'entrée actuelle est '=' et que les trois caractères précédents sont '===', ne le remappez pas du tout), mais nous aurions pour savoir comment appliquer ces règles.

  • OpenType est compliqué. Certes, je ne suis pas un expert en rendu de polices, mais le nombre de variations possibles menant à différents types de rendu est assez important. Sans une bibliothèque intégrée qui effectue le mappage pour nous, je pense que la manière la plus raisonnable d'attaquer cela est de manière incrémentielle. Fira Code utilise spécifiquement le format 3 de substitution de contexte de chaînage , mais je suis sûr qu'il existe d'autres polices populaires qui utilisent des polices différentes. Comme chacun a une sémantique légèrement différente, il est probablement logique de commencer par un et de partir de là.

@princjef Merci d'avoir partagé vos explorations, vraiment très utiles! J'ai également réfléchi à ce sujet il y a quelques jours et je suis arrivé à la conclusion suivante:

  • Détecter les ligatures dans les polices Web à l'aide d'une API intégrée semble impossible (comme vous le décrivez)
  • Il y a certaines ligatures qui n'ont pas de sens dans un terminal, même si la police le prend en charge (par exemple li )
  • Il existe un très petit sous-ensemble de ligatures qu'il est logique de prendre en charge, à savoir la plupart des ligatures Fira Code.
  • L'ajout de la prise en charge du dessin et de la suppression d'un caractère qui s'étend sur plusieurs cellules est très difficile à implémenter avec notre approche actuelle de rendu basée sur un seul caractère (CharAtlas).

TBH, je ne pense pas que cela vaille la peine de supporter les ligatures dans l'état actuel 😔

@mofux Je pense en fait que j'ai trouvé un moyen (quelque peu acceptable) de rendre les ligatures dans xterm.js en l'abordant sous un angle différent. J'ai en quelque sorte manqué que la toile rendra automatiquement les ligatures pour vous dans mes recherches initiales. Soutenir les ligatures devient une question de s'assurer que les caractères pertinents sont rendus ensemble.

À cette fin, j'ai peaufiné le rendu de texte pour rendre les caractères avec des attributs identiques (fg, bg, etc.) en un seul groupe. Cela ne rendra pas toutes les ligatures correctement (et pourrait en rendre certaines qui ne devraient pas l'être), mais cela devrait rendre une ligature partout où quelqu'un s'attendrait à en voir une. Voici une capture d'écran de NeoVIM dans l'application de démonstration utilisant Fira Code (montré dans Firefox, fonctionne également dans Chrome mais pas Edge):

image

Branch est ici si les gens veulent jeter un coup d'œil: https://github.com/princjef/xterm.js/tree/ligature-support

Quelques notes à ce sujet:

  • Je n'ai pas fait de benchmarking, mais je parie que ce ne sera pas bon pour la performance. En regroupant tous les personnages de même style, l'atlas des personnages est essentiellement jeté par la fenêtre, même pour les endroits où il n'y a pas de ligatures (car nous ne savons pas où ils seront / ne seront pas). Lorsque je rend plusieurs caractères ensemble, je règle simplement le code de caractère sur Infinity pour m'assurer d'éviter toute mise en cache.
  • Il y a probablement des cas de bord autour de la largeur et du chevauchement des caractères que je ne gère pas correctement. Il s'agit principalement d'une preuve de concept à ce stade.

Qu'en est-il du rendu du texte à l'aide de l'atlas de caractères, puis du rendu dans le fond en tant que bloc de texte en veille? Si les deux aboutissent à la même image, vous pouvez jeter le texte combiné et revenir à l'atlas. En divisant les chaînes de texte en arrière-plan, il peut être possible de savoir quelles chaînes de texte sont ligaturées.

La partie la plus délicate est que le rendu d'une ligature dépend non seulement des caractères remplacés par la ligature mais aussi de leur contexte. Par exemple, «=== 1» devrait rendre les trois signes égaux comme une ligature mais «====» devrait rendre les trois mêmes signes égaux sous forme de caractères séparés. Il n'y a pas de limite à la taille de ce contexte, il serait donc difficile et probablement sujet aux erreurs de déterminer les règles de rendu d'une ligature uniquement à partir de sa sortie.

Une approche plus fiable (mais moins portable) consiste à avoir des indications sur les plages de ligatures fournies par une fonction distincte qui connaît les métadonnées de police. Ensuite, tout sauf les plages fournies par la fonction externe peut être rendu en utilisant l'atlas, tandis que les groupes donnés pourraient utiliser une approche comme celle ci-dessus. Déterminer les emplacements des substitutions à partir d'une ligne de texte devrait être assez rapide mais présente certains des problèmes que j'ai détaillés précédemment (principalement la vitesse / fiabilité de trouver la bonne police lors de l'initialisation et la complexité du traitement des alternatives contextuelles OpenType).

Serait-il raisonnable d'avoir un paramètre pour activer les ligatures, qui écrit
une ligne entière à la fois vers le terminal? Il semble que ce serait
garantir un rendu correct, et l'atteinte des performances serait un opt-in pour
les gens qui se soucient plus des ligatures que de la vitesse.

Le dimanche 22 avril 2018, 16:21, Jeff Principe [email protected] a écrit:

La partie délicate avec cela est que le rendu d'une ligature dépend
non seulement sur les caractères remplacés par la ligature mais aussi sur leur contexte.
Par exemple, '=== 1' devrait rendre les trois signes égaux comme une ligature mais
'====' doit rendre les trois mêmes signes égaux sous forme de caractères séparés.
Il n'y a pas de limite à l'ampleur de ce contexte, donc ce serait difficile et
probablement sujet aux erreurs pour déterminer les règles du moment où une ligature est rendue
juste à partir de sa sortie.

Une approche plus fiable (mais moins portable) consiste à avoir des indices sur
plages de ligatures fournies par une fonction distincte qui connaît la police
métadonnées. Ensuite, tout sauf les plages fournies par la fonction externe
peut être rendu en utilisant l'atlas, tandis que les groupes donnés pourraient utiliser un
approche comme celle ci-dessus. Déterminer les emplacements des substitutions
donné une ligne de texte devrait être assez rapide mais a certains des problèmes que je
détaillé plus tôt (principalement la vitesse / fiabilité de trouver la bonne police sur
initialisation et complexité du traitement des alternatives contextuelles OpenType).

-
Vous recevez ceci parce que vous êtes abonné à ce fil.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/xtermjs/xterm.js/issues/958#issuecomment-383420281 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAKyryMlayIQijY32GpWBmpvCUi13Wfbks5trRBigaJpZM4PRej6
.

@princjef Wow, vos modifications sont si faciles à suivre et il semble que xterm puisse prendre en charge les ligatures avec le moteur de rendu. L'astuce consiste simplement à déterminer comment cartographier les règles. Cela me donne de l'espoir.

@princjef grande enquête!

Il n'y a aucun moyen que je puisse trouver pour récupérer les données de police à l'aide des API de navigateur, donc cela ne fonctionnera pas comme une fonctionnalité directe de xterm.js, mais plus probablement comme un package / extension séparé avec un hook exposé par xterm.js

@princjef Je vois un éventuel support de ligature vivant comme:

  • some-magical-package : Un module de nœud natif extrait les informations de police natives, mappant les chaînes de polices Web aux fichiers si possible. Cela pourrait être fait dans un AsyncWorker pour réduire les performances. Ce n'est pas grave si cela est fait paresseusement et au premier lancement, il faut plusieurs secondes pour scanner et faire un rafraîchissement.
  • xtermjs/xterm-ligature-support : Un addon qui dépend du nœud et utilise some-magical-package pour obtenir et mettre en cache les informations de police. Cet addon pourrait effectuer une analyse chaque fois que des polices non reconnues sont détectées dans le répertoire des polices et expulser les polices lorsqu'elles sont supprimées. J'attends quelque chose comme ça en tant qu'API approximative:

    /** Returns a list of characters to be drawn together */
    export function getLigatures(fontFamily: string): string[] { ... }
    

Il y a certaines ligatures qui n'ont pas de sens dans un terminal, même si la police le prend en charge (par exemple li)

@mofux Je ne suis pas sûr que nous devions nous inquiéter à ce sujet? Si l'utilisateur demande des ligatures, ne devrions-nous pas les rendre tous?

L'ajout de la prise en charge du dessin et de la suppression d'un caractère qui s'étend sur plusieurs cellules est très difficile à implémenter avec notre approche actuelle de rendu basée sur un seul caractère (CharAtlas).

@mofux Nous devrions pouvoir ajouter assez facilement une fonction pour dessiner ensemble un ensemble de caractères adjacents.

@princjef : Je n'ai pas fait de benchmarking, mais je parie que ça ne va pas être bon pour les performances.

@wavebeem : Serait-il raisonnable d'avoir un paramètre pour activer les ligatures, qui écrit une ligne entière à la fois sur le terminal?

Je m'attends à ce que cela annule presque complètement les améliorations de performances associées à l'utilisation du canevas. Aussi, je veux garder le nombre d'options au minimum, nous devrions essayer d'arriver à un endroit où les ligatures ne fonctionnent que lorsqu'un addon est inclus pour ajouter un support.

Également en ce qui concerne les performances, je travaillerai probablement sur l'ajout d'une option de rendu DOM de secours dans les mois à venir, car il y a trop de choses qui peuvent mal tourner avec le support GPU dans Chromium. Voir https://github.com/xtermjs/xterm.js/issues/1360. Les ligatures fonctionneront directement dans ce mode.

Qu'en est-il du rendu du texte à l'aide de l'atlas de caractères, puis du rendu dans le fond en tant que bloc de texte en veille? Si les deux aboutissent à la même image, vous pouvez jeter le texte combiné et revenir à l'atlas.

@ j-f1 c'est plus difficile qu'il n'y paraît. Même si les caractères sont rendus identiques, le second sera différent car l'espacement dans l'atlas de caractères est différent (les caractères sont toujours dessinés sur un nombre rond). Nous aurions besoin de faire beaucoup plus de rendu pour que cela fonctionne et beaucoup de pixels différents, ce qui coûte cher.

@Tyriar Je pense que la conception générale que vous avez décrite est logique. Nous _pourrions_ être en mesure de nous en sortir avec quelque chose qui ne dépend pas du code natif pour trouver les polices dans some-magical-package , mais cela dépendra certainement de la plate-forme / du système de fichiers. J'ai commencé à jouer avec l'analyse des substitutions contextuelles d'alternatives, mais il est difficile de dire combien il faudra de plus pour bien faire les choses.

Je pense aussi que nous finirons par avoir besoin d'une interface légèrement différente de some-magical-package :

export function getSubstitutionRanges(fontFamily: string, text: string): Promise<[number, number][]>;

Les règles pour déterminer les ligatures elles-mêmes sont à la fois compliquées et profondément ancrées dans la police elle-même. Plutôt que de transmettre les données de police elles-mêmes et de mettre le fardeau de l'interpréter sur xterm.js, je laisserais cela à l'autre lib et lui demanderais d'indiquer à xterm.js quels caractères doivent être rendus ensemble. Les aspects lookahead / lookbehind du contexte compliquent également l'analyse. Par exemple, «===» correspond à une ligature, mais pas s'il est suivi d'un autre signe égal.

Une autre note sur le concept des plages de substitution: il n'y a pas de délimitation claire des limites d'une seule ligature d'après ce que je peux dire (du moins lors de l'utilisation de variantes contextuelles). Il n'y a que des séquences de substitutions appliquées à des caractères individuels. J'ai trouvé quelques astuces pour déterminer les limites si vous avez des ligatures consécutives, mais ce n'est probablement pas infaillible. J'aurais probablement tort de traiter accidentellement deux ligatures comme une seule plutôt que de les séparer accidentellement, car elles devraient toujours être rendues correctement si elles sont rendues toutes ensemble en un seul groupe. Le seul vrai problème est de lui appliquer des styles hétérogènes.

Le seul vrai problème est de lui appliquer des styles hétérogènes.

Ne le fais pas. Passez chaque chaîne de style continu à la fonction séparément. Vous pourrez peut- être faire une exception pour le texte souligné si le soulignement est dessiné séparément.

Nous pourrons peut-être nous en sortir avec quelque chose qui ne dépend pas du code natif

👍

Les règles pour déterminer les ligatures elles-mêmes sont à la fois compliquées et profondément ancrées dans la police elle-même. Plutôt que de transmettre les données de police elles-mêmes et de mettre le fardeau de l'interpréter sur xterm.js, je laisserais cela à l'autre lib et lui demanderais d'indiquer à xterm.js quels caractères doivent être rendus ensemble.

@princjef cela sonne encore mieux, moins xterm.js a à faire dans ce domaine, mieux c'est.

Le seul vrai problème est de lui appliquer des styles hétérogènes.

Je ne pense pas que quoi que ce soit d'autre tente de faire cela, nous ne devrions ajouter des ligatures que pour le texte qui utilise le même style.

Cela semble faisable du côté de la police. J'ai un code qui analyse avec succès toutes les ligatures du code Fira et fournit les bonnes plages pour les caractères à combiner. Si les gens ont une ou deux autres polices sur lesquelles ils recherchent une assistance, je peux essayer de les vérifier également. Jusqu'à présent, je n'ai implémenté que les types de substitution dont j'avais besoin pour Fira Code, donc une certaine variété serait la bienvenue pour exercer les autres types de substitution.

Encore faut-il comprendre la partie de recherche de police. Je vais me concentrer sur cela ensuite. Il y a quelques paquets là-bas mais ils semblent tous être bogués ou mal entretenus

@princjef Si vous souhaitez vérifier d'autres polices, j'utilise Iosevka .

D'accord, j'ai créé un package appelé font-ligatures (aka some-magical-package ) et quelques packages associés afin que nous puissions trouver efficacement la bonne police et ensuite déterminer où se trouvent les ligatures pour une entrée de texte donnée.

J'ai passé du temps à optimiser le processus de recherche de la police. Sur une Surface Pro 4 avec ~ 150 polices ttf / otf, je peux récupérer les métadonnées de police pour chacune d'entre elles en 300 à 400 ms. Il est principalement lié aux E / S et peut être renvoyé en arrière-plan pendant les premiers cycles de rendu pendant le chargement, mais devrait être suffisamment rapide pour être chargé au moment où un pty a démarré et crache du texte. Une fois qu'il est chargé, nous pouvons déclencher un rendu pour mettre à jour tout texte déjà présent. Cela peut être répété chaque fois que la police change ou nous pouvons mettre en cache la liste complète la première fois (je récupère la liste complète au début de toute façon).

En ce qui concerne le mappage de ligatures lui-même, la bibliothèque prend une chaîne et renvoie des métadonnées sur les ligatures de polices, y compris les groupes de caractères qui doivent être rendus ensemble. Le CI inclut des tests pour chaque ligature dans Fira Code, Iosevka et Monoid, donc je suis raisonnablement convaincu qu'il effectue le traitement correctement pour les types de substitution qu'il effectue (même si je suis sûr qu'il existe des polices qui utilisent d'autres types qui Je n'ai pas implémenté).

Cependant, je n'ai passé aucun temps à optimiser / régler l'analyse des ligatures. J'ai fait quelques tests rapides et il semble que l'analyse des ligatures prend 2 à 20 ms pour une chaîne de longueur moyenne (lire: 1 ligne). Il y a encore beaucoup de marge d'optimisation donc je ne suis pas trop inquiet pour le moment. Je voulais surtout le sortir pour démontrer l'interface et laisser les gens botter les pneus s'ils le veulent.

Ça a l'air plutôt cool @princjef! Que pensez-vous de l'ajout de tests au code Fira pour 0xc0ffee , 0x1234 et 17x32 ? (Le x se transforme en signe de temps sur ceux-ci)

@princjef génial!

J'ai fait quelques tests rapides et il semble que l'analyse des ligatures prend 2 à 20 ms pour une chaîne de longueur moyenne (lire: 1 ligne)

Pouvez-vous m'indiquer certains des codes critiques qui vérifient cela?

@ j-f1 Oui, cela fonctionne aussi: https://github.com/princjef/font-ligatures/blob/master/src/index.spec.ts#L136 -L137

@Tyriar Je viens d'ajouter une référence de base avec laquelle vous pouvez jouer. le modèle d'appel ressemble à node bench/lines.js <font-name> <input-text> [iterations] . Vous pouvez également passer une chaîne multiligne ou développer un fichier d'entrée pour le texte et il passera en revue les lignes pour essayer d'éviter que des optimisations irréalistes exécutent la même entrée à plusieurs reprises.

En écrivant cela, j'ai remarqué que même lorsque j'utilise plusieurs lignes d'entrée différentes, les performances augmentent considérablement après la première exécution. Pour ~ 10 entrées de caractères, je vois des moyennes d'une fraction de milliseconde pour Iosevka et d'un peu plus d'une demi-milliseconde pour Fira Code. Soit je rencontre un cas particulier, soit Turbofan fonctionne, c'est magique. Ce n'est toujours pas assez efficace pour être utilisé tel quel, mais je commencerai ensuite à me concentrer sur les optimisations des performances (à quel point j'ajouterai probablement un meilleur benchmark pour avoir une idée des améliorations).

Quelques remarques:

  • En raison de la façon dont les remplacements fonctionnent, je m'attendrais à ce que le temps d'exécution soit mis à l'échelle linéairement avec la taille de l'entrée, bien que je ne l'ai pas vérifié
  • En raison du nombre de ligatures et du fonctionnement des remplacements, Fira Code est beaucoup plus performant à analyser que Iosevka ou Monoid. Je vois régulièrement qu'il faut 5 à 10 fois plus de temps pour faire Fira Code que Iosevka.
  • Les polices sans ligatures fonctionnent beaucoup plus rapidement et peuvent être encore optimisées. S'il n'y a pas d'alternatives contextuelles dans la police, je peux faire une sortie rapide avec un jeu de résultats vide (ou nous pouvons simplement contourner l'appel à un niveau supérieur).

J'ai commencé à suivre l'aspect des performances dans un problème dans le package que j'ai créé (https://github.com/princjef/font-ligatures/issues/2). Voici les nombres initiaux copiés à partir de là pour quelques configurations (tous les nombres sont des temps en ms). Les cinq premières colonnes de nombres sont par ligne d'entrée et les deux dernières par caractère. L'avant-dernière colonne est celle à laquelle je porte le plus d'attention. Je tourne pendant environ 0,5 microseconde par caractère (0,0005 en millisecondes):

NOM | AVG | STDEV | 5% | 50% | 95% | AVG (CHAR) | STDEV (CHAR)
----------------------- | ------- | --------- | ------ | -------- | ------- | ------------- | ----------------
Code Fira: code.txt | 5,9570 | 12,6951 | 0,5270 | 5.1020 | 12,2330 | 0,1443531 | 0.2091743
Code 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
Monoïde: code.txt | 0,8896 | 1,6637 | 0,0910 | 0,6625 | 1,9225 | 0,0215566 | 0,0482166
Monoïde: 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

Maintenant qu'il existe de bonnes données de base, nous aurons une meilleure idée des gains réalisés avec chaque ajustement des performances.

@Tyriar avez-vous une préférence pour l'emplacement du package xterm-ligature-support et comment il y parvient?

Il semble que vous pensez qu'il devrait passer sous l'organisation xtermjs (ce qui me semble raisonnable), mais je n'ai pas la possibilité de créer / pousser vers un référentiel dans l'organisation. Préférez-vous que je le place dans un dépôt sous mon utilisateur qui migre dans l'organisation ou souhaitez-vous créer un dépôt de stub auquel je peux soumettre un PR?

Du point de vue de la révision, il est logique de finaliser d'abord # 1460, donc pas de précipitation, mais je veux savoir où vider le code une fois qu'il est prêt.

@princjef J'ai créé https://github.com/xtermjs/xterm-ligature-support et vous ai donné un accès administrateur. Je suppose que vous avez vu comment les autres addons fonctionnent mais ce sera le premier addon externe officiel. Utilisez donc les addons internes et https://github.com/CoderPad/xterm-webfont comme référence pour l'implémentation 😄

Je vais bientôt consulter le PR 👍

Publié une mise à jour dans le dépôt vscode sur ce https://github.com/microsoft/vscode/issues/34103 , voici le travail restant avant de pouvoir appeler cela fermé dans xterm.js:

  • Intégrez xtermjs / xterm-addon-ligatures dans le repo xtermjs / xterm.js , cela permettra une publication automatisée et garantira que les tests continuent de réussir
  • Branchez des ligatures dans la démo
  • Mettre en place des tests de marionnettiste qui vérifient sur tous les moteurs de rendu (dom, canvas, webgl) que les ligatures fonctionnent
  • Réduisez au maximum les dépendances

Merci pour tout le travail acharné ici tout le monde! 😄 👍

Si je peux demander, @Tyriar , existe-t-il des plans pour la prise en charge du navigateur Web?

J'ai également vu que cela pouvait fonctionner dans le navigateur, mais ce serait très lent. Si je peux demander, quelle était la lenteur de cette version qui fonctionnait dans le navigateur?

Merci!

@ torch2424 Je ne pense pas que ce soit possible avec la façon dont les moteurs de rendu fonctionnent car le support de ligature repose sur l'analyse du fichier de police (sans un code en dur comme les ligatures disponibles fournies par l'utilisateur).

@Tyriar Merci pour la réponse rapide!

C'est malheureux, mais c'était plus agréable à avoir. Nous avons envisagé une version électronique, alors peut-être que nous l'aurons comme fonctionnalité incluse 😄 Merci!

Hmm, je pense que cela devrait être possible, soit en utilisant une police Web et en chargeant les mêmes fichiers de polices (urgh) dans les royaumes JS pour extraire les données de ligature. Je ne sais pas si cela est faisable / vaut la peine de le faire de cette façon, car l'extraction de la ligature est une grosse entaille dans les performances. Vous n'êtes pas sûr de l'utilisation de mem, un fichier de police peut devenir assez gros, peut-être que @princjef a ici quelques chiffres sur le comportement d'exécution?

Cela fait un moment que je ne l'ai pas examiné, mais je me souviens qu'il n'y avait pas d'API intégrées pour extraire les informations de police brutes dans le navigateur, même pour les polices Web.

Si vous deviez charger manuellement votre propre police Web à partir d'un fichier et injecter séparément le contenu du même fichier dans le code d'analyse des ligatures, c'est théoriquement faisable sans avoir à abandonner les optimisations de mise en cache des glyphes dans le moteur de rendu. Cela dit, l'addon existant n'est pas conçu avec ce cas d'utilisation à l'esprit, car il nécessite plus de coordination et de câblage manuel que le cas sans navigateur.

Je ne sais pas si cela est faisable / vaut la peine de le faire de cette façon, car l'extraction de la ligature est une grosse entaille dans les performances. Pas sûr de l'utilisation de mem, un fichier de police peut devenir assez gros

Cela peut certainement être un problème pour certaines polices. Le package de traitement des ligatures est fortement optimisé pour l'efficacité de la recherche / détection, ce qui pour l'instant se fait au prix de temps de chargement et de consommation de mémoire plus longs. Cela variera considérablement d'une police à l'autre, mais c'est une bonne considération à garder à l'esprit.

Même si l'extraction des informations de ligature était possible, l'API Web utilise des points de code texte / caractère, tandis que les ligatures à l'intérieur de la police utilisent des index de glyphe spécifiques à la police qui ne peuvent pas être transmis directement aux API Web pour le dessin.

@princjef Thx pour le heads-up, cela semble trop encombrant, je n'en ai pas la peine pour le bénéfice qu'il donne ensuite.

@khaledhosny L'idée était plus d'obtenir les informations de ligature des polices dans JS tout en travaillant avec des points de code et de laisser le moteur de rendu de polices du navigateur faire le travail de bas niveau (étant donné qu'il utilise les mêmes polices). Je ne sais pas si l'extraction de glyphes et le propre rendu seraient même possibles uniquement en JS (lol, un rendu de polices basé sur JS? Même si cela était faisable, à mon humble avis, les performances seraient vraiment mauvaises).

Mise à jour à ce sujet, je viens de fusionner l'addon des ligatures dans la base de code (https://github.com/xtermjs/xterm.js/pull/2847), cela peut encore être un peu cassé mais c'est difficile à dire sans configuration des tests d'intégration ( https://github.com/xtermjs/xterm.js/issues/2896).

Actuellement, l'addon ne fonctionne que dans un navigateur + environnement d'exécution de nœud (c'est-à-dire électron), j'ai proposé une proposition qui, je m'attends à ne fonctionner que dans le navigateur, qui nous permettrait de supprimer le nœud deps et de l'introduire dans VS Code (https: / /github.com/microsoft/vscode/issues/34103). Il est étiqueté avec l'aide voulue si quelqu'un veut essayer https://github.com/xtermjs/xterm.js/issues/2897.

Nous devrions envisager d'utiliser l' API Font Access (actuellement en essai d'origine) pour l'addon ligatures.

J'utilise ttyd qui partage le terminal sur le Web et utilise xterm.js. comme vous le voyez dans l'image ci-dessous, les icônes ne sont pas chargées correctement. ils sont visibles dans le terminal d'origine. mais sur le web, ils manquent.

image

@UziTech oh wow, ça a l'air génial! Je pense que tout travail effectué dans ce domaine devrait être tourné vers l'avenir afin que nous puissions en tirer parti avec l'API d'accès aux polices.

@UziTech @Tyriar @princjef
Je pense que le code de l'API d'accès aux polices peut être placé dans des packages font-ligatures .
Après avoir détecté si le processus est dans un navigateur ou un nœud / électron, il peut décider d'appeler l'API d'accès aux polices ou d'utiliser la méthode actuelle.

J'ai créé une preuve de concept hacky et je l'ai lancée dans la démo à ma fourche (branche localFonts)
Screenshot 2021-01-17 at 18 39 27

Vous pouvez l'essayer après avoir activé #font-access dans chrome://flags (vous devez actualiser une fois après avoir autorisé l'accès aux polices)

Je peux essayer d'ouvrir des pr si cela vous convient.

Après avoir détecté si le processus est dans un navigateur ou un nœud / électron, il peut décider d'appeler l'API d'accès aux polices ou d'utiliser la méthode actuelle.

Nous finirons par rencontrer des problèmes avec cette solution car les projets qui sont uniquement Web auront des problèmes pour regrouper les nœuds. Je n'ai pas de réponse à cela, mais je pense aussi que nous devrions inverser les valeurs par défaut (éventuellement?) Et utiliser par défaut l'accès aux polices si la détection des fonctionnalités réussit, sinon le retour.

Excellent travail pour le faire fonctionner! C'est génial 😍

Nous pouvons les require après la détection des fonctionnalités uniquement si nécessaire.
Et les projets Web uniquement dépendants peuvent les marquer comme externes lors du regroupement.

Nous pouvons avoir l'API d'accès aux polices par défaut une fois qu'elle est disponible dans les navigateurs, je suppose.

👍 Je réfléchis peut-être trop au problème du bundler car vous mentionnez qu'il existe des solutions de contournement. Je pense que nous abandonnerions / supprimerions progressivement l'option Electron une fois que l'accès aux polices est activé dans Electron de toute façon.

@Tyriar pouvons-nous mise à

@UziTech [email protected] devrait l'avoir, j'ai créé un rappel pour changer la version pour 4.10 https://github.com/xtermjs/xterm.js/issues/3220

J'ai ouvert un pr princjef / font-ligatures # 22 comme première étape pour y parvenir

Cette page vous a été utile?
0 / 5 - 0 notes