View Issue Details

IDProjectCategoryView StatusLast Update
0000238LDMud 3.6Efunspublic2023-10-02 18:35
ReporterlarsAssigned ToGnomi  
Status resolvedResolutionfixed 
Product Version3.2.8 and before 
Fixed in Version3.6.3 
Summary0000238: Colored string handling
DescriptionShort: Useful coloured string efuns
From: "Alexander Weidt et al." <>
Date: Fri Feb 23 13:42:33 2001
Type: Feature
New: Acknowledged
See also: f-011016-0

Hi Lars,,

hier schick ich Dir mal die Klasse basic/coloured_string.c.

- #define REGEXP_TERMINAL_COLOUR_TOKEN "%\\^([^%]|(%%*[^%^]))*%%*\\^"
- LIB_CNTL_SEQUENCES->get_plain_mapping() liefert ein Mapping fuer
  terminal_colour(), welches alle hier im Mud definierten tokens enthaelt
  und auf "" abbildet.

Viele Gruesse,

 * /basic/coloured_string.c by Alfe for TubMud 01-Feb-14
 * This is a basic class for handling coloured strings.

#pragma strong_types

#include <regexps.h>
#include <libs.h> // Coogan, 16-Feb-01

private nosave mapping plain_mapping;

 * this applies `changer' on all parts of the given coloured_string
 * which are not a colour token and returns the result.
string apply_on_coloured_string(string coloured_string,closure changer) {
  mixed h;
  int i;
  h = regexplode(coloured_string,REGEXP_TERMINAL_COLOUR_TOKEN);
  for (i=0; i<sizeof(h); i+=2) // pick the non-tokens
    h[i] = funcall(changer,h[i]);
  return implode(h,"");

 * this removes all colour tokens from the given coloured_string and
 * returns the result; thus it produces a verbatim string.
string to_verbatim(string coloured_string) {
  if (!plain_mapping)
    plain_mapping = LIB_CNTL_SEQUENCES->get_plain_mapping();
  return terminal_colour(coloured_string,plain_mapping);

 * this returns the visible string length of a coloured string
int strlen_visible(string coloured_string) {
  if (!plain_mapping)
    plain_mapping = LIB_CNTL_SEQUENCES->get_plain_mapping();
  return strlen(terminal_colour(coloured_string,plain_mapping));

private void find_pos(string *parts,
                      int pos,status pos_from_back,
                      int real_part,int real_pos,
                      status as_start) {
  if (pos_from_back) {
    if (pos < 0) {
      real_part = sizeof(parts) - 1;
      real_pos = strlen(parts[<1]);
    } else {
      pos = strlen_visible(implode(parts,"")) - pos;
  } else { // from front
    // skip all parts which are too short:
    for (real_part = real_pos = 0;
         real_part < sizeof(parts) && (as_start?
                                       pos > strlen(parts[real_part]) :
                                       pos >= strlen(parts[real_part]));
         real_pos += strlen(parts[real_part]),
         pos -= strlen(parts[real_part]),
         real_part += 2)
    if (real_part >= sizeof(parts)) { // too long?
      real_part = sizeof(parts) - 1;
      real_pos = strlen(parts[<1]);
    } else
      real_pos = pos;

 * this returns a substring of the given coloured string;
varargs string substring(string coloured_string,
                         int start, int stop,
                         status start_from_back,status stop_from_back) {
  string *parts;
  int *real_pos, *vis_pos;
  int i;
  int real_start_pos,real_stop_pos;
  int real_start_part,real_stop_part;
  parts = regexplode(coloured_string,REGEXP_TERMINAL_COLOUR_TOKEN);
  find_pos(parts, stop, stop_from_back, &real_stop_part, &real_stop_pos,0);
  if (real_start_part > real_stop_part)
    return "";
  if (real_start_part == real_stop_part)
    parts[real_start_part] =
  else {
    parts[real_start_part] = parts[real_start_part][real_start_pos..];
    parts[real_stop_part] = parts[real_stop_part][..real_stop_pos];
  return implode(parts[real_start_part..real_stop_part],"");

varargs string coloured_sprintf(string format,varargs mixed *args) {
  int i;
  int strlen_diff;
  for (i=0; i<sizeof(args); i+=2)
    if (stringp(args[i+1])) {
      strlen_diff = strlen(args[i+1]) - strlen_visible(args[i+1]);
      if (args[i] < 0)
        args[i] -= strlen_diff;
        args[i] += strlen_diff;
  return apply(#'sprintf,format,args);

Aber gleich zu [] noch was anderes: Wir haben hier die Notwendigkeit
festgestellt, farbige strings mit terminal_colour()-token an definierten
Stellen umzubrechen bzw. teilstrings zu extrahieren, und diese Extraktion
ist in LPC recht teuer.

Dies ist bisher hier so geloest in einer sefun
subcoloured_string(string coloured_string,
                   int start, int stop,
                   status start_from_back,status stop_from_back):

string s = "%^BOLD_BLUE%^Test%^NORMAL%^ %^RED%^another test%^NORMAL%^";

subcoloured_string(s, 2) == "%^BOLD_BLUE%^est%^NORMAL%^ %^RED%^another test%^NORMAL%^"
s[0..3] == "%^BOLD_BLUE%^Test%^NORMAL%^%^RED%^%^NORMAL%^"
s[5..] == "%^BOLD_BLUE%^%^NORMAL%^%^RED%^another test%^NORMAL%^"

D.h. alle Farbtokens bleiben im resultat-string drin, und extrahiert wird
letztlich der verbatim-teil dazwischen.
Die sefun zerlegt zunaechst den String in farbtokens und plain text, dann
wird das extract auf den plaintext-Stuecken vorgenommen, und danach wieder
der farb-string zusammengesetzt. Wie gesagt, sehr teuer.

Aber hierbei koennen wir wirklich wieder in Probleme laufen, wenn man das
in [] machen wollte. Ein Datentyp 'coloured_string' waere wirklich nett.
Und/oder natuerlich eine efun, die diese extrahierung von plain text
aus colour-token-verseuchten strings vornimmt. :-)
And Slava wrote in Oct 2001:

Recently I revealed great demand in something like hibrid of
sprintf+terminal_colour. Also I've discovered, that some time ago
there was something about this topic - f-990309-1.

In the matter of fact there is a great demand in such a functionality
in the driver. Till now, there are no official way, how to handle
coloured strings. I mean, yes you can do something with it - wrap,
and do very rudimentary formatting, using terminal_colour. But this is
not enough.

Furthermore, without additional and expensive workarounds, there are no
way how to:

1. format coloured string like in sprintf(), especially using such a
   modifiers, like: '-=', '|=', etc.
2. measure coloured string length like in strlen() or sizeof()
3. Use all the great funs, that we have for their non-coloured
   equivalents. All because of there is difference in actual string
   size and its displayable one.

Subject: sprintf() and colour strings
From: Lars Duening, Alfe
Date: 2001-10-16
Type: Feature
State: Acknowledged.
See also: f-010223, f-011015-1, f-000905-1

New format specifier '%S' to format colour-coded strings, '%s' normal strings
as usual.

Optionally introduce an efun

  csprintf(mapping cntl, string format, mixed args...)

which first applies sprintf(), and then replaces all colour strings in the
result before returning it.

Dafire also requested this formatting capability:

From: "Bastian Hoyer" <>
Date: Tue, 16 Oct 2001 11:15:39 +0200

Hallo Lars,

was ich braeuchte waere ein leerzeichen das vorne am Wort klebt :)

also ich mache eine liste die so aussieht:

aaa: +bbb -ccc +ddd eee fff

vor jedem wert hab ich ein + oder - oder ein leerzeichen :)

wenn das jetzt umbricht sieht das evtl so aus :

aaa: +bbb -ccc +ddd
     eee fff

weil das Leerzeichen vor eee beim umbrechen wegfaellt :)

Ich hoffe das war irgendwie verstaendlich :)
Ich glaub bei html ist das ein   :)



related to 0000265 new LDMud Formatting in terminal_colour() 



2004-11-27 01:14

reporter   ~0000223

p-020810: Hyperborea's implementation of formatting of colored text (using their own color tag notation)

2004-11-27 01:15


p-020810.gz (9,435 bytes)


2010-03-10 17:54

reporter   ~0001781

zesstra: this might be something for your extras git-repository, although I would actually prefer avalons colour-aware implementation (which is also MXP sequence aware). I just thought I'd bump this.


2010-03-14 10:25

administrator   ~0001793

Uh. Yes, that would be IMHO a good candidate.
Anybody interested in 'adopting' this? ;-)


2023-10-02 18:35

manager   ~0002711

sprintf() in LDMud 3.6.3 honors ANSI Escape sequences together with Unicode Grapheme Clusters.

Issue History

Date Modified Username Field Change
2004-11-26 23:50 lars New Issue
2004-11-27 00:18 lars Relationship added related to 0000265
2004-11-27 01:14 lars Note Added: 0000223
2004-11-27 01:15 lars File Added: p-020810.gz
2010-03-10 17:54 _xtian_ Note Added: 0001781
2010-03-14 10:25 zesstra Tag Attached: ldmud-extensions
2010-03-14 10:25 zesstra Note Added: 0001793
2010-03-14 10:25 zesstra Status new => feedback
2023-10-02 18:33 Gnomi Assigned To => Gnomi
2023-10-02 18:33 Gnomi Status feedback => assigned
2023-10-02 18:34 Gnomi Project LDMud => LDMud 3.6
2023-10-02 18:35 Gnomi Status assigned => resolved
2023-10-02 18:35 Gnomi Resolution open => fixed
2023-10-02 18:35 Gnomi Fixed in Version => 3.6.3
2023-10-02 18:35 Gnomi Note Added: 0002711