Xterm.js: Prise en charge de la sauvegarde et de la restauration de l'état du terminal

Créé le 14 mars 2017  ·  15Commentaires  ·  Source: xtermjs/xterm.js

Salut à tous,

Avec la maturation de xterm.js , je pense qu'une fonctionnalité intéressante pour élargir la gamme d'applications xterm.js pourrait être utile pour la formalisation d'un mode sans tête. Qu'est ce que je veux dire? Eh bien, fondamentalement, pour la capacité de:

  1. Exécutez un client sans moteur de rendu.
  2. Communiquez à un client avec un moteur de rendu l'état d'un client headless et vice versa.

À l'heure actuelle, le seul moyen de "définir" de manière fiable l'état d'un client est de rejouer l'ensemble de toutes les commandes qui ont produit l'état de cet éditeur (au moins via l'API publique). Cependant, vous pouvez facilement imaginer vouloir faire des choses comme:

  • parcourir l'histoire d'un terminal
  • exécuter un terminal dans le cloud auquel vous vous connectez par intermittence via le client
  • (mon cas d'utilisation) avoir plusieurs utilisateurs ont littéralement le même terminal avec la possibilité d'aller et venir

Une grande partie de cela est pratiquement déjà possible si vous sérialisez simplement term.rows et des indicateurs d'état assortis, mais l'adoption d'une API formelle aiderait beaucoup. Cela peut également aider à améliorer la testabilité et la robustesse de la bibliothèque principale!

Pensées?
Vincent

help wanted typenhancement

Commentaire le plus utile

Des mises à jour sur celui-ci? J'ai également un cas d'utilisation similaire.

Tous les 15 commentaires

@vincentwoo Je vois que cela est assez utile, avez-vous une idée de ce à quoi ressemblerait une telle API?

Je pense que vous voudrez probablement un autre constructeur comme term.Headless , et une nouvelle méthode sur les terminaux sans tête et réguliers comme getState() qui peut ensuite être introduite dans reset .

@vincentwoo serait-il également possible de sérialiser l'état sur le serveur et de l'envoyer par câble au client? Récemment, je l'ai fait pour que vous n'ayez pas besoin d'ouvrir xterm sur un élément pour qu'il conserve le tampon, alors cela pourrait suffire?

Ouais, la sérialisation est essentiellement ce que j'entends par "getState", tant que ce qui est produit peut être consommé par le client.

En ce qui concerne simplement l'utilisation du xterm normal sans élément, cela pourrait fonctionner. Je peux lui donner une chance sur node, plus tard.

Je pense que https://github.com/sourcelair/xterm.js/issues/266 signifie qu'il fonctionne essentiellement comme sans tête avant que Terminal.open soit appelé.

Cool. Des réflexions sur la façon dont l'État exportateur pourrait fonctionner?

Cela dépend de ce qui doit être conservé, juste le tampon et le curseur?

Je ne suis pas sûr moi-même, c'est pourquoi c'était une demande. Je ne sais pas à quoi ressemble la machine à états xterm en interne, ni exactement ce que vous entendez par «tampon» et «curseur».

C'est une excellente proposition @vincentwoo , merci! Je pense que la meilleure partie est la sérialisation de l'état (qui est également la partie principale de cette discussion).

IMO, un bon début dans ce domaine est l'introduction d'une propriété privée (par exemple nommée state ), où nous stockerons les "données" du terminal comme:

  • géométrie terminale
  • mode terminal
  • tampon (c'est le texte imprimé sur le terminal)
  • position du curseur
  • style de curseur

Cette propriété doit être utilisée en interne pour "définir" l'état du terminal à chaque fois (et être consultée par les internes du terminal pour voir ce qui se passe lorsque cela est nécessaire), mais elle doit être en lecture seule par le monde extérieur (par exemple term.getState() ).

Comment ça sonne?

Ça me semble bien! Je ne suis pas un expert pour connaître exactement chaque variable d'état qui identifie de manière unique l'état de xterm.js , mais je suis heureux de donner un coup de pied aux pneus. Je pense qu'essayer de trouver la liste et la tester est aussi un excellent moyen de trouver un comportement bizarre dans la bibliothèque.

Quelques autres choses que nous voulons probablement sérialiser:

  • Toutes les options
  • Le tampon alt

@parisk Je pensais qu'une fonction getState ou serialize effectuerait la sérialisation à ce stade, nous pourrions tout mettre dans un objet json et renvoyer le json assez facilement. Tout l'état que vous mentionnez peut ne pas appartenir à l'objet Terminal, par exemple le tampon vit dans CircularList . Il serait plus logique de dire à CircularList de se sérialiser lors d'un appel à la fonction. Quelque chose comme ça:

Terminal.prototype.getState() {
  const state = {};
  // this.serializableComponents is an ISerializable[] which ensures they
  // have componentKey/getState()
  this.serializableComponents.forEach(c => {
    state[c.componentKey] = c.getState();
  });
  // TODO: Add anything owned by Terminal to state
  // ...
  return state;
}

// Restore using something like this which would do the reverse
Terminal.prototype.restoreState(state: Object): void;

// A static method that returns a Terminal might be better:
Terminal.restoreTerminal(state: Object): Terminal;

C'est une approche intéressante 👍. J'ouvre une succursale pour tenter le coup.

Des mises à jour sur celui-ci? J'ai également un cas d'utilisation similaire.

Copier et coller la proposition pour résoudre ce problème à partir de https://github.com/xtermjs/xterm.js/pull/2213#issuecomment -500233758 ci-dessous


J'ai eu une conversation avec @jerch à ce sujet et nous voyons ces problèmes avec l'approche actuelle consistant à l'inclure dans le noyau:

  • Nous aurions besoin d'exposer l'API pour enregistrer / restaurer l'état, mais nous ne voulons certainement pas nous engager dans un format particulier, cela casserait probablement toutes les quelques versions.
  • Cela ajoute un tas de ballonnements au noyau lorsque si peu d'utilisateurs l'utiliseront réellement

Compte tenu de cela, nous pensons que la meilleure façon d'aborder cette fonctionnalité est d'utiliser un addon (exemple xterm-addon-serialize ) qui sérialise l'état à l'aide de la nouvelle API de tampon ( Terminal.buffer.* ). La méthode de sérialisation pourrait ressembler à ceci:

/**
 * Serializes terminal rows into a string that can be written back to the terminal
 * to restore the state. The cursor will also be positioned to the correct cell.
 * When restoring a terminal it is best to do before `Terminal.open` is called
 * to avoid wasting CPU cycles rendering incomplete frames.
 * <strong i="16">@param</strong> rows The number of rows to serialize, starting from the bottom of the
 * terminal. This defaults to the number of rows in the viewport.
 */
serialize(rows?: number): string;

Si vous n'êtes pas familier avec les bornes de la chaîne résultante ressemblerait à quelque chose comme ça "\x1b[Hfoo\n\rbar\x1b[2;4H" pour un simple ligne (déplacer le curseur à la ligne 1, colonne 1, imprimez "foo" , aller à la ligne suivante et imprimer "bar" puis positionnez le curseur sur la ligne 2 et la colonne 4).

Cela présente de nombreux avantages:

  • Les consommateurs qui ne l'utilisent pas n'ont pas besoin de charger le code
  • Les consommateurs qui l'utilisent peuvent charger dynamiquement le code
  • Il utilise une API publique déclarée stable et sérialisée dans un format standard pouvant être utilisé sur n'importe quel terminal
  • Il exploite tout le travail formidable de @jerch pour accélérer l'analyseur
  • Par défaut, il s'agit uniquement de la fenêtre d'affichage qui serait ultra-rapide pour la sérialisation et la restauration.
  • Cela ne complique pas / ne gonfle pas l'architecture de base

Notez que cela ne pourrait pas prendre en charge la couleur ou d'autres styles tant que nous n'avons pas exposé les attributs dans l'API, mais c'est quelque chose que nous voulons faire et que nous pourrions améliorer ultérieurement.

Suppression du mode sans tête du titre car xterm.js le prend déjà en charge en fonctionnant correctement sans appeler open .

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