Xterm.js: Le terminal ne rend pas les vraies couleurs

Créé le 16 janv. 2017  ·  20Commentaires  ·  Source: xtermjs/xterm.js

Commentaire le plus utile

Bonjour. Des mises à jour à ce sujet ? J'ai hâte que ça marche

Tous les 20 commentaires

Je ne peux pas attendre ça. J'ai piraté hterm pour essayer d'obtenir le support de truecolor, mais j'ai l'impression que c'est une bien meilleure option.

La mise en œuvre devra être effectuée ici https://github.com/sourcelair/xterm.js/blob/365a9f949cc1acfb6c4649ee1d85da3bbc60f928/src/InputHandler.ts#L1276

La partie délicate consiste à déterminer comment nous stockons les couleurs par rapport au(x) personnage(s), puis comment les rendre (probablement des attributs style ). Quelque chose comme https://github.com/sourcelair/xterm.js/pull/450 simplifierait probablement l'ajout des attributs.

J'y jetterai peut-être un coup d'œil quand j'aurai un peu de temps, mais je ne peux pas dire que je suis trop familier avec les séquences de contrôle.

J'ai jeté un œil à http://invisible-island.net/xterm/ctlseqs/ctlseqs.html mais je n'ai rien trouvé sur la vraie couleur ou la couleur 24 bits. Ai-je raté quelque chose, ou existe-t-il une autre ressource qui couvre cela?

@cnsumner xterm ne peut actuellement pas afficher les vraies couleurs mais prend en charge l'une des séquences d'échappement proposées. Vous pouvez en savoir plus à ce sujet ici : https://gist.github.com/XVilka/8346728
BTW, cela est en partie spécifié dans la norme ECMA-48.

Rassemblez une preuve de concept désordonnée pour avoir une meilleure idée de ce que nous devons faire ici https://github.com/Tyriar/xterm.js/tree/484_truecolor

image

Choses à faire :

  • La branche ajoute actuellement un autre numéro à chaque caractère représentant sa "vraie couleur" au format 0x1RRGGBB (fg) ou 0x0RRGGBB (bg), qui tient dans un entier de 32 bits
  • Il doit prendre en charge les couleurs fg et bg et être capable de mélanger les couleurs vraies et normales
  • curTrueColor est super moche
  • Soutenir l'inverse
  • Les drapeaux de couleur doivent être effacés lorsque les cellules sont réutilisées
  • Il est peut-être temps de repenser la façon dont les caractères sont encodés, le format actuel est :

    [attribute, character, width]
    
    • attribute : Un entier de 32 bits qui contient ascii fg, ascii bg et des drapeaux (gras, souligné, clignotement, inverse, invisible), tous les bits ne sont pas utilisés
    • char : Soit la chaîne vide (pour 0 caractères de largeur qui remplissent les caractères larges) ou une chaîne unicode à un seul caractère
    • width : La largeur du caractère, peut actuellement être 0, 1 ou 2 mais cela pourrait inclure plus pour prendre en charge correctement les onglets https://github.com/sourcelair/xterm.js/issues/734
  • La solution finale devrait être compacte pour la mémoire et également rapide d'accès, s'en tenir à un tableau, des drapeaux binaires et un décalage de bits pour les données est probablement la meilleure idée.

@Tyriar
Ouais l'utilisation de la mémoire va exploser si elle n'est pas optimisée pour une faible consommation. Peut-être qu'il peut être emballé avec width , il est peu probable que ce champ dépasse 16 en ne consommant que 4 octets (l'onglet par défaut est 4 ou 8 normalement). Cela laisse de la place pour une définition RVB* (en supposant que width est un entier de 32 bits). Je ne sais pas combien de bits sont libres dans attribute , peut-être qu'il peut y avoir la deuxième définition RVB .

Il semble que les attributs actuellement consommés 9 octets pour bg, 9 octets pour bg et 5 octets pour les drapeaux, laissant suffisamment de largeur à la fin. Les définitions RVB ont besoin de 24 octets (8*3) chacune.

Voici l'approche d'économie d'espace (légèrement compliquée) que je pense que vous suggérez :

[char, attr1, attr2]

Où attr1 est (29 bits) :

  • largeur : 4 bits
  • est de 256 couleurs ou drapeau truecolor : 1 bit
  • couleur bg : 24 bits

Et attr2 est (30 bits):

  • drapeaux : 5 bits
  • est de 256 couleurs ou drapeau truecolor : 1 bit
  • couleur fg : 24 bits

Une approche plus simple utiliserait un nombre spécifiquement pour les attributs :

[char, attr, truecolorBg, truecolorFg]

Où attr est :

  • largeur : 4 octets
  • drapeaux : 5 octets
  • 256 bg couleur : 9 octets
  • 256 fg couleur : 9 octets

