Pouvez-vous rendre mon terminal moins ennuyeux?

11

Les terminaux sont tellement ennuyeux de nos jours. Ils ressemblaient à ceci:

Terminal 1 Terminal 2

Maintenant, ils sont juste fades et ternes et en noir et blanc. Je veux que vous m'écriviez un programme qui rendra mon terminal tout de nouveau coloré!

La description

Prenez cet exemple de code Ruby:

Exemple de code

La plupart des terminaux Linux prennent en charge ces séquences d'échappement ( \esignifie le caractère d'échappement), et Windows peut les prendre en charge avec ANSICON . Voici la syntaxe de la séquence d'échappement spécifique qui peut changer la couleur du texte ou de l'arrière-plan d'une chaîne:

\e[{{COLOR}}m

\ereprésente le caractère d'échappement ( 0x1Ben ASCII) et {{COLOR}}est remplacé par le numéro de la couleur que vous souhaitez utiliser (plus de détails à ce sujet plus tard). Le texte qui vient après cette séquence d'échappement sera formaté comme indiqué et une valeur de 0réinitialisera tout le formatage.

Votre défi consiste à prendre une chaîne spécifiant du texte pouvant contenir de la couleur et à en produire une version colorée.

Entrée sortie

Le texte normal fonctionne comme d'habitude et est imprimé littéralement. Par exemple, l'entrée wafflesdonne la même sortie, sans couleur spéciale.

La syntaxe pour spécifier une couleur est similaire à la syntaxe de Wikipedia . Par exemple, pour colorer les mots "la couleur rouge" en rouge dans la phrase This is the color red!, l'entrée serait:

This is {{red|the color red}}!

Les couleurs d'arrière-plan fonctionnent également. Si vous vouliez des lettres noires sur fond blanc, vous utiliseriez ceci:

{{black|white|This text is black on white}}

Pour obtenir uniquement une couleur d'arrière-plan, omettez le premier plan:

{{|red|This text has a red background}}

spécification

Deux accolades ouvertes indiquent toujours le début d'une directive de couleur . Deux accolades fermantes indiquent la fin. Les parenthèses correspondront toujours; il n'y aura jamais de {{sans correspondant }}, et un }}ne viendra jamais avant son correspondant {{. Ces directives de couleur ne seront pas imbriquées et a {{n'apparaîtra jamais dans une directive de couleur.

Dans une directive couleur, il y aura toujours un ou deux |symboles. S'il y en a un, le texte avant c'est la couleur de premier plan et le texte après est la chaîne à afficher dans cette couleur. S'il y en a deux, le texte avant le premier est la couleur de premier plan, le texte après le premier mais avant le second est la couleur d'arrière-plan et le texte après le second est la chaîne à afficher. Ces barres verticales peuvent exister en dehors d'une directive de couleur et doivent être imprimées littéralement.

La couleur de premier plan ou d'arrière-plan (mais pas les deux) peut être vide, auquel cas vous devez les laisser par défaut. La chaîne finale (celle à afficher) ne sera jamais vide.

Voici les instructions pour sortir du texte d'une certaine couleur:

  • Une séquence de couleurs est définie dans la section "Description". Par exemple, une séquence de couleurs de 42 serait "\e[42m".

  • Pour définir une couleur, imprimez la séquence de couleurs du nombre déterminé ci-dessous:

     Color name   | Color sequence number (foreground / background)
    --------------+----------
     black        | 30 / 40
     red          | 31 / 41
     green        | 32 / 42
     yellow       | 33 / 43
     blue         | 34 / 44
     magenta      | 35 / 45
     cyan         | 36 / 46
     lightgray    | 37 / 47
     darkgray     | 90 / 100
     lightred     | 91 / 101
     lightgreen   | 92 / 102
     lightyellow  | 93 / 103
     lightblue    | 94 / 104
     lightmagenta | 95 / 105
     lightcyan    | 96 / 106
     white        | 97 / 107
    
  • Les noms de couleur sont sensibles à la casse et un nom de couleur non valide ne sera jamais fourni. Vous n'avez pas à gérer des choses comme REDou lightgrey(orthographié avec un e).

  • Après avoir imprimé une séquence de couleurs, elle s'appliquera à tout le texte qui la suit. Pour terminer une séquence de couleurs (réinitialiser à la couleur par défaut), sortez une séquence de couleurs de 0( "\e[0m").

Cas de test

 {{|yellow|     }}
{{|yellow| }}     {{|yellow| }}
{{|yellow| }} {{red|'}} {{red|'}} {{|yellow| }}
{{|yellow| }} \_/ {{|yellow| }}
{{|yellow| }}     {{|yellow| }}
 {{|yellow|     }}

Cela devrait produire un visage souriant ... avec des yeux rouges maléfiques.

Règles

  • Vous ne pouvez utiliser aucune bibliothèque ou fonction de votre langage de programmation pour analyser automatiquement une couleur. Cela signifie que vous devez être celui qui détermine ce que "red"signifie; une bibliothèque ne peut pas le faire automatiquement pour vous.

  • Il s'agit de , donc le code le plus court en octets gagnera!

Poignée de porte
la source
Il s'agit en fait d'un terminal? Ou juste une visionneuse de texte colorée? Est-il censé exécuter des commandes?
Nathan Merrill
J'ai du mal à tester cela. Tout ce que j'envoie à STDOUT en utilisant la syntaxe spécifiée est en texte brut. Mon profil bash utilise une invite colorée, donc je l'ai volé \n\[\e[32m\]\w\n\[\e[0m\]> (nom de répertoire vert, invite simple sur la ligne suivante), mais je ne peux pas le faire fonctionner à partir d'un programme (essayé python et Java jusqu'à présent). Des idées?
Geobits
@Geobits Try echo -e "\e[31mtest\e[0m".
Poignée de porte
4
Je pense que vous apprécierez lolcat.
Anko
1
Je pense que par youil signifie au sens figuré your program(par opposition à un appel à une fonction de bibliothèque), et qu'il prend determinedans le sens de figure out, pas comme dans choose. C'est-à-dire que c'est votre programme qui doit gérer le mappage: String ("red") | -> Integer (31). redc'est seulement 31parce qu'il le dit, que l'information doit être intégrée au programme. Bien que l'on puisse dire exactement ce qui compterait your program- pouvons-nous utiliser des fonctions de manipulation de chaînes à usage général? - ne trichez / abusez pas ouvertement.
blutorange

Réponses:

6

Rubis, 205 189 188 186 185 185 182 174 170 165 161 159 154 154 octets

Mettre de longues chaînes de noms de couleurs dans votre code ne semble pas assez ringard.

Jusqu'à 170 en partie grâce à rubik. Maintenant, les barres de défilement ont disparu!

Une amélioration évidente et pas si évidente, grâce à la réponse flexible, sans l'amélioration, je n'aurais pas revu cela!

Plus maintenant, j'ai sauvé 4 octets avec #sum. Je n'en avais pas l'intention, mais je viens de remarquer que cette solution est également insensible à la casse. Il traite avec bonheur {{RED|Red text}}.

Vidage hexadécimal:

0000000: 7a3d 2d3e 6a7b 693d 2240 3054 2d44 1547  z=->j{i="@0T-D.G
0000010: 5155 0034 3256 2f46 1749 0b22 2e69 6e64  QU.42V/F.I.".ind
0000020: 6578 2028 415b 6a5d 2e74 6f5f 732e 7375  ex (A[j].to_s.su
0000030: 6d25 3839 292e 6368 723b 692b 3d69 3e39  m%89).chr;i+=i>9
0000040: 3f38 303a 3330 7d0a 243e 3c3c 243c 2e72  ?80:30}.$><<$<.r
0000050: 6561 642e 6773 7562 282f 7b7b 282e 2a3f  ead.gsub(/{{(.*?
0000060: 297d 7d2f 297b 413d 2431 2e73 706c 6974  )}}/){A=$1.split
0000070: 277c 273b 221b 5b25 693b 2569 6d23 7b41  '|';".[%i;%im#{A
0000080: 2e70 6f70 7d1b 5b30 6d22 255b 7a5b 305d  .pop}.[0m"%[z[0]
0000090: 2c31 302b 7a5b 315d 5d7d                 ,10+z[1]]}

Vous pouvez le convertir avec xxd -r hex.dump.

Le programme avec tous les caractères non imprimables s'est échappé à des fins de référence:

z=->j{i="@0T-D\x15GQU\x0042V/F\x17I\v".index (A[j].to_s.sum%89).chr;i+=i>9?80:30}
$><<$<.read.gsub(/{{(.*?)}}/){A=$1.split'|';"\x1b[%i;%im#{A.pop}\x1b[0m"%[z[0],10+z[1]]}

C'est une ligne. Utilisez-le comme ça

ruby colors.rb -W0 < input.txt

Le -W0drapeau supprime les avertissements qui seraient envoyés stderrautrement. Cependant, le programme fonctionne correctement sans aucun indicateur.

Production:

production

blutorange
la source
1
Ah, j'ai eu la même idée, mais tu m'as battu! Je pense que vous pourriez économiser char avec la base 35, le module 98 et XOR 1. La chaîne serait: '1?IYU_N[(\x0c\x16&",\x1f\x01'. Ma chaîne a une longueur de 16 cependant. Je vois que le vôtre a 18 ans, vous devez donc probablement vous ajuster.
rubik
Merci. Les deux octets supplémentaires sont là pour prendre en charge le code couleur 39/49, qui définit la couleur par défaut arrière / arrière-plan. Mais merci pour l'astuce, je suis actuellement au travail et je vais y réfléchir un peu plus en rentrant chez moi.
blutorange
1
Eh bien, j'ai observé que les seules bases que vous pouvez utiliser sont 35 et 36 (au moins la int()fonction de Python ne peut pas dépasser 36). Ensuite, j'ai essayé toutes les combinaisons pour le module (de 2 à 10000, mais en théorie on pourrait élargir la recherche à tout Unicode) et pour le xor, que j'ai gardé petit (1 à 9). Ensuite, j'ai considéré des résultats acceptables uniquement ceux qui ne contenaient pas de caractères en double.
rubik
Oui, c'est plus ou moins ce que j'ai fait aussi. À l'origine, je me limitais aux caractères imprimables, car cela vous donne moins de maux de tête et semble plus agréable. Mais comme j'utilise déjà l'octet 0x1e au lieu de la séquence d'échappement, je pourrais aussi bien utiliser plus de caractères non imprimables. Afin d'obtenir des caractères imprimables, j'ai utilisé x.to_i(base)%mod+offset. J'ai ensuite remplacé le +par ^, car bon, il a l'air plus cool. A part ça, c'est inutile. Suppression de ^99et modification <<en +enregistré pour plus d'octets. Merci pour l'astuce, je ne l'aurais pas remarqué autrement!
blutorange
4

Ruby, 329 octets.

h={};(y=0..15).each{|i|h[%w(black red green yellow blue magenta cyan lightgray darkgray lightred lightgreen lightyellow lightblue lightmagenta lightcyan white)[i]]=y.map{|j|[30,40].map{|k|k+i%8+i/8*60}}[i]}
loop{puts gets.gsub(/{{.+?}}/){|x|"\e[#{h[(g=x.scan(/[^{}|]+/))[0]][0]}m#{(g[2]? "\e[#{h[g[1]][1]}m":'')}#{g.last}\e[0m"}}
Alex Deva
la source
De quelle version de Ruby ai-je besoin pour l'exécuter? Je ruby 2.1.2p95et il jette l' erreur: undefined method 'gsub' for nil:NilClass (NoMethodError) .
Ray
Salut @Ray, cela fonctionne dans 2.0.0-p451. Je ne l'ai pas essayé en 2.1.2. Ici, cela fonctionne comme un script et ici, cela fonctionne en irb .
Alex Deva
Cela fonctionne lorsque vous saisissez du texte manuellement. Si vous le faites ruby colors.rb < input.txt, il continuera à boucler une fois que toutes les entrées auront été lues. getsRetourne ensuite nil, qui ne possède pas de #gsubméthode, provoquant ainsi une erreur. Utilisez $><<$<.readau lieu de loop{puts gets, c'est aussi plus court; )
blutorange
Je viens de tester ce script avec le visage souriant (voir la question et l'image de mon message), et il n'y a pas de bordure jaune autour du sourire?
blutorange
4

Flex (lexer) - 226 197 192 182 168 (ou 166)

Pour le ramener à 166, remplacez le \33par un caractère d'échappement réel.

 int z;p(i){printf("\33[%dm",i);}
%%
"{{" z=2;
[a-z]*\| if(!z)REJECT;~-yyleng&&p("062q00t03058ns7uo0p90r4"[*(int*)&yytext[yyleng>7?4:0]%131%27]-10*z);z--;
"}}" p(z=0);

Compiler et exécuter:

$ flex -o colour.c colour.l
$ gcc -o colour colour.c -lfl
$ ./colour < input
rici
la source
3

Python - 351

import re,sys
R=range
E=lambda n,d=0:'\033[%dm'%(T[n]+d)if n else''
def P(m):f,b,t=m.groups();return'%s%s%s\033[0m'%(E(f),E(b,10),t)
x='!red!green!yellow!blue!magenta!cyan'.replace
T=dict(zip(('black'+x('!',' ')+' lightgray darkgray'+x('!',' light')+' white').split(),R(30,38)+R(90,98)))
print re.sub(r'{{(\w+)?\|?(\w+)?\|?(.+?)}}',P,sys.stdin.read())
Rayon
la source
1

Cobra - 496

Il pourrait s'agir presque d' une seule déclaration imprimée.

use System.Text.RegularExpressions
class P
    def main
        print Regex.replace(Console.readLine,r'\{\{('+(l=List<of String>(((m=' black red green yellow blue magenta cyan'.split).join(' ')+' lightgray darkgray'+m.join(' light')+' white').split))[1:].join('|')+r')?\|?('+l[1:].join('|')+r')?\|(.*?)\}\}',do(a as Match))
            return if(x=l.indexOf('[a.groups[1]]'),r'\e['+'[if(x>8,x+81,x+29)]m','')+if(y=l.indexOf('[a.groups[2]]'),r'\e['+'[if(y>8,y+91,y+39)]m','')+'[a.groups[3]]'+if(x+y,r'\e[0m','')
Οurous
la source
1

Python, 561

Lit le texte à formater depuis stdin.

import re,sys
def p(f,b,t):
    p=''
    m='\033[%dm'
    if f!=0:p+=m%f
    if b!=0:p+=m%b
    return p+t+m%0
def c(n,b=0):
    s='black:30#red:31#green:32#yellow:33#blue:34#magenta:35#cyan:36#lightgray:37#darkgray:90#lightred:91#lightgreen:92#lightyellow:93#lightblue:94#lightmagenta:95#lightcyan:96#white:97'
    r=0
    for i in s.split('#'):
        (t,c)=i.split(':')
        if t==n:
            r=int(c)
            if b==1:r+=10
    return r
def r(m):
    i=m.groups()
    f=b=0
    if i[0]!='':f=c(i[0])
    if i[1]!=None:b=c(i[1],1)
    return p(f,b,i[2])
print re.sub('{{(\w*)\|(?:(\w*)\|)?([^}]+)}}',r,sys.stdin.read())
Sammitch
la source
2
C'est trop verbeux pour avoir is not Nonedans un codegolf. Vous pouvez utiliser !=None, par exemple.
Ray
De plus, dans def p(f,b,t), votre code lancera un ZeroDivisionError. Tout mod 0 est impossible.
Beta Decay
@BetaDecay qui n'est pas un entier en cours de module, c'est une chaîne en cours de formatage.
Sammitch
Je reçois des erreurs de syntaxe non valides lors de l' re.subexécution de ce programme
ArtOfCode
(commentaire tardif) Ce code de 499 octets fonctionne-t-il?
Erik the Outgolfer