Short: Useful coloured string efuns From: "Alexander Weidt et al." <tubmud@cs.tu-berlin.de> 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. Anmerkungen: - #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, Coogan. ----------------------------------------------------------------------- /* * /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; find_pos(parts,pos,0,&real_part,&real_pos,as_start); } } 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,start,start_from_back,&real_start_part,&real_start_pos,1); 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] = parts[real_start_part][real_start_pos..real_stop_pos]; 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; else 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.