Linenoise: Ajouter le support multi-octets

Créé le 23 janv. 2012  ·  21Commentaires  ·  Source: antirez/linenoise

Le code actuel ne prend pas en charge les chaînes multi-octets, par exemple les chaînes ayant des caractères Unicode au-delà de la plage ASCII. Les décalages de colonne pour refreshLine sont calculés à l'aide de strlen() qui renvoie 2 au lieu de 1 pour un caractère à 2 octets comme « Ş » en turc.

La bibliothèque doit utiliser mbstowcs() ou d'autres fonctions pour obtenir le nombre de caractères au lieu du nombre d'octets pour le traitement des colonnes (flèches haut, bas, effacement d'un caractère, etc.).

De plus, comme ces fonctions dépendent de LC_CTYPE, vous ou les applications utilisant linoise devez appeler setlocale(LC_ALL, "") pour définir les paramètres régionaux de l'application sur les paramètres régionaux du système.

Merci.

Commentaire le plus utile

Mon fork (https://github.com/yhirose/linenoise/tree/utf8-support) prend désormais en charge Unicode 11.0 et inclut toutes les modifications récentes apportées dans antirez/linenoise .

Tous les 21 commentaires

Jetez un œil à mon fork, https://github.com/msteveb/linenoise , qui prend en charge utf-8

Avez-vous vraiment besoin de toutes ces fonctions ? Je ne suis pas très familier avec le truc, mais j'ai facilement résolu certains des problèmes étranges en utilisant mbstowcs() au lieu de strlen() où la longueur de la chaîne est supposée équivalente au nombre de caractères de la chaîne. Mais je n'ai pas trouvé de moyen de corriger la suppression des caractères larges avec retour arrière.

L'approche ici consiste à éviter toute dépendance à la prise en charge du système pour utf-8. Par exemple, j'ai des systèmes exécutant uClibc sans prise en charge des paramètres régionaux qui peuvent toujours exécuter sans problème une console utf-8 sur un port série. Bien sûr, vous êtes invités à adopter une approche différente.

J'ai un problème similaire; J'ai essayé le bruit de ligne pour une implémentation shell. Si je veux des invites colorées, les codes d'échappement finissent par être inclus dans le calcul de la longueur.

Une solution plus simple et plus facile consiste à :

1) permet de spécifier vous-même la longueur de l'invite.
2) utiliser des commandes de terminal pour extraire la position du curseur après avoir généré l'invite (je ne sais pas si cela est possible)

Je trouve cela dans le code de mongo shell. Je suis toujours agacé par de plus en plus d'outils CLI (mongo, redis-cli, node)) que j'utilise dont le curseur bouge bizarrement lorsqu'il y a des caractères multi-octets. Je ne sais pas si les autres utilisent de la linoise ou autre chose, mais j'aimerais que cela soit corrigé :-)

J'ai fait une linoise modifiée qui vous permet de spécifier la largeur vous-même, donc c'est un travail supplémentaire pour l'application, mais au moins possible; Je l'utilise depuis environ 3 mois sans aucun problème. Je vais peut-être en faire une pull request.

La branche 'utf-8 support' sur mon fork a résolu les problèmes UTF-8 suivants qui apparaissent dans la dernière version 1.0 de linoise :

  • Caractères multi-octets : ö (U+00F6)
  • Caractères multi-codes : ö (U+006F U+0308)
  • Caractères larges : 日本語 (« japonais »)
  • Texte d'invite comprenant les caractères ci-dessus et le texte de couleur d'échappement ANSI.

J'ai d'abord essayé https://github.com/msteveb/linenoise. Mais il n'est pas basé sur la dernière linoise qui prend en charge le fantastique mode multiligne. De plus, il ne prend pas en charge les caractères larges CJK et les caractères multicodes...

Bonjour, je pense suivre la voie suivante avec ce problème:

  1. Utilisez @yhirose comme référence afin de vérifier où les fonctions de chaîne en clair C doivent être remplacées par des fonctions multi-octets.
  2. Exportez une API qui permet à l'utilisateur de linoise de définir des fonctions alternatives pour les calculs de longueur de chaîne. Définissez la fonction sur les fonctions C simples par défaut.
  3. Incluez le code @yhirose en tant que fichier séparé que vous pouvez ajouter à votre application, en appelant les nouvelles fonctions linoise pour définir les fonctions de longueur, afin d'avoir une prise en charge multi-octets.

De cette façon, nous obtenons que la simplicité de linoise reste presque intacte, mais en option, il est à la fois possible de prendre en charge les caractères multi-octets à la fois avec des fonctions C++ , d'autres fonctions fournies par l'utilisateur différentes des fonctions standard, ou celles incluses dans linoise lui-même si votre project est en C et vous ne voulez pas réécrire ce que @yhirose a déjà écrit encore et encore.

Cela a du sens pour vous ? Merci.

@antirez , Merci d'avoir prêté attention aux utilisateurs de code multi-octets ! L'idée que vous avez présentée me semble tout à fait logique. Je suis encore plus heureux car si la bibliothèque linoise elle-même peut donner l'extensibilité, nous pourrions facilement ajouter un autre support d'encodage multi-octets.