Je veux tellement encapsuler ces détails car ils compliquent vraiment les choses, je me demande si le script dactylographié nous permettra de mettre des getters sur un tableau d'une manière ou d'une autre. L'utilisation d'un objet était 20 fois plus lente qu'un tableau basé sur un micro-benchmark que j'ai fait sur jsperf, je sais qu'ils ne sont pas toujours fiables mais c'est un peu ce à quoi je m'attendais en tant que surcharge pour créer un objet basé sur un prototype.

Quoi que nous fassions, le format doit être très bien documenté. En ce moment, vous devez le découvrir vous-même en regardant InputHandler.charAttributes .

Quelques réflexions supplémentaires sur l'économie de mémoire :

  • Si un caractère a une largeur > 1, nous n'avons pas vraiment besoin de stocker de données pour les caractères suivants. Les "caractères vides" sont là comme solution de contournement et fonctionneraient probablement bien étant null .
  • Normalement, un ensemble de caractères est stylisé, ce qui signifie que les attributs peuvent être partagés entre une séquence de caractères.
  • Les attributs peuvent être mis en cache et chaque caractère utilise un pointeur vers l'une des valeurs mises en cache,

Oui, je pense que sur la plupart des moteurs JS, les tableaux avec accès à l'index sont toujours plus rapides que les objets et la résolution de leurs propriétés. V8 a cependant obtenu quelques optimisations supplémentaires pour les objets. En termes de construction et de GC, un tableau est plus rapide en raison de la disposition beaucoup plus simple de la mémoire (cet inconvénient peut être omis en réutilisant les objets existants).

Je n'ai aucune idée de la bonne mise en page ici, le problème est que tout contenu très emballé augmentera la pénalité d'exécution en raison des transformations nécessaires. (C'est l'une des raisons de ne pas utiliser les champs de bits en C si la mémoire n'est pas un problème - les opérations de décalage nécessaires pollueront le cache d'instructions, ce qui entraînera des échecs de cache - le code s'exécute beaucoup plus lentement).
À mon humble avis, seuls les tests montreront ce qui fonctionne le mieux ici.

@jerch intéressant, j'ai une version à 4 chiffres pour plus de simplicité en ce moment dans https://github.com/sourcelair/xterm.js/pull/756.

Ainsi, la mémoire ici devrait être d'environ : 5 * (1000 scrollback) * (8 octets sur une machine 64 bits) * 80 = 3,2 Mo (avant surcharge du tableau js). La largeur réelle d'un terminal VS Code typique verrait ce double si nous conservons le format actuel. Cela semble assez raide maintenant que je le regarde, d'autant plus que les utilisateurs auront souvent plus de 1000 scrollback et plusieurs terminaux actifs. L'espace de fin qui n'ajoute pas grand-chose du tout et pourrait tout aussi bien être nul, ce qui serait probablement une énorme victoire.

L'idée du cache d'attributs/couleurs semble également prometteuse, tant qu'il existe un bon moyen pour un accès rapide. Une structure légère en forme d'arbre évasé serait idéale (accès rapide pour les attributs les plus fréquemment utilisés).

Il peut également valoir la peine de réutiliser les tableaux de données de ligne lorsqu'ils sont coupés au lieu de simplement les jeter ( par exemple, ici ).

Ouais et avec la surcharge du moteur à l'esprit, cela devient encore plus gros - tout dans un tableau ou un objet est stocké en tant que référence, essentiellement un pointeur vers le contenu. Les js-arrays denses ont un léger avantage ici, ils sont formés comme un tableau de type C quelque part sur le chemin (en fait, ArrayLists). Les tableaux clairsemés et autres objets sont construits avec une magie d'arbre pour résoudre la résolution de propriété.
Donc, pour 64 bits, l'élément de référence ajoute 5 * 8 octets supplémentaires par cellule (il double essentiellement votre calcul au-dessus - 6,4 Mo). Le contenu peut ajouter encore plus d'octets à côté du "contenu réel", mais cela dépend de l'implémentation réelle des types Integer et String.

Peut-être qu'un TypedArray peut résoudre ce problème. Là, le contenu entier peut résider directement à la position d'index en mémoire sans indirection supplémentaire. asm.js ne fonctionne essentiellement que sur ceux-ci.

Voici un micro benchmark rapide pour comparer TypedArray et js-Array pour la création et l'insertion de données : http://jsbench.github.io/#af3ea1056a70df2aa6775699d174df0d

Le TypedArray s'exécute 10 fois plus rapidement avec FF et Chrome sur ma machine. Cela peut être dû à la préallocation, ne l'avez pas testé avec js-Array car c'est déconseillé. Je ne sais pas si les JIT détectent le fait que la valeur augmente simplement de 1 tous les 8 octets et optimise même cette sortie. Ensuite, la référence est inutile du tout.

L'accès est légèrement moins bon pour un TypedArray (peut-être à cause d'une conversion Number ), la consommation de mémoire est bien meilleure avec un TypedArray.

