"Backlighting" How it works: A new resource should be set up to control the backlighting functionality, called "nedit*text.backlightCharTypes" - it sets up a relationship between characters and their backlight coloring; for example, this is what I use (assuming ASCII/ISO8859-1 style encoding): nedit*text.background: #e5e5e5 nedit*text.backlightCharTypes: \ 32-255:#f0f0f0;0-31,127,128-159:orange;9-13:#e0e0e0 Put this in .Xdefaults or your NEdit app-defaults file. Alternatively, if you don't want it all the time, add the line as as -xrm parameter, eg nedit -xrm '*text.backlightCharTypes: 0-31:red;32-255:white;9:gray' ... ================================================================================ Changes to NEdit source code What follows are diffs with the original NEdit 5.0.2 source code files (renamed with the extension .orig): ================================================================================ diff -rc Makefile.common.orig Makefile.common *** Makefile.common.orig Thu Mar 19 22:20:30 1998 --- Makefile.common Tue Oct 6 21:31:28 1998 *************** *** 4,9 **** --- 4,11 ---- # included by machine specific makefiles. # + EXTRAS = -DBACKLIGHT_CODE + OBJS = nedit.o file.o menu.o window.o selection.o search.o undo.o shift.o \ help.o preferences.o tags.o userCmds.o shell.o regularExp.o macro.o \ text.o textSel.o textDisp.o textBuf.o textDrag.o server.o highlight.o \ *************** *** 18,25 **** $(CC) $(CFLAGS) nc.o ../util/libNUtil.a $(LIBS) -o $@ help.o: help.c ! $(CC) $(CFLAGS) $(BIGGER_STRINGS) -c help.c -o $@ smartIndent.o: smartIndent.c ! $(CC) $(CFLAGS) $(BIGGER_STRINGS) -c smartIndent.c -o $@ --- 20,29 ---- $(CC) $(CFLAGS) nc.o ../util/libNUtil.a $(LIBS) -o $@ help.o: help.c ! $(CC) $(CFLAGS) $(BIGGER_STRINGS) $(EXTRAS) -c help.c -o $@ smartIndent.o: smartIndent.c ! $(CC) $(CFLAGS) $(BIGGER_STRINGS) $(EXTRAS) -c smartIndent.c -o $@ + .c.o: + $(CC) $(CFLAGS) $(EXTRAS) -c $< -o $@ diff -rc nedit.c.orig nedit.c *** nedit.c.orig Thu Mar 19 22:20:23 1998 --- nedit.c Sat Oct 3 02:03:40 1998 *************** *** 84,89 **** --- 84,92 ---- "*text.foreground: black", "*text.highlightBackground: red", "*text.highlightForeground: black", + #ifdef BACKLIGHT_CODE + /* "*text.backlightCharTypes: 32-255:#f0f0f0", */ + #endif "*XmText*foreground: black", "*XmText*background: #cccccc", "*helpText.background: #cccccc", diff -rc text.h.orig text.h *** text.h.orig Thu Mar 19 22:20:25 1998 --- text.h Sat Oct 3 01:53:41 1998 *************** *** 92,97 **** --- 92,102 ---- #define textNemulateTabs "emulateTabs" #define textCEmulateTabs "EmulateTabs" + #ifdef BACKLIGHT_CODE + #define textNbacklightCharTypes "backlightCharTypes" + #define textCBacklightCharTypes "BacklightCharTypes" + #endif + extern WidgetClass textWidgetClass; typedef struct _TextClassRec *TextWidgetClass; diff -rc textP.h.orig textP.h *** textP.h.orig Thu Mar 19 22:20:26 1998 --- textP.h Sat Oct 3 01:49:43 1998 *************** *** 113,118 **** --- 113,122 ---- source text was deleted */ int dragSourceDeleted; /* # of chars. deleted "" */ int dragNLines; /* # of newlines in text being drag'd */ + + #ifdef BACKLIGHT_CODE + XmString backlightCharTypes; /* background class string to parse */ + #endif } TextPart; typedef struct _TextRec { diff -rc text.c.orig text.c *** text.c.orig Thu Mar 19 22:20:25 1998 --- text.c Tue Oct 6 21:41:23 1998 *************** *** 544,549 **** --- 544,553 ---- XtOffset(TextWidget, text.highlightBGPixel), XmRString, "red"}, {textNcursorForeground, textCCursorForeground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.cursorFGPixel), XmRString, "black"}, + #ifdef BACKLIGHT_CODE + {textNbacklightCharTypes,textCBacklightCharTypes,XmRString,sizeof(XmString), + XtOffset(TextWidget, text.backlightCharTypes), XmRString, NULL}, + #endif {textNrows, textCRows, XmRInt,sizeof(int), XtOffset(TextWidget, text.rows), XmRString, "24"}, {textNcolumns, textCColumns, XmRInt, sizeof(int), *************** *** 695,700 **** --- 699,705 ---- buf = BufCreate(); /* Create and initialize the text-display part of the widget */ + #ifndef BACKLIGHT_CODE new->text.textD = TextDCreate((Widget)new, new->text.hScrollBar, new->text.vScrollBar, new->text.marginWidth, new->text.marginHeight, new->core.width - new->text.marginWidth * 2, *************** *** 704,709 **** --- 709,726 ---- new->text.selectBGPixel, new->text.highlightFGPixel, new->text.highlightBGPixel, new->text.cursorFGPixel, new->text.continuousWrap, new->text.wrapMargin); + #else + new->text.textD = TextDCreate((Widget)new, new->text.hScrollBar, + new->text.vScrollBar, new->text.marginWidth, new->text.marginHeight, + new->core.width - new->text.marginWidth * 2, + new->core.height - new->text.marginHeight * 2, + buf, new->text.fontStruct, new->core.background_pixel, + new->primitive.foreground, new->text.selectFGPixel, + new->text.selectBGPixel, new->text.highlightFGPixel, + new->text.highlightBGPixel, new->text.cursorFGPixel, + new->text.continuousWrap, new->text.wrapMargin, + new->text.backlightCharTypes); + #endif /* Add mandatory delimiters blank, tab, and newline to the list of delimiters. The memory use scheme here is that new values are diff -rc textDisp.h.orig textDisp.h *** textDisp.h.orig Thu Mar 19 22:20:25 1998 --- textDisp.h Mon Oct 5 11:34:14 1998 *************** *** 84,91 **** --- 84,98 ---- GC cursorFGGC; /* GC for drawing the cursor */ GC styleGC; /* GC with color and font unspecified for drawing colored/styled text */ + #ifdef BACKLIGHT_CODE + Pixel fgPixel, selectFGPixel; /* Foreground colors */ + Pixel highlightFGPixel; + Pixel *bgClassPixel; /* table of colors for each BG class */ + unsigned char *bgClass; /* obtains index into bgClassPixel[] */ + #endif } textDisp; + #ifndef BACKLIGHT_CODE textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar, Position left, Position top, Position width, Position height, textBuffer *buffer, XFontStruct *fontStruct, Pixel bgPixel, *************** *** 92,97 **** --- 99,112 ---- Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel cursorFGPixel, int continuousWrap, int wrapMargin); + #else + textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar, + Position left, Position top, Position width, Position height, + textBuffer *buffer, XFontStruct *fontStruct, Pixel bgPixel, + Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, + Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel cursorFGPixel, + int continuousWrap, int wrapMargin, XmString bgClassString); + #endif void TextDFree(textDisp *textD); void TextDSetBuffer(textDisp *textD, textBuffer *buffer); textBuffer *TextDGetBuffer(textDisp *textD); diff -rc textDisp.c.orig textDisp.c *** textDisp.c.orig Thu Mar 19 22:20:25 1998 --- textDisp.c Tue Oct 6 20:54:40 1998 *************** *** 38,49 **** --- 38,65 ---- /* Masks for text drawing methods. These are or'd together to form an integer which describes what drawing calls to use to draw a string */ + #ifndef BACKLIGHT_CODE #define FILL_MASK 0x100 #define SECONDARY_MASK 0x200 #define PRIMARY_MASK 0x400 #define HIGHLIGHT_MASK 0x800 #define STYLE_LOOKUP_MASK 0xff + #else + #define FILL_SHIFT 8 + #define SECONDARY_SHIFT 9 + #define PRIMARY_SHIFT 10 + #define HIGHLIGHT_SHIFT 11 + #define STYLE_LOOKUP_SHIFT 0 + #define BACKLIGHT_SHIFT 12 + #define FILL_MASK (1 << FILL_SHIFT) + #define SECONDARY_MASK (1 << SECONDARY_SHIFT) + #define PRIMARY_MASK (1 << PRIMARY_SHIFT) + #define HIGHLIGHT_MASK (1 << HIGHLIGHT_SHIFT) + #define STYLE_LOOKUP_MASK (0xff << STYLE_LOOKUP_SHIFT) + #define BACKLIGHT_MASK (0xff << BACKLIGHT_SHIFT) + #endif + /* Maximum displayable line length (how many characters will fit across the widest window). This amount of memory is temporarily allocated from the stack in the redisplayLine routine for drawing strings */ *************** *** 64,71 **** --- 80,92 ---- static void clearRect(textDisp *textD, int style, int x, int y, int width, int height); static void drawCursor(textDisp *textD, int x, int y); + #ifndef BACKLIGHT_CODE static int styleOfPos(textDisp *textD, int lineStartPos, int lineLen, int lineIndex, int dispIndex); + #else + static int styleOfPos(textDisp *textD, int lineStartPos, + int lineLen, int lineIndex, int dispIndex, int thisChar); + #endif static int stringWidth(textDisp *textD, char *string, int length, int style); static int inSelection(selection *sel, int pos, int lineStartPos, int dispIndex); *************** *** 110,115 **** --- 131,277 ---- static int rangeTouchesRectSel(selection *sel, int rangeStart, int rangeEnd); static void extendRangeForStyleMods(textDisp *textD, int *start, int *end); + #ifdef BACKLIGHT_CODE + /* + ** Allocate a read-only (shareable) colormap cell for a named color, from the + ** the default colormap of the screen on which the widget (w) is displayed. If + ** the colormap is full and there's no suitable substitute, print an error on + ** stderr, and return the widget's background color as a backup. + ** COPIED ALMOST VERBATIM FROM highlight.c: allocColor(). + */ + static Pixel allocBGColor(Widget w, char *colorName) + { + XColor colorDef; + Display *display = XtDisplay(w); + int screenNum = XScreenNumberOfScreen(XtScreen(w)); + Colormap cMap = DefaultColormap(display, screenNum); + Pixel background; + + /* Allocate and return the color cell, or print an error and fall through */ + if (XParseColor(display, cMap, colorName, &colorDef)) { + if (XAllocColor(display, cMap, &colorDef)) + return colorDef.pixel; + else + fprintf(stderr, "NEdit: Can't allocate color: %s\n", colorName); + } else + fprintf(stderr, "NEdit: Color name %s not in database\n", colorName); + + /* Color cell couldn't be allocated, return the widget's background color */ + XtVaGetValues(w, XmNbackground, &background, 0); + return background; + } + + /* + ** Read the background color class specification string in str, allocating the + ** necessary colors, and allocating and setting up the character->class_no and + ** class_no->pixel map arrays, returned via *pp_bgClass and *pp_bgClassPixel + ** respectively. + ** Note: the allocation of class numbers could be more intelligent: there can + ** never be more than 256 of these (one per character); but I don't think + ** there'll be a pressing need. I suppose the scanning of the specification + ** could be better too, but then, who cares! + */ + static void SetupBGClasses(Widget w, XmString str, Pixel **pp_bgClassPixel, + unsigned char **pp_bgClass, Pixel bgPixelDefault) + { + unsigned char bgClass[256]; + Pixel bgClassPixel[256]; + int class_no = 0; + char *semicol; + char *s = (char *)str; + size_t was_semicol; + int lo, hi; + char *pos; + Boolean is_good = True; + + *pp_bgClassPixel = NULL; + *pp_bgClass = NULL; + + if (!s) + return; + + /* default for all chars is class number zero, for standard background */ + memset(bgClassPixel, 0, sizeof bgClassPixel); + memset(bgClass, 0, sizeof bgClass); + bgClassPixel[0] = bgPixelDefault; + /* since class no == 0 in a "style" has no set bits in BACKLIGHT_MASK + (see styleOfPos()), when drawString() is called for text with a + backlight class no of zero, bgClassPixel[0] is never consulted, and + the default background color is chosen. */ + + /* The format of the class string s is: + low[-high]{,low[-high]}:color{;low-high{,low[-high]}:color} + eg + 32-255:#f0f0f0;1-31,127:red;128-159:orange;9-13:#e5e5e5 + where low and high represent a character range between ordinal + ASCII values. Using strtol() allows automatic octal, dec and hex + reading of low and high. The example format sets backgrounds as follows: + char 1 - 8 colored red (control characters) + char 9 - 13 colored #e5e5e5 (isspace() control characters) + char 14 - 31 colored red (control characters) + char 32 - 126 colored #f0f0f0 + char 127 colored red (delete character) + char 128 - 159 colored orange ("shifted" control characters) + char 160 - 255 colored #f0f0f0 + Notice that some of the later ranges overwrite the class values defined + for earlier ones (eg the first clause, 32-255:#f0f0f0 sets the DEL + character background color to #f0f0f0; it is then set to red by the + clause 1-31,127:red). */ + + while (s && class_no < 255) { + class_no++; /* simple class alloc scheme */ + was_semicol = 0; + is_good = True; + if ((semicol = (char *)strchr(s, ';'))) { + *semicol = '\0'; /* null-terminate low[-high]:color clause */ + was_semicol = 1; + } + + /* loop over ranges before the color spec, assigning the characters + in the ranges to the current class number */ + for (lo = hi = strtol(s, &pos, 0); + is_good; + lo = hi = strtol(pos + 1, &pos, 0)) { + if (pos && *pos == '-') + hi = strtol(pos + 1, &pos, 0); /* get end of range */ + is_good = (pos && 0 <= lo && lo <= hi && hi <= 255); + if (is_good) + while (lo <= hi) + bgClass[lo++] = (unsigned char)class_no; + if (*pos != ',') + break; + } + if ((is_good = (is_good && *pos == ':'))) { + is_good = (*pos++ != '\0'); /* pos now points to color */ + bgClassPixel[class_no] = allocBGColor(w, pos); + } + if (!is_good) { + /* complain? this class spec clause (in string s) was faulty */ + } + + /* end of loop iterator clauses */ + if (was_semicol) + *semicol = ';'; /* un-null-terminate low[-high]:color clause */ + s = semicol + was_semicol; + } + /* when we get here, we've set up our class table and class-to-pixel table + in local variables: now put them into the "real thing" */ + if (class_no) { + class_no++; /* bigger than all valid class_nos */ + *pp_bgClass = (unsigned char *)XtMalloc(256); + *pp_bgClassPixel = (Pixel *)XtMalloc(class_no * sizeof (Pixel)); + if (!*pp_bgClass || !*pp_bgClassPixel) { + XtFree((char *)*pp_bgClass); + XtFree((char *)*pp_bgClassPixel); + return; + } + memcpy(*pp_bgClass, bgClass, 256); + memcpy(*pp_bgClassPixel, bgClassPixel, class_no * sizeof (Pixel)); + } + } + #endif + + #ifndef BACKLIGHT_CODE textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar, Position left, Position top, Position width, Position height, textBuffer *buffer, XFontStruct *fontStruct, Pixel bgPixel, *************** *** 116,121 **** --- 278,291 ---- Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel cursorFGPixel, int continuousWrap, int wrapMargin) + #else + textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar, + Position left, Position top, Position width, Position height, + textBuffer *buffer, XFontStruct *fontStruct, Pixel bgPixel, + Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, + Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel cursorFGPixel, + int continuousWrap, int wrapMargin, XmString bgClassString) + #endif { textDisp *textD; XGCValues gcValues; *************** *** 152,157 **** --- 322,332 ---- textD->styleTable = NULL; textD->nStyles = 0; textD->bgPixel = bgPixel; + #ifdef BACKLIGHT_CODE + textD->fgPixel = fgPixel; + textD->selectFGPixel = selectFGPixel; + textD->highlightFGPixel = highlightFGPixel; + #endif textD->selectBGPixel = selectBGPixel; textD->highlightBGPixel = highlightBGPixel; textD->wrapMargin = wrapMargin; *************** *** 169,174 **** --- 344,353 ---- for (i=1; inVisibleLines; i++) textD->lineStarts[i] = -1; + #ifdef BACKLIGHT_CODE + SetupBGClasses(widget, bgClassString, &textD->bgClassPixel, + &textD->bgClass, bgPixel); + #endif /* Attach an event handler to the widget so we can know the visibility (used for choosing the fastest drawing method) */ XtAddEventHandler(widget, VisibilityChangeMask, False, *************** *** 221,226 **** --- 400,411 ---- releaseGC(textD->w, textD->highlightBGGC); releaseGC(textD->w, textD->styleGC); XtFree((char *)textD->lineStarts); + + #ifdef BACKLIGHT_CODE + XtFree((char *)textD->bgClassPixel); + XtFree((char *)textD->bgClass); + #endif + XtFree((char *)textD); } *************** *** 769,776 **** --- 954,966 ---- for(charIndex=0; charIndexbuffer->tabDist, textD->buffer->nullSubsChar); + #ifndef BACKLIGHT_CODE charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex); + #else + charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, + outIndex, lineStr[charIndex]); + #endif xStep += stringWidth(textD, expandedChar, charLen, charStyle); outIndex += charLen; } *************** *** 1259,1264 **** --- 1449,1457 ---- int stdCharWidth, charWidth, startIndex, charStyle, style; int charLen, outStartIndex, outIndex, cursorX, hasCursor = False; int dispIndexOffset, cursorPos = textD->cursorPos; + #ifdef BACKLIGHT_CODE + char baseChar; + #endif char expandedChar[MAX_EXP_CHAR_LEN], outStr[MAX_DISP_LINE_LEN]; char *lineStr, *outPtr; *************** *** 1318,1328 **** --- 1511,1530 ---- x = textD->left - textD->horizOffset; outIndex = 0; for(charIndex=0; ; charIndex++) { + #ifndef BACKLIGHT_CODE charLen = charIndex >= lineLen ? 1 : BufExpandCharacter(lineStr[charIndex], outIndex, expandedChar, buf->tabDist, buf->nullSubsChar); style = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset); + #else + baseChar = '\0'; + charLen = charIndex >= lineLen ? 1 : + BufExpandCharacter(baseChar = lineStr[charIndex], outIndex, + expandedChar, buf->tabDist, buf->nullSubsChar); + style = styleOfPos(textD, lineStartPos, lineLen, charIndex, + outIndex + dispIndexOffset, baseChar); + #endif charWidth = charIndex >= lineLen ? stdCharWidth : stringWidth(textD, expandedChar, charLen, style); if (x + charWidth >= leftClip && charIndex >= leftCharIndex) { *************** *** 1355,1369 **** --- 1557,1586 ---- } } } + #ifndef BACKLIGHT_CODE charLen = charIndex >= lineLen ? 1 : BufExpandCharacter(lineStr[charIndex], outIndex, expandedChar, buf->tabDist, buf->nullSubsChar); charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset); + #else + baseChar = '\0'; + charLen = charIndex >= lineLen ? 1 : + BufExpandCharacter(baseChar = lineStr[charIndex], outIndex, + expandedChar, buf->tabDist, buf->nullSubsChar); + charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, + outIndex + dispIndexOffset, baseChar); + #endif for (i=0; istyleGC ; gcValues.font = fs->fid; gcValues.foreground = styleRec->color; + #ifndef BACKLIGHT_CODE gcValues.background = style&PRIMARY_MASK ? textD->selectBGPixel : style&HIGHLIGHT_MASK ? textD->highlightBGPixel : textD->bgPixel; + #else + gcValues.background = + style&PRIMARY_MASK ? textD->selectBGPixel : + style&HIGHLIGHT_MASK ? textD->highlightBGPixel : + style&BACKLIGHT_MASK ? + textD->bgClassPixel[(style>>BACKLIGHT_SHIFT) & 0xff] : + textD->bgPixel; + #endif if (gcValues.foreground == gcValues.background) /* B&W kludge */ gcValues.foreground = textD->bgPixel; XChangeGC(XtDisplay(textD->w), gc, *************** *** 1454,1459 **** --- 1680,1700 ---- gc = textD->highlightGC; else if (style & PRIMARY_MASK) gc = textD->selectGC; + #ifdef BACKLIGHT_CODE + else if (style & BACKLIGHT_MASK) { + /* Uses the syntax highlighting style GC, changing it as needed. */ + fs = textD->fontStruct; + gc = textD->styleGC; + gcValues.font = fs->fid; + gcValues.foreground = textD->fgPixel; + gcValues.background = + textD->bgClassPixel[(style>>BACKLIGHT_SHIFT) & 0xff]; + if (gcValues.foreground == gcValues.background) /* B&W kludge */ + gcValues.foreground = textD->bgPixel; + XChangeGC(XtDisplay(textD->w), gc, + GCFont | GCForeground | GCBackground, &gcValues); + } + #endif else gc = textD->gc; *************** *** 1578,1585 **** --- 1819,1831 ---- ** Note that style is a somewhat incorrect name, drawing method would ** be more appropriate. */ + #ifndef BACKLIGHT_CODE static int styleOfPos(textDisp *textD, int lineStartPos, int lineLen, int lineIndex, int dispIndex) + #else + static int styleOfPos(textDisp *textD, int lineStartPos, + int lineLen, int lineIndex, int dispIndex, int thisChar) + #endif { textBuffer *buf = textD->buffer; textBuffer *styleBuf = textD->styleBuffer; *************** *** 1606,1611 **** --- 1852,1864 ---- style |= HIGHLIGHT_MASK; if (inSelection(&buf->secondary, pos, lineStartPos, dispIndex)) style |= SECONDARY_MASK; + #ifdef BACKLIGHT_CODE + /* store in the BACKLIGHT_MASK portion of style the background color class + of the character thisChar */ + if (textD->bgClass) { + style |= (textD->bgClass[(unsigned char)thisChar]<buffer->tabDist, textD->buffer->nullSubsChar); + #ifndef BACKLIGHT_CODE charStyle = styleOfPos(textD, lineStart, lineLen, charIndex, outIndex); + #else + charStyle = styleOfPos(textD, lineStart, lineLen, charIndex, outIndex, + lineStr[charIndex]); + #endif charWidth = stringWidth(textD, expandedChar, charLen, charStyle); if (x < xStep + (posType == CURSOR_POS ? charWidth/2 : charWidth)) { XtFree(lineStr);