Comme vous pouvez le voir dans mon fork, le concept le plus important pour activer la prise en charge de « multi-octets » est de faire une distinction claire entre « position/largeur d'octet » dans le tampon de texte et « position/largeur de colonne » à l'écran. Voici quelques exemples en UTF-8 :

  • (U+3042) : E3 81 82 (3 octets) : Large (largeur de 2 colonnes)
  • ö (U+00F6) : C3 B6 (2 octets) : étroit (largeur de 1 colonne)
  • (U+006F U+0308) : 6F CC 88 (3 octets) : étroit (1 colonne de largeur)

Une fois que nous connaissons la différence, il est assez facile de gérer correctement le code multi-octets. Vous pouvez saisir l'idée à partir des changements dans le 1er commit . J'ai également appliqué le même principe au texte d'invite dans le 2ème commit .

Le seul endroit où nous devons être prudents est le code de gestion du mode multiligne. Par exemple, lorsque le dernier caractère est large et qu'il ne reste qu'une colonne sur la ligne actuelle, ce caractère large ne tient pas dans l'espace restant. Le caractère large doit donc être affiché au début de la ligne suivante. Ce code le gère.

Une autre chose que j'ai faite est de sauter tous les caractères de séquence d'échappement ANSI lors du calcul de la position/largeur de la colonne dans

Je suis vraiment ravi de voir la nouvelle API dans un avenir proche. S'il vous plaît laissez-moi savoir si vous avez des questions à ce sujet. Je suis sûr que vous ferez un travail fantastique !!

Après avoir recherché plus sur les dépendances entre le code linoise et le code d'encodage UTF-8 en fonction de votre objectif de conception, j'ai réalisé que seules trois fonctions sont nécessaires lors de l'ajout d'un autre support d'encodage.

Sur la base de la recherche, j'ai mis à jour ma branche. Voici la différence entre la tête linoise et la branche utf8-support . Comme vous pouvez le voir, je me suis complètement débarrassé de tout le code spécifique à UTF-8 de linenoise.c et je les ai mis dans encodings/utf8.h et encodings/utf8.c . J'ai également ajouté une API d'expérimentation appelée linenoiseSetEncodingFunctions sur linoise.h, afin que les utilisateurs puissent définir leur propre ensemble de fonctions d'encodage. J'ai confirmé que toutes les fonctionnalités fonctionnent toujours.

Voici un extrait de mon API expérimentale actuelle :

typedef size_t (linenoisePrevCharLen)(const char *buf, size_t buf_len, size_t pos, size_t *col_len);
typedef size_t (linenoiseNextCharLen)(const char *buf, size_t buf_len, size_t pos, size_t *col_len);
typedef size_t (linenoiseReadCode)(int fd, char *buf, size_t buf_len, int* c);

void linenoiseSetEncodingFunctions(
    linenoisePrevCharLen *prevCharLenFunc,
    linenoiseNextCharLen *nextCharLenFunc,
    linenoiseReadCode *readCodeFunc);

linenoisePrevCharLen et linenoiseNextCharLen renvoient la longueur en octets comme valeur de retour et définissent la longueur de la colonne sur le paramètre col_len . linenoiseReadCode lit les octets dans buf , et convertit les octets et définit un code de caractère significatif pour l'encodage en paramètre c .

Si les utilisateurs n'appellent pas linenoiseSetEncodingFunctions , cela finira par appeler les implémentations _default_. Ils gèrent simplement _un octet_ en tant que caractère.

J'espère que le message vous sera utile lors de la conception de la nouvelle API d'encodage. Je suis vraiment impatient d'y être!!

@yhirose c'est un travail fantastique !!! :-) Je vais vérifier le code et le fusionner. Merci pour ça.

Pas encore fusionné ?

@antirez des progrès sur la fusion?

J'ai modifié mon fork (https://github.com/yhirose/linenoise/tree/utf8-support) pour rattraper les récents changements apportés à la linoise d'origine, tels que la fonction "indices".

Merci beaucoup @yhirose. Vous avez amélioré le bon code ! et mon
travail plus facile !

@sonophoto

Le lundi 27 juin 2016 à 18:56:45 -0700, yhirose a écrit :

   I have modified my fork 

(https://github.com/yhirose/linenoise/tree/utf8-support) pour rattraper son retard
avec les récents changements apportés à la linoise d'origine tels que les « indices »
caractéristique.
-
Vous recevez ceci parce que vous êtes abonné à ce fil.
Répondez directement à cet e-mail, affichez-le sur GitHub ou coupez le fil de discussion.

*

Mon fork (https://github.com/yhirose/linenoise/tree/utf8-support) prend désormais en charge Unicode 9.0.

@antirez Aurez-vous du temps libre dans un proche avenir pour fusionner le support multi-octets de https://github.com/hoelzro/lua-linenoise pour utiliser le fork de

Mon fork (https://github.com/yhirose/linenoise/tree/utf8-support) prend désormais en charge Unicode 11.0 et inclut toutes les modifications récentes apportées dans antirez/linenoise .

Mon fork (https://github.com/yhirose/linenoise/tree/utf8-support) prend désormais en charge Unicode 12.1.

Mon fork (https://github.com/yhirose/linenoise/tree/utf8-support) prend désormais en charge Unicode 13.0.

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

Questions connexes

ghost picture ghost  ·  4Commentaires

fatcerberus picture fatcerberus  ·  5Commentaires

JelteF picture JelteF  ·  8Commentaires

denisvm picture denisvm  ·  9Commentaires

krux02 picture krux02  ·  8Commentaires