L'inconvénient d'un TypedArray est le bloc de mémoire statique en ce qui concerne les données de rechange (les astuces pour éviter les données ne fonctionneront pas du tout ici, la mémoire est "perdue" de toute façon) ou le redimensionnement avec l'emballage du contenu. Il est difficile de faire les choses correctement et impliquera probablement de copier de gros morceaux de données encore et encore.

Bonjour. Des mises à jour à ce sujet ? J'ai hâte que ça marche

Quelqu'un travaille-t-il activement sur ce problème ? Est-ce qu'on en parle ailleurs ? @chabou @Tyriar ? Microsoft aide-t-il compte tenu de l'utilisation dans VS Code ?

Il s'agit du dernier problème lié à l'utilisation d'hyper dans WSL sous Windows 10 pour fournir un workflow CLI de développement décent prenant en charge tmux et vim/neovim. Les autres émulateurs de terminaux disponibles à utiliser avec WSL ne sont tout simplement pas agréables à regarder, wsltty est proche, mais la prise en charge des onglets et la prise en charge des plugins sont manquantes...

@vastbinderj Pourquoi la prise en charge manquante des couleurs vraies ne vous donne pas un flux de travail CLI de développement décent ? Question honnête.

@szmarczak et @vastbinderj
Ce problème est toujours à l'ordre du jour, mais un peu bloqué en raison de l'utilisation élevée de la mémoire qu'il introduira avec la conception actuelle du tampon de terminal. Il attirera plus d'attention lorsque #791 nous aura apporté une disposition de tampon plus efficace.

@rfgamaral simple - Je travaille quotidiennement sur de nombreux serveurs unix/linux différents sur de très grands systèmes d'entreprise avec de nombreux microservices et le fait de ne pas avoir une prise en charge des couleurs décente dans l'hôte principal est perturbateur. Gérer les couleurs qui ne sont pas les mêmes, que je sois sur rhel, centos ou debian, est pénible. De plus, m'asseoir pour aider un développeur junior ou un pair sur Windows signifie que je dois changer de contexte si les choses ne fonctionnent pas de manière uniforme. Cependant, je suis très impressionné par le chemin parcouru par wsl si rapidement avec des améliorations publiées presque tous les mois et de même avec VS Code, c'est exceptionnel.

@jerch Merci pour la mise à jour, j'attendrai patiemment que le #791 soit élaboré...

J'attends aussi cela avec impatience.

Il convient de rappeler que les nombres JavaScript peuvent représenter des entiers exacts jusqu'à 53 bits. Vous disposez donc de 21 bits en plus des 32 bits "pratiques". Vous pouvez "ou" un peu par simple ajout, si ce n'est pas déjà fait. Pour lire les bits de poids fort, divisez simplement par un entier puissance de deux approprié, puis utilisez les opérations binaires normales.

Bien sûr, il y a un peu plus de temps système à travailler avec les bits d'ordre supérieur, mais sur les processeurs modernes, la division par puissance ou deux est relativement bon marché - moins chère que les accès mémoire.

Je suggère d'utiliser un seul nombre avec 50 bits : 25 bits chacun pour le premier plan et l'arrière-plan. Un bit si défini indique que nous utilisons une "vraie" couleur de 24 bits ; sinon, nous utilisons des couleurs "logiques" (thèmes) ou 8 bits. Les bits indicateurs doivent être les 2 bits de poids faible ; si elles ne sont pas définies, les couleurs logiques/8 bits pourraient être dans les 30 bits suivants, nous n'utilisons donc que les bits 32-50 si nous utilisons réellement les couleurs vraies.

@PerBothner Nous avons décidé d'utiliser un Uint32Array pour le nouveau tampon et, pour plus de commodité, de mettre également les couleurs dans ce tableau. Ce n'est pas encore fait car nous voulons d'abord nettoyer la nouvelle impl avant de prendre en charge truecolor.

J'ai également fait quelques tests/calculs sur les mises en page possibles (voir https://gist.github.com/jerch/27c2cf91ad313a25415873e4047b2900). Pour faire court - les idées concernent le compromis entre la sauvegarde de la mémoire et la pénalité d'exécution. La transition vers un tableau typé a déjà permis d'économiser énormément de mémoire (implémente actuellement la deuxième idée d'en haut, bien que les vraies valeurs de couleur ne soient pas encore appliquées).

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