#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "textDisp.h"
#include "textBuf.h"
#include "text.h"
#include "textP.h"
#include "nedit.h"
#include "calltips.h"
#include "highlight.h"
#include "rangeset.h"
#include "../util/nedit_malloc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#ifndef __MVS__
#include <sys/param.h>
#endif
#include <Xm/Xm.h>
#include <Xm/ScrolledW.h>
#include <Xm/ScrollBar.h>
#include <Xm/Label.h>
#include <X11/Shell.h>
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
#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)
#define RANGESET_SHIFT (
20)
#define RANGESET_MASK (0x3F <<
RANGESET_SHIFT)
#define MAX_DISP_LINE_LEN 1000
#define TEXT_OF_TEXTD(t) (((TextWidget)((t)->w))->text)
#define MCURSOR_ALLOC 8
#define MCURSOR_MAX 1024
#define MCURSOR_ALLOC_RESET 32
enum positionTypes {
CURSOR_POS,
CHARACTER_POS};
static void updateLineStarts(textDisp *textD,
int pos,
int charsInserted,
int charsDeleted,
int linesInserted,
int linesDeleted,
int *scrolled);
static void offsetLineStarts(textDisp *textD,
int newTopLineNum);
static void calcLineStarts(textDisp *textD,
int startLine,
int endLine);
static void calcLastChar(textDisp *textD);
static int posToVisibleLineNum(textDisp *textD,
int pos,
int *lineNum);
static int getCharWidth(textDisp *textD,
const char *src_orig, FcChar32 *dst,
int len);
static FcChar32 getCharacter32(
const textDisp *textD,
const textBuffer* buf,
int pos,
int *charlen);
static void redisplayLine(textDisp *textD,
int visLineNum,
int leftClip,
int rightClip,
int leftCharIndex,
int rightCharIndex);
static void drawString(textDisp *textD,
int style,
int rbIndex,
int x,
int y,
int fromX,
int toX, FcChar32 *string,
int nChars, Boolean highlightLine, ansiStyle *ansi);
static void clearRect(textDisp *textD, XftColor *color,
int x,
int y,
int width,
int height);
static void drawCursor(textDisp *textD,
int x,
int y);
static int styleOfPos(textDisp *textD,
int lineStartPos,
int lineLen,
int lineIndex,
int dispIndex,
int thisChar);
static int charWidth4(
const textDisp* textD,
const FcChar32* string,
int length, NFont *font);
static NFont* styleFontList(
const textDisp* textD,
int style);
static int inSelection(selection *sel,
int pos,
int lineStartPos,
int dispIndex);
static int xyToPos(textDisp *textD,
int x,
int y,
int posType);
static void xyToUnconstrainedPos(textDisp *textD,
int x,
int y,
int *row,
int *column,
int posType);
static void bufPreDeleteCB(
int pos,
int nDeleted,
void *cbArg);
static void bufModifiedCB(
int pos,
int nInserted,
int nDeleted,
int nRestyled,
const char *deletedText,
void *cbArg);
static void setScroll(textDisp *textD,
int topLineNum,
int horizOffset,
int updateVScrollBar,
int updateHScrollBar);
static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData);
static void vScrollCB(Widget w, XtPointer clientData, XtPointer callData);
static void visibilityEH(Widget w, XtPointer data, XEvent *event,
Boolean *continueDispatch);
static void redrawLineNumbers(textDisp *textD,
int top,
int height,
int clearAll);
static void updateVScrollBarRange(textDisp *textD);
static int updateHScrollBarRange(textDisp *textD);
static int max(
int i1,
int i2);
static int min(
int i1,
int i2);
static int countLines(
const char *string);
static int measureVisLine(textDisp *textD,
int visLineNum);
static int emptyLinesVisible(textDisp *textD);
static void blankSingleCursorProtrusions(textDisp *textD);
static void blankCursorProtrusions(textDisp *textD);
static void allocateFixedFontGCs(textDisp *textD, Pixel bgPixel, Pixel fgPixel);
static GC allocateGC(Widget w,
unsigned long valueMask,
unsigned long foreground,
unsigned long background, Font font,
unsigned long dynamicMask,
unsigned long dontCareMask);
static void releaseGC(Widget w,
GC gc);
static void resetClipRectangles(textDisp *textD);
static int visLineLength(textDisp *textD,
int visLineNum);
static void measureDeletedLines(textDisp *textD,
int pos,
int nDeleted);
static int findWrapRange(textDisp *textD,
const char *deletedText,
int pos,
int nInserted,
int nDeleted,
int *modRangeStart,
int *modRangeEnd,
int *linesInserted,
int *linesDeleted);
static void wrappedLineCounter(
const textDisp* textD,
const textBuffer* buf,
int startPos,
int maxPos,
int maxLines,
Boolean startPosIsLineStart,
int styleBufOffset,
int* retPos,
int* retLines,
int* retLineStart,
int* retLineEnd,
Boolean *retWrap);
static void findLineEnd(textDisp *textD,
int startPos,
int startPosIsLineStart,
int *lineEnd,
int *nextLineStart);
static int wrapUsesCharacter(textDisp *textD,
int lineEndPos);
static void hideOrShowHScrollBar(textDisp *textD);
static int rangeTouchesRectSel(selection *sel,
int rangeStart,
int rangeEnd);
static void extendRangeForStyleMods(textDisp *textD,
int *start,
int *end);
static int getAbsTopLineNum(textDisp *textD);
static void offsetAbsLineNum(textDisp *textD,
int oldFirstChar);
static int maintainingAbsTopLineNum(textDisp *textD);
static void resetAbsLineNum(textDisp *textD);
static int measurePropChar(
const textDisp* textD, FcChar32 c,
int colNum,
int pos);
static XftColor allocBGColor(Widget w,
char *colorName,
int *ok);
static XftColor* getRangesetColor(textDisp *textD,
int ind, XftColor *bground);
static void textDRedisplayRange(textDisp *textD,
int start,
int end);
static void findActiveAnsiStyle(textDisp *textD,
ssize_t pos, ansiStyle *style);
static int parseEscapeSequence(textBuffer *buf,
size_t pos, ansiStyle *style);
static void extendAnsiStyle(ansiStyle *style, ansiStyle *ext);
static void ansiFgToColorIndex(textDisp *textD,
short fg, XftColor *color);
static void ansiBgToColorIndex(textDisp *textD,
short bg, XftColor *color);
textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar,
Position left, Position top, Position width, Position height,
Position lineNumLeft, Position lineNumWidth, Position marginWidth,
textBuffer *buffer, NFont *font, NFont *bold, NFont *italic,
NFont *boldItalic, ColorProfile *colorProfile,
int continuousWrap,
int wrapMargin, XmString bgClassString, Pixel calltipFGPixel,
Pixel calltipBGPixel, Pixel lineHighlightBGPixel, Boolean indentRainbow,
Boolean highlightCursorLine, Boolean ansiColors)
{
textDisp *textD;
XGCValues gcValues;
int i;
XftFont *xftFont = FontDefault(font);
textD = (textDisp *)NEditMalloc(
sizeof(textDisp));
textD->w = widget;
textD->d =
NULL;
textD->top = top;
textD->left = left;
textD->width = width;
textD->height = height;
textD->marginWidth = marginWidth;
textD->cursorOn = True;
textD->cursorToHint =
NO_HINT;
textD->cursorStyle =
NORMAL_CURSOR;
textD->xic_x =
0;
textD->xic_y =
0;
textD->buffer = buffer;
textD->firstChar =
0;
textD->lastChar =
0;
textD->nBufferLines =
0;
textD->topLineNum =
1;
textD->absTopLineNum =
1;
textD->needAbsTopLineNum = False;
textD->horizOffset =
0;
textD->visibility = VisibilityUnobscured;
textD->hScrollBar = hScrollBar;
textD->vScrollBar = vScrollBar;
textD->font = FontRef(font);
textD->boldFont = FontRef(bold);
textD->italicFont = FontRef(italic);
textD->boldItalicFont = FontRef(boldItalic);
textD->ascent = xftFont->ascent;
textD->descent = xftFont->descent;
textD->fixedFontWidth = -
1;
textD->styleBuffer =
NULL;
textD->styleTable =
NULL;
textD->nStyles =
0;
textD->colorProfile = colorProfile;
textD->wrapMargin = wrapMargin;
textD->continuousWrap = continuousWrap;
allocateFixedFontGCs(
textD, colorProfile->textBgColor.pixel, colorProfile->textFgColor.pixel);
textD->lineNumLeft = lineNumLeft;
textD->lineNumWidth = lineNumWidth;
textD->nVisibleLines = (height -
1) / (textD->ascent + textD->descent) +
1;
gcValues.foreground = colorProfile->cursorFgColor.pixel;
textD->cursorFGGC = XtGetGC(widget, GCForeground, &gcValues);
textD->lineStarts = (
int *)NEditMalloc(
sizeof(
int) * textD->nVisibleLines);
textD->lineStarts[
0] =
0;
textD->calltipW =
NULL;
textD->calltipShell =
NULL;
textD->calltip.
ID =
0;
textD->calltipFGPixel = calltipFGPixel;
textD->calltipBGPixel = calltipBGPixel;
for (i=
1; i<textD->nVisibleLines; i++)
textD->lineStarts[i] = -
1;
textD->bgClassPixel =
NULL;
textD->bgClass =
NULL;
TextDSetupBGClasses(widget, bgClassString, &textD->bgClassPixel,
&textD->bgClass, colorProfile->textBgColor);
textD->suppressResync =
0;
textD->nLinesDeleted =
0;
textD->modifyingTabDist =
0;
textD->pointerHidden = False;
textD->disableRedisplay = False;
textD->fixLeftClipAfterResize = False;
textD->graphicsExposeQueue =
NULL;
textD->indentRainbow = indentRainbow;
textD->highlightCursorLine = highlightCursorLine;
textD->redrawCursorLine = False;
textD->mcursorAlloc =
MCURSOR_ALLOC;
textD->mcursorSize =
1;
textD->mcursorSizeReal =
1;
textD->multicursor = NEditCalloc(
MCURSOR_ALLOC,
sizeof(textCursor));
textD->mcursorOn =
FALSE;
textD->multicursor[
0].cursorPos =
0;
textD->multicursor[
0].cursorPosCache = -
1;
textD->multicursor[
0].cursorPosCacheLeft =
0;
textD->multicursor[
0].cursorPosCacheRight =
0;
textD->multicursor[
0].cursorPreferredCol = -
1;
textD->multicursor[
0].x = -
100;
textD->multicursor[
0].y = -
100;
textD->cursor = textD->multicursor;
textD->newcursor = textD->multicursor;
textD->cacheNoWrappingWidth =
0;
textD->cacheNoWrapping = False;
TextDSetAnsiColors(textD, ansiColors);
XtAddEventHandler(widget, VisibilityChangeMask, False,
visibilityEH, textD);
if (buffer !=
NULL) {
BufAddModifyCB(buffer, bufModifiedCB, textD);
BufAddPreDeleteCB(buffer, bufPreDeleteCB, textD);
}
if (vScrollBar !=
NULL) {
XtVaSetValues(vScrollBar, XmNminimum,
1, XmNmaximum,
2,
XmNsliderSize,
1, XmNrepeatDelay,
10, XmNvalue,
1,
NULL);
XtAddCallback(vScrollBar, XmNdragCallback, vScrollCB, (XtPointer)textD);
XtAddCallback(vScrollBar, XmNvalueChangedCallback, vScrollCB,
(XtPointer)textD);
}
if (hScrollBar !=
NULL) {
XtVaSetValues(hScrollBar, XmNminimum,
0, XmNmaximum,
1,
XmNsliderSize,
1, XmNrepeatDelay,
10, XmNvalue,
0,
XmNincrement, font->maxWidth,
NULL);
XtAddCallback(hScrollBar, XmNdragCallback, hScrollCB, (XtPointer)textD);
XtAddCallback(hScrollBar, XmNvalueChangedCallback, hScrollCB,
(XtPointer)textD);
}
if (buffer !=
NULL)
bufModifiedCB(
0, buffer->length,
0,
0,
NULL, textD);
hideOrShowHScrollBar(textD);
return textD;
}
void TextDInitXft(textDisp *textD) {
XWindowAttributes attributes;
XGetWindowAttributes(XtDisplay(textD->w), XtWindow(textD->w), &attributes);
Screen *screen = textD->w->core.screen;
Visual *visual = screen->root_visual;
for(
int i=
0;i<screen->ndepths;i++) {
Depth d = screen->depths[i];
if(d.depth == textD->w->core.depth) {
visual = d.visuals;
break;
}
}
Display *dp = XtDisplay(textD->w);
textD->d = XftDrawCreate(
dp,
XtWindow(textD->w),
visual,
textD->w->core.colormap);
}
void TextDFree(textDisp *textD)
{
FontUnref(textD->font);
FontUnref(textD->boldFont);
FontUnref(textD->italicFont);
FontUnref(textD->boldItalicFont);
NEditFree(textD->multicursor);
BufRemoveModifyCB(textD->buffer, bufModifiedCB, textD);
BufRemovePreDeleteCB(textD->buffer, bufPreDeleteCB, textD);
releaseGC(textD->w, textD->gc);
NEditFree(textD->lineStarts);
while (TextDPopGraphicExposeQueueEntry(textD)) {
}
NEditFree(textD->bgClassPixel);
NEditFree(textD->bgClass);
NEditFree(textD);
}
void TextDSetBuffer(textDisp *textD, textBuffer *buffer)
{
if (textD->buffer !=
NULL) {
bufModifiedCB(
0,
0, textD->buffer->length,
0,
NULL, textD);
BufRemoveModifyCB(textD->buffer, bufModifiedCB, textD);
BufRemovePreDeleteCB(textD->buffer, bufPreDeleteCB, textD);
}
textD->buffer = buffer;
BufAddModifyCB(buffer, bufModifiedCB, textD);
BufAddPreDeleteCB(buffer, bufPreDeleteCB, textD);
bufModifiedCB(
0, buffer->length,
0,
0,
NULL, textD);
}
void TextDAttachHighlightData(textDisp *textD, textBuffer *styleBuffer,
styleTableEntry *styleTable,
int nStyles,
char unfinishedStyle,
unfinishedStyleCBProc unfinishedHighlightCB,
void *cbArg)
{
textD->styleBuffer = styleBuffer;
textD->styleTable = styleTable;
textD->nStyles = nStyles;
textD->unfinishedStyle = unfinishedStyle;
textD->unfinishedHighlightCB = unfinishedHighlightCB;
textD->highlightCBArg = cbArg;
TextDSetFont(textD, textD->font);
}
void TextDSetColorProfile(textDisp *textD, ColorProfile *profile)
{
XGCValues values;
Display *d = XtDisplay(textD->w);
textD->colorProfile = profile;
releaseGC(textD->w, textD->gc);
allocateFixedFontGCs(textD, profile->textBgColor.pixel, profile->textFgColor.pixel);
values.foreground = profile->cursorFgColor.pixel;
XChangeGC( d, textD->cursorFGGC, GCForeground, &values );
TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
textD->height);
redrawLineNumbers(textD, textD->top, textD->height, True);
}
void TextDSetFont(textDisp *textD, NFont *font)
{
XftFont *fontStruct = FontDefault(font);
int i, maxAscent = fontStruct->ascent, maxDescent = fontStruct->descent;
int width, height;
XftFont *styleFont;
NFont *styleFontList;
if(!textD->disableRedisplay) {
blankCursorProtrusions(textD);
}
for (i=
0; i<textD->nStyles; i++) {
styleFontList = textD->styleTable[i].font;
styleFont = styleFontList ? FontDefault(styleFontList) :
NULL;
if (styleFont !=
NULL && styleFont->ascent > maxAscent)
maxAscent = styleFont->ascent;
if (styleFont !=
NULL && styleFont->descent > maxDescent)
maxDescent = styleFont->descent;
}
textD->ascent = maxAscent;
textD->descent = maxDescent;
textD->fixedFontWidth = -
1;
if (textD->height < maxAscent + maxDescent)
textD->height = maxAscent + maxDescent;
if(textD->font != font) {
FontUnref(textD->font);
textD->font = FontRef(font);
}
if(textD->disableRedisplay) {
return;
}
width = textD->width;
height = textD->height;
textD->width = textD->height =
0;
TextDResize(textD, width, height);
clearRect(textD, &textD->colorProfile->textBgColor, textD->left,
textD->top + textD->height - maxAscent - maxDescent,
textD->width, maxAscent + maxDescent);
TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
textD->height);
redrawLineNumbers(textD, textD->top, textD->height, True);
}
void TextDSetBoldFont(textDisp *textD, NFont *boldFont)
{
if(textD->boldFont != boldFont) {
FontUnref(textD->boldFont);
textD->boldFont = FontRef(boldFont);
}
}
void TextDSetItalicFont(textDisp *textD, NFont *italicFont)
{
if(textD->italicFont != italicFont) {
FontUnref(textD->italicFont);
textD->italicFont = FontRef(italicFont);
}
}
void TextDSetBoldItalicFont(textDisp *textD, NFont *boldItalicFont)
{
if(textD->boldItalicFont != boldItalicFont) {
FontUnref(textD->boldItalicFont);
textD->boldItalicFont = FontRef(boldItalicFont);
}
}
int TextDMinFontWidth(textDisp *textD, Boolean considerStyles)
{
int fontWidth = textD->font->minWidth;
int i;
if (considerStyles) {
for (i =
0; i < textD->nStyles; ++i) {
int thisWidth = (textD->styleTable[i].font)->minWidth;
if (thisWidth < fontWidth) {
fontWidth = thisWidth;
}
}
}
return fontWidth;
}
int TextDMaxFontWidth(textDisp *textD, Boolean considerStyles)
{
int fontWidth = textD->font->maxWidth;
int i;
if (considerStyles) {
for (i =
0; i < textD->nStyles; ++i) {
int thisWidth = textD->styleTable[i].font->maxWidth;
if (thisWidth > fontWidth) {
fontWidth = thisWidth;
}
}
}
return fontWidth;
}
void TextDResize(textDisp *textD,
int width,
int height)
{
int oldVisibleLines = textD->nVisibleLines;
int canRedraw = XtWindow(textD->w) !=
0;
int newVisibleLines = height / (textD->ascent + textD->descent);
int redrawAll = False;
int oldWidth = textD->width;
int exactHeight = height - height % (textD->ascent + textD->descent);
if(width > oldWidth) {
textD->fixLeftClipAfterResize = True;
}
textD->width = width;
textD->height = height;
if(width < textD->cacheNoWrappingWidth) {
textD->cacheNoWrapping = False;
}
if (textD->continuousWrap && textD->wrapMargin==
0 && width!=oldWidth && !textD->cacheNoWrapping) {
Boolean wrap0 = False;
Boolean wrap1 = False;
int oldFirstChar = textD->firstChar;
textD->firstChar = TextDStartOfLine(textD, textD->firstChar);
int toplinenum = TextDCountLinesW(textD,
0, textD->firstChar, True, &wrap0);
int count = TextDCountLinesW(textD, textD->firstChar, textD->buffer->length, True, &wrap1);
textD->nBufferLines = toplinenum + count;
if(!(wrap0 || wrap1)) {
textD->cacheNoWrapping = True;
textD->cacheNoWrappingWidth = width;
}
textD->topLineNum = toplinenum+
1;
redrawAll = True;
offsetAbsLineNum(textD, oldFirstChar);
}
if (oldVisibleLines < newVisibleLines) {
NEditFree(textD->lineStarts);
textD->lineStarts = (
int *)NEditMalloc(
sizeof(
int) * newVisibleLines);
}
textD->nVisibleLines = newVisibleLines;
calcLineStarts(textD,
0, newVisibleLines);
calcLastChar(textD);
if (canRedraw && oldVisibleLines>newVisibleLines && exactHeight!=height)
XClearArea(XtDisplay(textD->w), XtWindow(textD->w), textD->left,
textD->top + exactHeight, textD->width,
height - exactHeight, False);
if (canRedraw && oldVisibleLines < newVisibleLines && textD->topLineNum +
textD->nVisibleLines > textD->nBufferLines)
setScroll(textD, max(
1, textD->nBufferLines - textD->nVisibleLines +
2 +
TEXT_OF_TEXTD(textD).cursorVPadding),
textD->horizOffset, False, False);
updateVScrollBarRange(textD);
if (updateHScrollBarRange(textD))
redrawAll = True;
if (redrawAll && canRedraw)
TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
textD->height);
hideOrShowHScrollBar(textD);
redrawLineNumbers(textD, textD->top, textD->height, True);
TextDRedrawCalltip(textD,
0);
}
void TextDRedisplayRect(textDisp *textD,
int left,
int top,
int width,
int height)
{
int fontHeight, firstLine, lastLine, line;
if(textD->fixLeftClipAfterResize) {
int changeLeftClip = textD->font->fonts->font->max_advance_width;
if(left > changeLeftClip) {
left -= changeLeftClip;
width += changeLeftClip;
}
textD->fixLeftClipAfterResize = False;
}
fontHeight = textD->ascent + textD->descent;
firstLine = (top - textD->top - fontHeight +
1) / fontHeight;
lastLine = (top + height - textD->top) / fontHeight;
resetClipRectangles(textD);
for (line=firstLine; line<=lastLine; line++)
redisplayLine(textD, line, left-textD->marginWidth, left+width,
0,
INT_MAX);
if (textD->lineNumWidth !=
0 && left <= textD->lineNumLeft + textD->lineNumWidth) {
redrawLineNumbers(textD, top, height, True);
}
}
static void textDRedisplayRange(textDisp *textD,
int start,
int end)
{
int i, startLine, lastLine, startIndex, endIndex;
if (end < textD->firstChar || (start > textD->lastChar &&
!emptyLinesVisible(textD)))
return;
if (start <
0) start =
0;
if (start > textD->buffer->length) start = textD->buffer->length;
if (end <
0) end =
0;
if (end > textD->buffer->length) end = textD->buffer->length;
if (start < textD->firstChar) {
start = textD->firstChar;
}
if (!posToVisibleLineNum(textD, start, &startLine)) {
startLine = textD->nVisibleLines -
1;
}
if (end >= textD->lastChar) {
lastLine = textD->nVisibleLines -
1;
}
else {
if (!posToVisibleLineNum(textD, end, &lastLine)) {
lastLine = textD->nVisibleLines -
1;
}
}
startIndex = (textD->lineStarts[startLine] == -
1)
?
0
: start - textD->lineStarts[startLine];
if (end >= textD->lastChar)
{
endIndex =
INT_MAX;
}
else if (textD->lineStarts[lastLine] == -
1)
{
endIndex =
0;
}
else
{
endIndex = end - textD->lineStarts[lastLine];
}
resetClipRectangles(textD);
if (startLine == lastLine) {
redisplayLine(textD, startLine,
0,
INT_MAX, startIndex, endIndex);
return;
}
redisplayLine(textD, startLine,
0,
INT_MAX, startIndex,
INT_MAX);
for (i=startLine+
1; i<lastLine; i++)
redisplayLine(textD, i,
0,
INT_MAX,
0,
INT_MAX);
redisplayLine(textD, lastLine,
0,
INT_MAX,
0, endIndex);
}
void TextDSetScroll(textDisp *textD,
int topLineNum,
int horizOffset)
{
int sliderSize, sliderMax;
int vPadding = (
int)(
TEXT_OF_TEXTD(textD).cursorVPadding);
if (topLineNum <
1)
topLineNum =
1;
else if ((topLineNum > textD->topLineNum) &&
(topLineNum > (textD->nBufferLines +
2 - textD->nVisibleLines +
vPadding)))
topLineNum = max(textD->topLineNum,
textD->nBufferLines +
2 - textD->nVisibleLines + vPadding);
XtVaGetValues(textD->hScrollBar, XmNmaximum, &sliderMax,
XmNsliderSize, &sliderSize,
NULL);
if (horizOffset <
0)
horizOffset =
0;
if (horizOffset > sliderMax - sliderSize)
horizOffset = sliderMax - sliderSize;
setScroll(textD, topLineNum, horizOffset, True, True);
}
void TextDGetScroll(textDisp *textD,
int *topLineNum,
int *horizOffset)
{
*topLineNum = textD->topLineNum;
*horizOffset = textD->horizOffset;
}
void TextDSetInsertPosition(textDisp *textD,
int newPos)
{
int oldLineStart, newLineStart, oldLineEnd, newLineEnd;
Boolean hiline = False;
if(textD->highlightCursorLine) {
oldLineStart = BufStartOfLine(textD->buffer, textD->cursor->cursorPos);
newLineStart = BufStartOfLine(textD->buffer, newPos);
if(oldLineStart != newLineStart || textD->mcursorOn || textD->redrawCursorLine) {
hiline = True;
oldLineEnd = BufEndOfLine(textD->buffer, textD->cursor->cursorPos);
newLineEnd = BufEndOfLine(textD->buffer, newPos);
textD->cursor->cursorPos = -
1;
}
}
Boolean redrawTextWidget =
0;
if(TextDClearMultiCursor(textD)) {
redrawTextWidget = True;
textD->cursor = textD->multicursor;
}
else if (newPos == textD->cursor->cursorPos) {
return;
}
if (newPos <
0) newPos =
0;
if (newPos > textD->buffer->length) newPos = textD->buffer->length;
textD->cursor->cursorPreferredCol = -
1;
TextDBlankCursor(textD);
textD->cursor->cursorPos = newPos;
textD->cursorOn = True;
if(redrawTextWidget) {
TextDRedisplayRect(textD,
0, textD->top, textD->width + textD->left, textD->height);
return;
}
int left, right;
TextDCursorLR(textD, &left, &right);
textDRedisplayRange(textD, left, right);
if(hiline) {
int oldLine = -
1, newLine = -
1, oldLine2 = -
1, newLine2 = -
1;
posToVisibleLineNum(textD, newLineStart, &newLine);
posToVisibleLineNum(textD, newLineEnd, &newLine2);
if(newLine == -
1 && newLine2 >=
0) {
newLine =
0;
}
if(newLine2 == -
1 && newLine >=
0) {
newLine2 = textD->nVisibleLines-
1;
}
posToVisibleLineNum(textD, oldLineStart, &oldLine);
posToVisibleLineNum(textD, oldLineEnd, &oldLine2);
if(oldLine == -
1 && oldLine2 >=
0) {
oldLine =
0;
}
if(oldLine2 == -
1 && oldLine >=
0) {
oldLine2 = textD->nVisibleLines-
1;
}
for(
int i=oldLine;i<=oldLine2;i++) {
redisplayLine(textD, i,
0,
INT_MAX,
0,
INT_MAX);
}
for(
int i=newLine;i<=newLine2;i++) {
redisplayLine(textD, i,
0,
INT_MAX,
0,
INT_MAX);
}
}
}
void TextDChangeCursors(textDisp *textD,
int startPos,
int diff) {
size_t newMCursorSize = textD->mcursorSize;
for(
int i=textD->mcursorSize-
1;i>=
0;i--) {
if(textD->multicursor[i].cursorPos < startPos) {
break;
}
textD->multicursor[i].cursorPos += diff;
textD->multicursor[i].cursorPreferredCol = -
1;
if(textD->multicursor[i].cursorPos > textD->buffer->length) {
newMCursorSize = i;
}
}
textD->mcursorSize = newMCursorSize >
0 ? newMCursorSize :
1;
textD->mcursorSizeReal = textD->mcursorSize;
if(textD->mcursorSize ==
1) {
textD->mcursorOn = False;
}
}
int TextDAddCursor(textDisp *textD,
int newMultiCursorPos) {
int mcInsertPos =
0;
for(
int i=
0;i<textD->mcursorSize;i++) {
if(textD->multicursor[i].cursorPos == newMultiCursorPos) {
return i;
}
else if(textD->multicursor[i].cursorPos > newMultiCursorPos) {
break;
}
mcInsertPos = i+
1;
}
if(textD->mcursorSize ==
MCURSOR_MAX) {
return -
1;
}
if(textD->mcursorSize == textD->mcursorAlloc) {
textD->mcursorAlloc *=
2;
textD->multicursor = NEditRealloc(textD->multicursor, textD->mcursorAlloc *
sizeof(textCursor));
}
textD->mcursorOn =
TRUE;
textD->mcursorSize++;
textD->mcursorSizeReal = textD->mcursorSize;
if(mcInsertPos+
1 < textD->mcursorSize) {
memmove(textD->multicursor+mcInsertPos+
1, textD->multicursor+mcInsertPos, (textD->mcursorSize-mcInsertPos-
1)*
sizeof(textCursor));
}
textCursor newCursor = TextDPos2Cursor(textD, newMultiCursorPos);
textD->multicursor[mcInsertPos] = newCursor;
textD->newcursor = &textD->multicursor[mcInsertPos];
textD->cursor = textD->multicursor;
textD->cursorOn = False;
if(textD->highlightCursorLine) {
int newCursorLine;
posToVisibleLineNum(textD, newMultiCursorPos, &newCursorLine);
redisplayLine(textD, newCursorLine,
0,
INT_MAX,
0,
INT_MAX);
}
TextDUnblankCursor(textD);
return -
1;
}
void TextDRemoveCursor(textDisp *textD,
int cursorIndex) {
if(textD->mcursorSize ==
1) {
return;
}
else if(textD->mcursorSize ==
2) {
textD->mcursorOn =
FALSE;
}
int cursorLine;
posToVisibleLineNum(textD, textD->multicursor[cursorIndex].cursorPos, &cursorLine);
if(cursorIndex+
1 != textD->mcursorSize) {
memmove(textD->multicursor + cursorIndex, textD->multicursor + cursorIndex +
1, (textD->mcursorSize - cursorIndex -
1)*
sizeof(textCursor));
}
textD->mcursorSize--;
textD->mcursorSizeReal = textD->mcursorSize;
if(textD->highlightCursorLine) {
redisplayLine(textD, cursorLine,
0,
INT_MAX,
0,
INT_MAX);
}
textD->newcursor = textD->cursor;
}
void TextDSetCursors(textDisp *textD,
size_t *cursors,
size_t ncursors) {
TextDBlankCursor(textD);
textD->mcursorSize =
0;
for(
int i=
0;i<ncursors;i++) {
TextDAddCursor(textD, (
int)cursors[i]);
}
}
int TextDClearMultiCursor(textDisp *textD) {
if(textD->mcursorSize >
1) {
TextDBlankCursor(textD);
textD->mcursorOn =
FALSE;
textD->mcursorSize =
1;
textD->mcursorSizeReal =
1;
if(textD->mcursorAlloc >
MCURSOR_ALLOC_RESET) {
textD->mcursorAlloc =
MCURSOR_ALLOC;
textD->multicursor = NEditRealloc(textD->multicursor,
MCURSOR_ALLOC *
sizeof(textCursor));
}
textD->cursor = textD->multicursor;
textD->newcursor = textD->multicursor;
return 1;
}
return 0;
}
void TextDCheckCursorDuplicates(textDisp *textD) {
size_t mcursorSize = textD->mcursorSize;
for(
size_t i=
1;i<textD->mcursorSize;i++) {
if(textD->multicursor[i].cursorPos == textD->multicursor[i-
1].cursorPos) {
TextDRemoveCursor(textD, i);
mcursorSize--;
i--;
}
}
textD->cursor = textD->multicursor;
textD->newcursor = textD->multicursor;
if(textD->highlightCursorLine) {
size_t lastPos = textD->multicursor[textD->mcursorSize-
1].cursorPos;
int cursorLine;
posToVisibleLineNum(textD, lastPos, &cursorLine);
if(cursorLine +
1 < textD->nVisibleLines) {
redisplayLine(textD, cursorLine +
1,
0,
INT_MAX,
0,
INT_MAX);
}
}
}
static void textDBlankCursorPos(textDisp *textD) {
blankSingleCursorProtrusions(textD);
textD->cursorOn = False;
int left, right;
TextDCursorLR(textD, &left, &right);
textDRedisplayRange(textD, left, right);
}
void TextDBlankCursor(textDisp *textD)
{
if (!textD->cursorOn)
return;
if(textD->mcursorSize ==
1) {
textDBlankCursorPos(textD);
}
else {
textCursor *origCursor = textD->cursor;
for(
int i=
0;i<textD->mcursorSize;i++) {
textD->cursor = textD->multicursor + i;
textDBlankCursorPos(textD);
}
textD->cursor = origCursor;
}
}
void textDUnblankCursorPos(textDisp *textD) {
int left, right;
TextDCursorLR(textD, &left, &right);
textDRedisplayRange(textD, left, right);
}
void TextDUnblankCursor(textDisp *textD)
{
if (!textD->cursorOn) {
textD->cursorOn = True;
if(textD->mcursorSize ==
1) {
textDUnblankCursorPos(textD);
}
else {
textCursor *origCursor = textD->cursor;
for(
int i=
0;i<textD->mcursorSize;i++) {
textD->cursor = textD->multicursor + i;
textDUnblankCursorPos(textD);
}
textD->cursor = origCursor;
}
}
}
void TextDSetCursorStyle(textDisp *textD,
int style)
{
textD->cursorStyle = style;
blankCursorProtrusions(textD);
if (textD->cursorOn) {
int left, right;
if(textD->mcursorSize ==
1) {
TextDCursorLR(textD, &left, &right);
textDRedisplayRange(textD, left, right);
}
else {
textCursor *origCursor = textD->cursor;
for(
int i=
0;i<textD->mcursorSize;i++) {
textD->cursor = textD->multicursor + i;
TextDCursorLR(textD, &left, &right);
textDRedisplayRange(textD, left, right);
}
textD->cursor = origCursor;
}
}
}
Boolean TextDPosHasCursor(textDisp *textD,
int pos,
int *index) {
*index = -
1;
if(textD->mcursorSizeReal ==
1) {
return pos == textD->cursor->cursorPos;
}
else {
for(
int i=
0;i<textD->mcursorSizeReal;i++) {
int cursor = textD->multicursor[i].cursorPos;
if(pos == cursor) {
*index = i;
return True;
}
}
return False;
}
}
Boolean TextDRangeHasCursor(textDisp *textD,
int start,
int end) {
if(textD->mcursorSizeReal ==
1) {
int cursor = textD->cursor->cursorPos;
return cursor >= start && cursor <= end;
}
else {
for(
int i=
0;i<textD->mcursorSizeReal;i++) {
int cursor = textD->multicursor[i].cursorPos;
if(cursor >= start && cursor <= end) {
return True;
}
}
return False;
}
}
void TextDSetWrapMode(textDisp *textD,
int wrap,
int wrapMargin)
{
textD->wrapMargin = wrapMargin;
textD->continuousWrap = wrap;
textD->cacheNoWrapping = False;
Boolean retWrap;
textD->nBufferLines = TextDCountLinesW(textD,
0, textD->buffer->length,
True, &retWrap);
if(!retWrap) {
textD->cacheNoWrappingWidth = textD->width;
textD->cacheNoWrapping = True;
}
textD->firstChar = TextDStartOfLine(textD, textD->firstChar);
textD->topLineNum = TextDCountLines(textD,
0, textD->firstChar, True) +
1;
resetAbsLineNum(textD);
calcLineStarts(textD,
0, textD->nVisibleLines);
calcLastChar(textD);
updateVScrollBarRange(textD);
updateHScrollBarRange(textD);
hideOrShowHScrollBar(textD);
TextDRedisplayRect(textD,
0, textD->top, textD->width + textD->left,
textD->height);
}
int TextDGetInsertPosition(textDisp *textD)
{
return textD->cursor->cursorPos;
}
void TextDInsert(textDisp *textD,
char *text)
{
int pos = textD->cursor->cursorPos;
textD->cursorToHint = pos + strlen(text);
BufInsert(textD->buffer, pos, text);
textD->cursorToHint =
NO_HINT;
}
void TextDOverstrike(textDisp *textD,
char *text)
{
int startPos = textD->cursor->cursorPos;
textBuffer *buf = textD->buffer;
int lineStart = BufStartOfLine(buf, startPos);
int textLen = strlen(text);
int i, p, endPos, indent, startIndent, endIndent, inc;
char *c, ch, *paddedText =
NULL;
startIndent = BufCountDispChars(textD->buffer, lineStart, startPos);
indent = startIndent;
for (c=text; *c!=
'\0'; c+=inc) {
inc = Utf8CharLen((
unsigned char*)c);
if(inc >=
1) {
indent++;
}
else {
indent += BufCharWidth(*c, indent, buf->tabDist, buf->nullSubsChar);
}
}
endIndent = indent;
indent=startIndent;
for (p=startPos; ; p+=inc) {
if (p == buf->length)
break;
ch = BufGetCharacter(buf, p);
inc = Utf8CharLen((
unsigned char*)&ch);
if (ch ==
'\n')
break;
indent += BufCharWidth(ch, indent, buf->tabDist, buf->nullSubsChar);
if (indent == endIndent) {
p += inc;
break;
}
else if (indent > endIndent) {
if (ch !=
'\t') {
p += inc;
paddedText = (
char*)NEditMalloc(textLen +
MAX_EXP_CHAR_LEN +
1);
strcpy(paddedText, text);
for (i=
0; i<indent-endIndent; i++)
paddedText[textLen+i] =
' ';
paddedText[textLen+i] =
'\0';
}
break;
}
}
endPos = p;
textD->cursorToHint = startPos + textLen;
BufReplace(buf, startPos, endPos, paddedText ==
NULL ? text : paddedText);
textD->cursorToHint =
NO_HINT;
NEditFree(paddedText);
}
XftColor PixelToColor(Widget w, Pixel p)
{
XColor xcolor;
memset(&xcolor,
0,
sizeof(XColor));
xcolor.pixel = p;
XQueryColor(XtDisplay(w), w->core.colormap, &xcolor);
XftColor color;
color.pixel = p;
color.color.red = xcolor.red;
color.color.green = xcolor.green;
color.color.blue = xcolor.blue;
color.color.alpha = 0xFFFF;
return color;
}
int TextDXYToPosition(textDisp *textD,
int x,
int y)
{
return xyToPos(textD, x, y,
CURSOR_POS);
}
int TextDXYToCharPos(textDisp *textD,
int x,
int y)
{
return xyToPos(textD, x, y,
CHARACTER_POS);
}
void TextDXYToUnconstrainedPosition(textDisp *textD,
int x,
int y,
int *row,
int *column)
{
xyToUnconstrainedPos(textD, x, y, row, column,
CURSOR_POS);
}
int TextDLineAndColToPos(textDisp *textD,
int lineNum,
int column)
{
int i, lineEnd, charIndex, outIndex, isMB;
int lineStart=
0, charLen=
0;
char expandedChar[
MAX_EXP_CHAR_LEN];
if (lineNum <
1)
lineNum =
1;
lineEnd = -
1;
for (i=
1; i<=lineNum && lineEnd<textD->buffer->length; i++) {
lineStart = lineEnd +
1;
lineEnd = BufEndOfLine(textD->buffer, lineStart);
}
if ( lineNum >= i ) {
return lineEnd;
}
charIndex=
0;
if (column >
0) {
char *lineStrAlloc;
const char *lineStr = BufGetRange2(textD->buffer, lineStart, lineEnd, &lineStrAlloc);
outIndex =
0;
for(i=lineStart; i<lineEnd; i++, charIndex++) {
charLen = BufExpandCharacter(lineStr+charIndex, lineEnd-charIndex,
outIndex, expandedChar, textD->buffer->tabDist,
textD->buffer->nullSubsChar, &isMB);
if ( outIndex+charLen >= column )
break;
outIndex+=charLen;
}
NEditFree(lineStrAlloc);
if (column >= outIndex + ( charLen /
2 ))
charIndex++;
if ((i>=lineEnd)&&(charIndex>
0)) charIndex--;
}
return lineStart + charIndex;
}
int TextDPositionToXY(textDisp *textD,
int pos,
int *x,
int *y)
{
int charIndex, lineStartPos, fontHeight, lineLen;
int visLineNum, charLen, outIndex, xStep, charStyle, inc;
FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
FcChar32 uc;
NFont *font;
if (pos < textD->firstChar ||
(pos > textD->lastChar && !emptyLinesVisible(textD)))
return False;
if (!posToVisibleLineNum(textD, pos, &visLineNum))
return False;
fontHeight = textD->ascent + textD->descent;
*y = textD->top + visLineNum*fontHeight + fontHeight/
2;
lineStartPos = textD->lineStarts[visLineNum];
if (lineStartPos == -
1) {
*x = textD->left - textD->horizOffset;
return True;
}
lineLen = visLineLength(textD, visLineNum);
char *lineStrAlloc;
const char *lineStr = BufGetRange2(textD->buffer, lineStartPos, lineStartPos + lineLen, &lineStrAlloc);
xStep = textD->left - textD->horizOffset;
outIndex =
0;
for(charIndex=
0; charIndex<pos-lineStartPos; charIndex+=inc) {
inc = getCharWidth(textD, lineStr+charIndex, &uc, lineLen - charIndex);
if(inc >
1) {
charLen =
1;
expandedChar[
0] = uc;
}
else {
charLen = BufExpandCharacter4(lineStr[charIndex],
outIndex,
expandedChar,
textD->buffer->tabDist, textD->buffer->nullSubsChar);
}
charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex,
outIndex, lineStr[charIndex]);
font = styleFontList(textD, charStyle);
xStep += charWidth4(textD, expandedChar, charLen, font);
outIndex += charLen;
}
*x = xStep;
NEditFree(lineStrAlloc);
return True;
}
int TextDPosToLineAndCol(textDisp *textD,
int pos,
int *lineNum,
int *column)
{
textBuffer *buf = textD->buffer;
if (textD->continuousWrap) {
if (!maintainingAbsTopLineNum(textD) || pos < textD->firstChar ||
pos > textD->lastChar)
return False;
*lineNum = textD->absTopLineNum + BufCountLines(buf,
textD->firstChar, pos);
*column = BufCountDispChars(buf, BufStartOfLine(buf, pos), pos);
return True;
}
if (!posToVisibleLineNum(textD, pos, lineNum))
return False;
*column = BufCountDispChars(buf, textD->lineStarts[*lineNum], pos);
*lineNum += textD->topLineNum;
return True;
}
int TextDInSelection(textDisp *textD,
int x,
int y)
{
int row, column, pos = xyToPos(textD, x, y,
CHARACTER_POS);
textBuffer *buf = textD->buffer;
xyToUnconstrainedPos(textD, x, y, &row, &column,
CHARACTER_POS);
if (rangeTouchesRectSel(&buf->primary, textD->firstChar, textD->lastChar))
column = TextDOffsetWrappedColumn(textD, row, column);
return inSelection(&buf->primary, pos, BufStartOfLine(buf, pos), column);
}
int TextDOffsetWrappedColumn(textDisp *textD,
int row,
int column)
{
int lineStart, dispLineStart;
if (!textD->continuousWrap || row <
0 || row > textD->nVisibleLines)
return column;
dispLineStart = textD->lineStarts[row];
if (dispLineStart == -
1)
return column;
lineStart = BufStartOfLine(textD->buffer, dispLineStart);
return column + BufCountDispChars(textD->buffer, lineStart, dispLineStart);
}
int TextDOffsetWrappedRow(textDisp *textD,
int row)
{
if (!textD->continuousWrap || row <
0 || row > textD->nVisibleLines)
return row;
return BufCountLines(textD->buffer, textD->firstChar,
textD->lineStarts[row]);
}
void TextDMakeInsertPosVisible(textDisp *textD)
{
int hOffset, topLine, x, y;
int cursorPos = textD->cursor->cursorPos;
int linesFromTop =
0, do_padding =
1;
int cursorVPadding = (
int)
TEXT_OF_TEXTD(textD).cursorVPadding;
hOffset = textD->horizOffset;
topLine = textD->topLineNum;
do_padding = ((
TEXT_OF_TEXTD(textD).dragState ==
NOT_CLICKED) &&
(cursorVPadding >
0));
if (cursorPos < textD->firstChar) {
topLine -= TextDCountLines(textD, cursorPos, textD->firstChar, False);
}
else if (cursorPos > textD->lastChar && !emptyLinesVisible(textD)) {
topLine += TextDCountLines(textD, textD->lastChar -
(wrapUsesCharacter(textD, textD->lastChar) ?
0 :
1),
cursorPos, False);
linesFromTop = textD->nVisibleLines-
1;
}
else if (cursorPos == textD->lastChar && !emptyLinesVisible(textD) &&
!wrapUsesCharacter(textD, textD->lastChar)) {
topLine++;
linesFromTop = textD->nVisibleLines-
1;
}
else {
if (do_padding)
linesFromTop = TextDCountLines(textD, textD->firstChar,
cursorPos, True);
}
if (topLine <
1) {
fprintf(stderr,
"xnedit: internal consistency check tl1 failed\n");
topLine =
1;
}
if (do_padding) {
if (textD->nVisibleLines <=
2*(
int)cursorVPadding) {
topLine += (linesFromTop - textD->nVisibleLines/
2);
topLine = max(topLine,
1);
}
else if (linesFromTop < (
int)cursorVPadding) {
topLine -= (cursorVPadding - linesFromTop);
topLine = max(topLine,
1);
}
else if (linesFromTop > textD->nVisibleLines-(
int)cursorVPadding-
1) {
topLine += (linesFromTop - (textD->nVisibleLines-cursorVPadding-
1));
}
}
if (!TextDPositionToXY(textD, cursorPos, &x, &y)) {
setScroll(textD, topLine, hOffset, True, True);
if (!TextDPositionToXY(textD, cursorPos, &x, &y))
return;
}
if (x > textD->left + textD->width)
hOffset += x - (textD->left + textD->width);
else if (x < textD->left)
hOffset += x - textD->left;
setScroll(textD, topLine, hOffset, True, True);
}
int TextDPreferredColumn(textDisp *textD,
int *visLineNum,
int *lineStartPos)
{
int column;
if (posToVisibleLineNum(textD, textD->cursor->cursorPos, visLineNum)) {
*lineStartPos = textD->lineStarts[*visLineNum];
}
else {
*lineStartPos = TextDStartOfLine(textD, textD->cursor->cursorPos);
*visLineNum = -
1;
}
column = (textD->cursor->cursorPreferredCol >=
0)
? textD->cursor->cursorPreferredCol
: BufCountDispChars(textD->buffer, *lineStartPos, textD->cursor->cursorPos);
return(column);
}
int TextDPosOfPreferredCol(textDisp *textD,
int column,
int lineStartPos)
{
int newPos;
newPos = BufCountForwardDispChars(textD->buffer, lineStartPos, column);
if (textD->continuousWrap) {
newPos = min(newPos, TextDEndOfLine(textD, lineStartPos, True));
}
return(newPos);
}
int TextDMoveRight(textDisp *textD)
{
if (textD->cursor->cursorPos >= textD->buffer->length)
return False;
TextDSetInsertPosition(
textD,
BufRightPos(textD->buffer, textD->cursor->cursorPos));
return True;
}
int TextDMoveLeft(textDisp *textD)
{
if (textD->cursor->cursorPos <=
0)
return False;
TextDSetInsertPosition(textD, BufLeftPos(textD->buffer, textD->cursor->cursorPos));
return True;
}
int TextDMoveUp(textDisp *textD,
int absolute)
{
int lineStartPos, column, prevLineStartPos, newPos, visLineNum;
if (absolute) {
lineStartPos = BufStartOfLine(textD->buffer, textD->cursor->cursorPos);
visLineNum = -
1;
}
else if (posToVisibleLineNum(textD, textD->cursor->cursorPos, &visLineNum))
lineStartPos = textD->lineStarts[visLineNum];
else {
lineStartPos = TextDStartOfLine(textD, textD->cursor->cursorPos);
visLineNum = -
1;
}
if (lineStartPos ==
0)
return False;
column = textD->cursor->cursorPreferredCol >=
0
? textD->cursor->cursorPreferredCol
: BufCountDispChars(textD->buffer, lineStartPos, textD->cursor->cursorPos);
if (absolute) {
prevLineStartPos = BufCountBackwardNLines(textD->buffer, lineStartPos,
1);
}
else if (visLineNum != -
1 && visLineNum !=
0) {
prevLineStartPos = textD->lineStarts[visLineNum-
1];
}
else {
prevLineStartPos = TextDCountBackwardNLines(textD, lineStartPos,
1);
}
newPos = BufCountForwardDispChars(textD->buffer, prevLineStartPos, column);
if (textD->continuousWrap && !absolute)
newPos = min(newPos, TextDEndOfLine(textD, prevLineStartPos, True));
TextDSetInsertPosition(textD, newPos);
textD->cursor->cursorPreferredCol = column;
return True;
}
int TextDMoveDown(textDisp *textD,
int absolute)
{
int lineStartPos, column, nextLineStartPos, newPos, visLineNum;
if (textD->cursor->cursorPos == textD->buffer->length) {
return False;
}
if (absolute) {
lineStartPos = BufStartOfLine(textD->buffer, textD->cursor->cursorPos);
visLineNum = -
1;
}
else if (posToVisibleLineNum(textD, textD->cursor->cursorPos, &visLineNum)) {
lineStartPos = textD->lineStarts[visLineNum];
}
else {
lineStartPos = TextDStartOfLine(textD, textD->cursor->cursorPos);
visLineNum = -
1;
}
column = textD->cursor->cursorPreferredCol >=
0
? textD->cursor->cursorPreferredCol
: BufCountDispChars(textD->buffer, lineStartPos, textD->cursor->cursorPos);
if (absolute)
nextLineStartPos = BufCountForwardNLines(textD->buffer, lineStartPos,
1);
else
nextLineStartPos = TextDCountForwardNLines(textD, lineStartPos,
1, True);
newPos = BufCountForwardDispChars(textD->buffer, nextLineStartPos, column);
if (textD->continuousWrap && !absolute) {
newPos = min(newPos, TextDEndOfLine(textD, nextLineStartPos, True));
}
TextDSetInsertPosition(textD, newPos);
textD->cursor->cursorPreferredCol = column;
return True;
}
textCursor TextDPos2Cursor(textDisp *textD,
int pos) {
textBuffer *buf = textD->buffer;
textCursor c;
c.cursorPos = pos;
c.cursorPosCache = pos;
c.cursorPosCacheLeft = BufLeftPos(buf, pos);
c.cursorPosCacheRight = BufRightPos(buf, pos);
c.cursorPreferredCol = -
1;
c.x = -
100;
c.y = -
100;
if(textD->ansiColors) {
while(BufGetCharacter(buf, c.cursorPosCacheLeft) ==
'\e') {
c.cursorPosCacheLeft = BufLeftPos(buf, c.cursorPosCacheLeft);
}
while(BufGetCharacter(buf, pos) ==
'\e') {
c.cursorPosCacheRight += BufCharLen(buf, c.cursorPosCacheRight);
pos = c.cursorPosCacheRight;
}
c.cursorPosCacheRight += BufCharLen(buf, textD->cursor->cursorPosCacheRight);
}
return c;
}
void TextDCursorLR(textDisp *textD,
int *left,
int *right)
{
if(textD->cursor->cursorPos != textD->cursor->cursorPosCache) {
textCursor c = TextDPos2Cursor(textD, textD->cursor->cursorPos);
textD->cursor->cursorPosCache = c.cursorPosCache;
textD->cursor->cursorPosCacheLeft = c.cursorPosCacheLeft;
textD->cursor->cursorPosCacheRight = c.cursorPosCacheRight;
}
*left = textD->cursor->cursorPosCacheLeft;
*right = textD->cursor->cursorPosCacheRight;
}
void TextDSetAnsiColors(textDisp *textD, Boolean ansiColors)
{
textD->ansiColors = ansiColors;
if(ansiColors) {
BufEnableAnsiEsc(textD->buffer);
textD->cursor->cursorPosCache = -
1;
}
else {
BufDisableAnsiEsc(textD->buffer);
}
}
int TextDCountLines(textDisp *textD,
int startPos,
int endPos,
int startPosIsLineStart)
{
Boolean retWrap;
int retLines = TextDCountLinesW(textD, startPos, endPos, startPosIsLineStart, &retWrap);
if(retWrap) {
textD->cacheNoWrapping = False;
}
return retLines;
}
int TextDCountLinesW(textDisp *textD,
int startPos,
int endPos,
int startPosIsLineStart, Boolean *retWrapped)
{
int retLines, retPos, retLineStart, retLineEnd;
if (!textD->continuousWrap) {
if(retWrapped) {
*retWrapped =
0;
}
return BufCountLines(textD->buffer, startPos, endPos);
}
wrappedLineCounter(textD, textD->buffer, startPos, endPos,
INT_MAX,
startPosIsLineStart,
0, &retPos, &retLines, &retLineStart,
&retLineEnd, retWrapped);
return retLines;
}
int TextDCountForwardNLines(
const textDisp* textD,
int startPos,
unsigned nLines, Boolean startPosIsLineStart)
{
int retLines, retPos, retLineStart, retLineEnd;
if (!textD->continuousWrap)
return BufCountForwardNLines(textD->buffer, startPos, nLines);
if (nLines ==
0)
return startPos;
wrappedLineCounter(textD, textD->buffer, startPos, textD->buffer->length,
nLines, startPosIsLineStart,
0, &retPos, &retLines, &retLineStart,
&retLineEnd,
NULL);
return retPos;
}
int TextDEndOfLine(
const textDisp* textD,
int pos,
Boolean startPosIsLineStart)
{
int retLines, retPos, retLineStart, retLineEnd;
if (!textD->continuousWrap)
return BufEndOfLine(textD->buffer, pos);
if (pos == textD->buffer->length)
return pos;
wrappedLineCounter(textD, textD->buffer, pos, textD->buffer->length,
1,
startPosIsLineStart,
0, &retPos, &retLines, &retLineStart,
&retLineEnd,
NULL);
return retLineEnd;
}
int TextDStartOfLine(
const textDisp* textD,
int pos)
{
int retLines, retPos, retLineStart, retLineEnd;
if (!textD->continuousWrap)
return BufStartOfLine(textD->buffer, pos);
wrappedLineCounter(textD, textD->buffer, BufStartOfLine(textD->buffer, pos),
pos,
INT_MAX, True,
0, &retPos, &retLines, &retLineStart,
&retLineEnd,
NULL);
return retLineStart;
}
int TextDCountBackwardNLines(textDisp *textD,
int startPos,
int nLines)
{
textBuffer *buf = textD->buffer;
int pos, lineStart, retLines, retPos, retLineStart, retLineEnd;
if (!textD->continuousWrap)
return BufCountBackwardNLines(textD->buffer, startPos, nLines);
pos = startPos;
while (True) {
lineStart = BufStartOfLine(buf, pos);
wrappedLineCounter(textD, textD->buffer, lineStart, pos,
INT_MAX,
True,
0, &retPos, &retLines, &retLineStart, &retLineEnd,
NULL);
if (retLines > nLines)
return TextDCountForwardNLines(textD, lineStart, retLines-nLines,
True);
nLines -= retLines;
pos = lineStart -
1;
if (pos <
0)
return 0;
nLines -=
1;
}
}
static void bufPreDeleteCB(
int pos,
int nDeleted,
void *cbArg)
{
textDisp *textD = (textDisp *)cbArg;
if (textD->continuousWrap &&
(textD->fixedFontWidth == -
1 || textD->modifyingTabDist))
measureDeletedLines(textD, pos, nDeleted);
else
textD->suppressResync =
0;
}
static void bufModifiedCB(
int pos,
int nInserted,
int nDeleted,
int nRestyled,
const char *deletedText,
void *cbArg)
{
int linesInserted, linesDeleted, startDispPos, endDispPos;
textDisp *textD = (textDisp *)cbArg;
textBuffer *buf = textD->buffer;
int oldFirstChar = textD->firstChar;
int scrolled, origCursorPos = textD->cursor->cursorPos;
int wrapModStart, wrapModEnd;
int redrawLN = False;
if (nInserted !=
0 || nDeleted !=
0)
textD->cursor->cursorPreferredCol = -
1;
if (textD->continuousWrap) {
redrawLN = findWrapRange(textD, deletedText, pos, nInserted, nDeleted,
&wrapModStart, &wrapModEnd, &linesInserted, &linesDeleted);
if(!redrawLN && nDeleted >
0) {
for(
int i=
0;i<nDeleted;i++) {
if(deletedText[i] ==
'\n') {
redrawLN =
1;
break;
}
}
}
}
else {
linesInserted = nInserted ==
0 ?
0 :
BufCountLines(buf, pos, pos + nInserted);
linesDeleted = nDeleted ==
0 ?
0 : countLines(deletedText);
}
if (nInserted !=
0 || nDeleted !=
0) {
if (textD->continuousWrap) {
updateLineStarts(textD, wrapModStart, wrapModEnd-wrapModStart,
nDeleted + pos-wrapModStart + (wrapModEnd-(pos+nInserted)),
linesInserted, linesDeleted, &scrolled);
}
else {
updateLineStarts(textD, pos, nInserted, nDeleted, linesInserted,
linesDeleted, &scrolled);
}
}
else
scrolled = False;
if (maintainingAbsTopLineNum(textD) && (nInserted !=
0 || nDeleted !=
0)) {
if (pos + nDeleted < oldFirstChar)
textD->absTopLineNum += BufCountLines(buf, pos, pos + nInserted) -
countLines(deletedText);
else if (pos < oldFirstChar)
resetAbsLineNum(textD);
}
textD->nBufferLines += linesInserted - linesDeleted;
updateVScrollBarRange(textD);
scrolled |= updateHScrollBarRange(textD);
if (textD->cursorToHint !=
NO_HINT) {
textD->cursor->cursorPos = textD->cursorToHint;
textD->cursorToHint =
NO_HINT;
}
else if (textD->cursor->cursorPos > pos) {
if(textD->mcursorSize >
1) {
TextDChangeCursors(textD, pos, nInserted - nDeleted);
}
else {
if (textD->cursor->cursorPos < pos + nDeleted)
textD->cursor->cursorPos = pos;
else
textD->cursor->cursorPos += nInserted - nDeleted;
}
}
Bool isLastCursor = textD->cursor == textD->multicursor + textD->mcursorSize -
1;
if(scrolled && isLastCursor) {
blankCursorProtrusions(textD);
TextDRedisplayRect(textD,
0, textD->top, textD->width + textD->left,
textD->height);
if (textD->styleBuffer) {
textD->styleBuffer->primary.selected = False;
textD->styleBuffer->primary.zeroWidth = False;
}
return;
}
startDispPos = textD->continuousWrap ? wrapModStart : pos;
int cpos = origCursorPos;
if (textD->highlightCursorLine) {
cpos = BufStartOfLine(buf, origCursorPos);
}
if (origCursorPos == startDispPos && textD->cursor->cursorPos != startDispPos) {
startDispPos = min(startDispPos, BufLeftPos(buf, cpos));
}
if (linesInserted == linesDeleted) {
if (nInserted ==
0 && nDeleted ==
0)
endDispPos = pos + nRestyled;
else {
endDispPos = textD->continuousWrap ? wrapModEnd :
BufEndOfLine(buf, pos + nInserted) +
1;
if (origCursorPos >= startDispPos &&
(origCursorPos <= endDispPos || endDispPos == buf->length))
blankCursorProtrusions(textD);
}
if (linesInserted >
2 || redrawLN) redrawLineNumbers(textD, textD->top, textD->height, True);
}
else {
endDispPos = textD->lastChar +
1;
if (origCursorPos >= pos) {
blankCursorProtrusions(textD);
}
redrawLineNumbers(textD, textD->top, textD->height, True);
}
if (textD->styleBuffer)
extendRangeForStyleMods(textD, &startDispPos, &endDispPos);
textDRedisplayRange(textD, startDispPos, endDispPos);
}
void TextDMaintainAbsLineNum(textDisp *textD,
int state)
{
textD->needAbsTopLineNum = state;
resetAbsLineNum(textD);
}
static int getAbsTopLineNum(textDisp *textD)
{
if (!textD->continuousWrap)
return textD->topLineNum;
if (maintainingAbsTopLineNum(textD))
return textD->absTopLineNum;
return 0;
}
static void offsetAbsLineNum(textDisp *textD,
int oldFirstChar)
{
if (maintainingAbsTopLineNum(textD)) {
if (textD->firstChar < oldFirstChar)
textD->absTopLineNum -= BufCountLines(textD->buffer,
textD->firstChar, oldFirstChar);
else
textD->absTopLineNum += BufCountLines(textD->buffer,
oldFirstChar, textD->firstChar);
}
}
static int maintainingAbsTopLineNum(textDisp *textD)
{
return textD->continuousWrap &&
(textD->lineNumWidth !=
0 || textD->needAbsTopLineNum);
}
static void resetAbsLineNum(textDisp *textD)
{
textD->absTopLineNum =
1;
offsetAbsLineNum(textD,
0);
}
static int posToVisibleLineNum(textDisp *textD,
int pos,
int *lineNum)
{
int i;
if (pos < textD->firstChar)
return False;
if (pos > textD->lastChar) {
if (emptyLinesVisible(textD)) {
if (textD->lastChar < textD->buffer->length) {
if (!posToVisibleLineNum(textD, textD->lastChar, lineNum)) {
fprintf(stderr,
"xnedit: Consistency check ptvl failed\n");
return False;
}
return ++(*lineNum) <= textD->nVisibleLines-
1;
}
else {
posToVisibleLineNum(textD, max(textD->lastChar-
1,
0), lineNum);
return True;
}
}
return False;
}
for (i=textD->nVisibleLines-
1; i>=
0; i--) {
if (textD->lineStarts[i] != -
1 && pos >= textD->lineStarts[i]) {
*lineNum = i;
return True;
}
}
return False;
}
static int getCharWidth(textDisp *textD,
const char *src_orig, FcChar32 *dst,
int len)
{
if(textD->ansiColors && *src_orig ==
'\e') {
if(len <
3)
return 1;
if(src_orig[
1] !=
'[')
return 1;
int i;
for(i=
2;i<len;i++) {
char c = src_orig[i];
if(c ==
'm') {
i++;
break;
}
if(c <
'0' || (c >
'9' && c !=
';'))
break;
}
*dst =
0;
return i;
}
else {
return Utf8ToUcs4(src_orig, dst, len);
}
}
static FcChar32 getCharacter32(
const textDisp *textD,
const textBuffer* buf,
int pos,
int *charlen)
{
if(textD->ansiColors) {
if(BufGetCharacter(buf, pos) ==
'\e') {
if(BufGetCharacter(buf, pos+
1) ==
'[') {
int start = pos;
pos +=
2;
char c;
while((c = BufGetCharacter(buf, pos)) !=
'\0') {
if(c ==
'm') {
pos++;
break;
}
if(c <
'0' || (c >
'9' && c !=
';'))
break;
pos++;
}
*charlen = pos - start;
return 0;
}
}
}
return BufGetCharacter32(buf, pos, charlen);
}
typedef struct _textCursorX {
int cursorX;
int index;
} textCursorX;
static void redisplayLine(textDisp *textD,
int visLineNum,
int leftClip,
int rightClip,
int leftCharIndex,
int rightCharIndex)
{
textBuffer *buf = textD->buffer;
int x, y, startX, charIndex, lineStartPos, lineLen, fontHeight, inc;
int stdCharWidth, charWidth, startIndex, charStyle, style;
int charLen, outStartIndex, outIndex, hasCursor = False;
int dispIndexOffset, y_orig;
int startOfLine =
INT_MAX;
int endOfLine =
0;
int cursorLine = False;
FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
FcChar32 outStr[
MAX_DISP_LINE_LEN];
FcChar32 *outPtr;
const char *lineStr;
char *lineStrFree;
char baseChar;
FcChar32 uc =
0;
NFont *styleFL = textD->font;
NFont *charFL;
XftFont *styleFont;
XftFont *charFont;
int rbTabDist =
TEXT_OF_TEXTD(textD).emulateTabs >
0 ?
TEXT_OF_TEXTD(textD).emulateTabs : buf->tabDist;
Boolean indentRainbow = textD->indentRainbow;
textCursorX singleCursor = { textD->cursor->cursorPos,
0 };
textCursorX *cursorX = textD->mcursorSizeReal ==
1 ? &singleCursor : NEditCalloc(textD->mcursorSizeReal,
sizeof(textCursorX));
int cursorNum =
0;
int cursorIndex;
if (visLineNum <
0 || visLineNum >= textD->nVisibleLines)
return;
leftClip = max(textD->left, leftClip);
rightClip = min(rightClip, textD->left + textD->width);
if (leftClip > rightClip) {
return;
}
fontHeight = textD->ascent + textD->descent;
y = textD->top + visLineNum * fontHeight;
lineStartPos = textD->lineStarts[visLineNum];
if (lineStartPos == -
1) {
lineLen =
0;
lineStr =
NULL;
lineStrFree =
NULL;
}
else {
lineLen = visLineLength(textD, visLineNum);
lineStr = BufGetRange2(buf, lineStartPos, lineStartPos + lineLen, &lineStrFree);
endOfLine = BufEndOfLine(buf, lineStartPos);
if(textD->highlightCursorLine) {
startOfLine = BufStartOfLine(buf, lineStartPos);
}
}
int ansiS = -
1;
int ansiCharS = -
1;
ansiStyle newAnsiStyle = {-
1, -
1, -
1, -
1};
ansiStyle ansi = {-
1, -
1, -
1, -
1};
if(textD->ansiColors && lineStartPos >=
0) {
findActiveAnsiStyle(textD, lineStartPos, &ansi);
}
stdCharWidth = textD->font->maxWidth;
if (stdCharWidth <=
0) {
fprintf(stderr,
"xnedit: Internal Error, bad font measurement\n");
NEditFree(lineStrFree);
return;
}
if (textD->continuousWrap && (rangeTouchesRectSel(&buf->primary,
lineStartPos, lineStartPos + lineLen) || rangeTouchesRectSel(
&buf->secondary, lineStartPos, lineStartPos + lineLen) ||
rangeTouchesRectSel(&buf->highlight, lineStartPos,
lineStartPos + lineLen))) {
dispIndexOffset = BufCountDispChars(buf,
BufStartOfLine(buf, lineStartPos), lineStartPos);
}
else
dispIndexOffset =
0;
x = textD->left - textD->horizOffset;
outIndex =
0;
int rbEnd = lineLen;
int rbCharIndex =
0;
int rbPixelIndex =
0;
inc =
1;
for (charIndex =
0; ; charIndex+=inc) {
if(charIndex >= lineLen) {
baseChar =
'\0';
charLen =
1;
inc =
1;
}
else {
baseChar = lineStr[charIndex];
const char *line = lineStr + charIndex;
int remainingLen = lineLen - charIndex;
inc = getCharWidth(textD, line, &uc, remainingLen);
if(inc >
1) {
charLen =
1;
expandedChar[
0] = uc;
}
else {
charLen = BufExpandCharacter4(lineStr[charIndex],
outIndex,
expandedChar,
buf->tabDist, buf->nullSubsChar);
}
}
style = styleOfPos(textD, lineStartPos, lineLen, charIndex,
outIndex + dispIndexOffset, baseChar);
charWidth = charIndex >= lineLen
? stdCharWidth
: charWidth4(
textD,
expandedChar,
charLen,
styleFL = styleFontList(textD, style));
if (x + charWidth >= leftClip && charIndex >= leftCharIndex) {
startIndex = charIndex;
outStartIndex = outIndex;
startX = x;
styleFont = FindFont(styleFL, uc);
break;
}
if(textD->ansiColors && baseChar ==
'\e') {
newAnsiStyle.fg = -
1;
newAnsiStyle.bg = -
1;
newAnsiStyle.bold = -
1;
newAnsiStyle.italic = -
1;
parseEscapeSequence(buf, lineStartPos + charIndex, &newAnsiStyle);
extendAnsiStyle(&ansi, &newAnsiStyle);
ansiS = charIndex;
}
if(indentRainbow) {
if(isspace(baseChar)) {
if(baseChar ==
'\t') {
rbCharIndex += buf->tabDist - rbCharIndex % buf->tabDist;
}
else {
rbCharIndex++;
}
}
else {
rbEnd = charIndex;
}
}
x += charWidth;
outIndex += charLen;
}
rbPixelIndex = rbCharIndex / rbTabDist;
if(rbEnd < startIndex) {
indentRainbow =
0;
}
if(textD->d) {
XRectangle rect;
rect.x =
0;
rect.y =
0;
rect.width = rightClip - leftClip;
rect.height = textD->ascent + textD->descent;
XftDrawSetClipRectangles(textD->d, leftClip, y, &rect,
1);
}
int rbCurrentPixelIndex =
0;
if(!indentRainbow) {
rbCurrentPixelIndex = -
1;
rbPixelIndex = -
1;
}
if(textD->highlightCursorLine && TextDRangeHasCursor(textD, startOfLine, endOfLine)) {
cursorLine = True;
}
outPtr = outStr;
outIndex = outStartIndex;
x = startX;
inc =
1;
for (charIndex = startIndex; charIndex < rightCharIndex; charIndex += inc) {
if (TextDPosHasCursor(textD, lineStartPos+charIndex, &cursorIndex)) {
if (charIndex < lineLen
|| (charIndex == lineLen && (lineStartPos+charIndex) >= buf->length)) {
hasCursor = True;
cursorX[cursorNum].cursorX = x -
1;
cursorX[cursorNum].index = cursorIndex;
cursorNum++;
}
else if (charIndex == lineLen) {
if (wrapUsesCharacter(textD, (lineStartPos+charIndex))) {
hasCursor = True;
cursorX[cursorNum].cursorX = x -
1;
cursorX[cursorNum].index = cursorIndex;
cursorNum++;
}
}
}
int cpCharLen;
if(charIndex >= lineLen) {
baseChar =
'\0';
charLen =
1;
rbCurrentPixelIndex = -
1;
cpCharLen = -
1;
}
else {
baseChar = lineStr[charIndex];
if(indentRainbow) {
if(isspace(baseChar)) {
if(baseChar ==
'\t') {
rbCharIndex += buf->tabDist - rbCharIndex % buf->tabDist;
}
else {
rbCharIndex++;
}
rbCurrentPixelIndex = ((rbCharIndex+rbTabDist-
1) / rbTabDist)+textD->colorProfile->numRainbowColors -
1;
}
else {
rbCurrentPixelIndex = -
1;
indentRainbow =
0;
if(rbCharIndex % rbTabDist >
0) {
rbPixelIndex = -
2;
}
}
}
inc = getCharWidth(textD, lineStr+charIndex, &uc, lineLen - charIndex);
if(inc >
1) {
if(uc !=
0) {
charLen =
1;
expandedChar[
0] = uc;
}
else {
charLen =
0;
}
}
else {
charLen = BufExpandCharacter4(lineStr[charIndex],
outIndex,
expandedChar,
buf->tabDist, buf->nullSubsChar);
}
cpCharLen = charLen;
}
if(textD->ansiColors && baseChar ==
'\e') {
newAnsiStyle.fg = -
1;
newAnsiStyle.bg = -
1;
newAnsiStyle.bold = -
1;
newAnsiStyle.italic = -
1;
parseEscapeSequence(buf, lineStartPos + charIndex, &newAnsiStyle);
ansiCharS = charIndex;
}
charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex,
outIndex + dispIndexOffset, baseChar);
charFL = styleFontList(textD, charStyle);
charFont = FindFont(charFL, uc);
if (charStyle != style || charFont != styleFont || rbPixelIndex != rbCurrentPixelIndex || ansiS != ansiCharS) {
drawString(textD, style, rbPixelIndex, startX, y, max(startX, leftClip), min(x, rightClip), outStr, outPtr - outStr, cursorLine, &ansi);
outPtr = outStr;
startX = x;
style = charStyle;
styleFont = charFont;
rbPixelIndex = rbCurrentPixelIndex;
extendAnsiStyle(&ansi, &newAnsiStyle);
}
ansiS = ansiCharS;
if(cpCharLen ==
1) {
*outPtr = *expandedChar;
charWidth = charWidth4(textD, expandedChar, charLen, charFL);
}
else if(charIndex < lineLen) {
memcpy(outPtr, expandedChar,
sizeof(FcChar32)*charLen);
charWidth = charWidth4(textD, expandedChar, charLen, charFL);
}
else {
charWidth = stdCharWidth;
}
outPtr += charLen;
x += charWidth;
outIndex += charLen;
if (outPtr - outStr +
MAX_EXP_CHAR_LEN >=
MAX_DISP_LINE_LEN
|| x >= rightClip) {
break;
}
}
extendAnsiStyle(&ansi, &newAnsiStyle);
drawString(textD, style, rbCurrentPixelIndex, startX, y, max(startX, leftClip), min(x, rightClip), outStr, outPtr - outStr, cursorLine, &ansi);
y_orig = textD->cursor->y;
if (textD->cursorOn) {
if (hasCursor) {
for(
int i=
0;i<cursorNum;i++) {
drawCursor(textD, cursorX[i].cursorX, y);
cursorIndex = cursorX[i].index;
if(cursorIndex >=
0) {
textD->multicursor[cursorIndex].x = cursorX[i].cursorX;
textD->multicursor[cursorIndex].y = y;
}
}
}
else if (charIndex < lineLen
&& TextDPosHasCursor(textD, lineStartPos+charIndex+
1, &cursorIndex)
&& x == rightClip) {
if ((lineStartPos+charIndex+
1) >= buf->length) {
drawCursor(textD, x -
1, y);
if(cursorIndex >=
0) {
textD->multicursor[cursorIndex].x = x -
1;
textD->multicursor[cursorIndex].y = y;
}
}
else {
if (wrapUsesCharacter(textD, lineStartPos+charIndex+
1)) {
drawCursor(textD, x -
1, y);
if(cursorIndex >=
0) {
textD->multicursor[cursorIndex].x = x -
1;
textD->multicursor[cursorIndex].y = y;
}
}
}
}
else if (TextDPosHasCursor(textD, lineStartPos + rightCharIndex, &cursorIndex)) {
drawCursor(textD, x -
1, y);
if(cursorIndex >=
0) {
textD->multicursor[cursorIndex].x = x -
1;
textD->multicursor[cursorIndex].y = y;
}
}
}
if(hasCursor && textD->mcursorSizeReal ==
1) {
int cx = cursorX[
0].cursorX;
if(cx != textD->xic_x || y != textD->xic_y) {
TextWidget textwidget = (TextWidget)textD->w;
if(textwidget->text.xic) {
XPoint ipos;
ipos.x = cx - (FontDefault(textD->font)->max_advance_width /
3);
ipos.y = y;
XVaNestedList xicvals;
xicvals = XVaCreateNestedList(
0, XNSpotLocation, &ipos,
NULL);
XSetICValues(textwidget->text.xic, XNPreeditAttributes, xicvals,
NULL);
XFree(xicvals);
textD->xic_x = cx;
textD->xic_y = y;
}
}
}
if (hasCursor && (y_orig != textD->cursor->y || y_orig != y))
TextDRedrawCalltip(textD,
0);
NEditFree(lineStrFree);
if(textD->mcursorSizeReal >
1) NEditFree(cursorX);
}
static void drawString(textDisp *textD,
int style,
int rbIndex,
int x,
int y,
int fromX,
int toX, FcChar32 *string,
int nChars, Boolean highlightLine, ansiStyle *ansi)
{
if(toX < fromX || nChars ==
0)
return;
XftColor *gc = &textD->colorProfile->textFgColor;
NFont *fontList = textD->font;
XftColor *bground = &textD->colorProfile->textBgColor;
XftColor *fground = &textD->colorProfile->textFgColor;
int underlineStyle =
FALSE;
XftColor color = textD->colorProfile->textFgColor;
if (XtWindow(textD->w) ==
0)
return;
if(nChars ==
0) rbIndex = -
1;
if (rbIndex >=
0 || style & (
STYLE_LOOKUP_MASK |
BACKLIGHT_MASK |
RANGESET_MASK)) {
gc = &textD->styleGC;
}
else if (style &
HIGHLIGHT_MASK) {
bground = &textD->colorProfile->hiliteBgColor;
color = textD->colorProfile->hiliteFgColor;
}
else if (style &
PRIMARY_MASK) {
bground = &textD->colorProfile->selectBgColor;
color = textD->colorProfile->selectFgColor;
}
else if (highlightLine && textD->highlightCursorLine) {
bground = &textD->colorProfile->lineHiBgColor;
}
else {
gc = &textD->colorProfile->textFgColor;
}
if (gc == &textD->styleGC) {
styleTableEntry *styleRec;
if (style &
STYLE_LOOKUP_MASK) {
styleRec = &textD->styleTable[(style &
STYLE_LOOKUP_MASK) -
ASCII_A];
underlineStyle = styleRec->underline;
fontList = styleRec->font;
color = styleRec->color;
}
else {
styleRec =
NULL;
fground = &textD->colorProfile->textFgColor;
}
bground =
style &
PRIMARY_MASK ? &textD->colorProfile->selectBgColor :
style &
HIGHLIGHT_MASK ? &textD->colorProfile->hiliteBgColor :
style &
RANGESET_MASK ?
getRangesetColor(textD,
(style&
RANGESET_MASK)>>
RANGESET_SHIFT,
bground) :
rbIndex >=
0 ? &textD->colorProfile->rainbowColors[rbIndex%textD->colorProfile->numRainbowColors] :
styleRec && styleRec->bgColorName ? &styleRec->bgColor :
(style &
BACKLIGHT_MASK) && !(style &
FILL_MASK) ?
&textD->bgClassPixel[(style>>
BACKLIGHT_SHIFT) & 0xff] :
&textD->colorProfile->textBgColor;
if (fground == bground)
fground = &textD->colorProfile->textBgColor;
if((bground == &textD->colorProfile->textBgColor || rbIndex >=
0) && highlightLine && textD->highlightCursorLine) {
bground = &textD->colorProfile->lineHiBgColor;
}
}
XftColor ansiBGColor;
if(ansi->fg >
0) {
ansiFgToColorIndex(textD, ansi->fg, &color);
}
if(ansi->bg >
0 && bground == &textD->colorProfile->textBgColor) {
ansiBgToColorIndex(textD, ansi->bg, &ansiBGColor);
bground = &ansiBGColor;
}
if(ansi->bold >
0 || ansi->italic >
0) {
if(ansi->bold == ansi->italic) {
fontList = textD->boldItalicFont;
}
else if(ansi->bold ==
1) {
fontList = textD->boldFont;
}
else {
fontList = textD->italicFont;
}
}
if (toX >= textD->left) {
clearRect(
textD,
bground,
fromX,
y,
toX - fromX,
textD->ascent + textD->descent);
}
if(style &
FILL_MASK) {
return;
}
XftFont *font = FindFont(fontList, string[
0]);
if (font->ascent < textD->ascent)
clearRect(textD, bground, fromX, y, toX - fromX, textD->ascent - font->ascent);
if (font->descent < textD->descent)
clearRect(textD, bground, fromX, y + textD->ascent + font->descent, toX - fromX,
textD->descent - font->descent);
XftDrawString32(textD->d, &color, font, x, y + textD->ascent, string, nChars);
if (style &
SECONDARY_MASK || underlineStyle)
{
XftDrawRect(textD->d, fground, x, y + textD->ascent, toX -
1,
1);
}
}
static void clearRect(textDisp *textD, XftColor *color,
int x,
int y,
int width,
int height)
{
if (width ==
0 || XtWindow(textD->w) ==
0)
return;
if (color == &textD->colorProfile->textBgColor) {
XClearArea(XtDisplay(textD->w), XtWindow(textD->w), x, y,
width, height, False);
}
else {
XftDrawRect(textD->d, color, x, y, width, height);
}
}
static void drawCursor(textDisp *textD,
int x,
int y)
{
XSegment segs[
5];
int left, right, cursorWidth, midY;
int fontWidth = textD->font->minWidth;
int fontHeight = textD->ascent + textD->descent;
int nSegs =
0;
int bot = y + fontHeight -
1;
if (XtWindow(textD->w) ==
0 || x < textD->left-
1 ||
x > textD->left + textD->width)
return;
cursorWidth = (fontWidth/
3) *
2;
if(textD->mcursorOn && textD->cursorStyle !=
CARET_CURSOR && textD->cursorStyle !=
BLOCK_CURSOR) {
cursorWidth =
0;
}
left = x - cursorWidth/
2;
right = left + cursorWidth;
if (textD->cursorStyle ==
CARET_CURSOR) {
midY = bot - fontHeight/
5;
segs[
0].x1 = left; segs[
0].y1 = bot; segs[
0].x2 = x; segs[
0].y2 = midY;
segs[
1].x1 = x; segs[
1].y1 = midY; segs[
1].x2 = right; segs[
1].y2 = bot;
segs[
2].x1 = left; segs[
2].y1 = bot; segs[
2].x2 = x; segs[
2].y2=midY-
1;
segs[
3].x1 = x; segs[
3].y1=midY-
1; segs[
3].x2 = right; segs[
3].y2 = bot;
nSegs =
4;
}
else if (textD->cursorStyle ==
NORMAL_CURSOR) {
segs[
0].x1 = left; segs[
0].y1 = y; segs[
0].x2 = right; segs[
0].y2 = y;
segs[
1].x1 = x; segs[
1].y1 = y; segs[
1].x2 = x; segs[
1].y2 = bot;
segs[
2].x1 = left; segs[
2].y1 = bot; segs[
2].x2 = right; segs[
2].y2=bot;
nSegs =
3;
}
else if (textD->cursorStyle ==
HEAVY_CURSOR) {
segs[
0].x1 = x-
1; segs[
0].y1 = y; segs[
0].x2 = x-
1; segs[
0].y2 = bot;
segs[
1].x1 = x; segs[
1].y1 = y; segs[
1].x2 = x; segs[
1].y2 = bot;
segs[
2].x1 = x+
1; segs[
2].y1 = y; segs[
2].x2 = x+
1; segs[
2].y2 = bot;
segs[
3].x1 = left; segs[
3].y1 = y; segs[
3].x2 = right; segs[
3].y2 = y;
segs[
4].x1 = left; segs[
4].y1 = bot; segs[
4].x2 = right; segs[
4].y2=bot;
nSegs =
5;
}
else if (textD->cursorStyle ==
DIM_CURSOR) {
midY = y + fontHeight/
2;
segs[
0].x1 = x; segs[
0].y1 = y; segs[
0].x2 = x; segs[
0].y2 = y;
segs[
1].x1 = x; segs[
1].y1 = midY; segs[
1].x2 = x; segs[
1].y2 = midY;
segs[
2].x1 = x; segs[
2].y1 = bot; segs[
2].x2 = x; segs[
2].y2 = bot;
nSegs =
3;
}
else if (textD->cursorStyle ==
BLOCK_CURSOR) {
right = x + fontWidth;
segs[
0].x1 = x; segs[
0].y1 = y; segs[
0].x2 = right; segs[
0].y2 = y;
segs[
1].x1 = right; segs[
1].y1 = y; segs[
1].x2 = right; segs[
1].y2=bot;
segs[
2].x1 = right; segs[
2].y1 = bot; segs[
2].x2 = x; segs[
2].y2 = bot;
segs[
3].x1 = x; segs[
3].y1 = bot; segs[
3].x2 = x; segs[
3].y2 = y;
nSegs =
4;
}
XDrawSegments(XtDisplay(textD->w), XtWindow(textD->w),
textD->cursorFGGC, segs, nSegs);
textD->cursor->x = x;
textD->cursor->y = y;
}
static int styleOfPos(textDisp *textD,
int lineStartPos,
int lineLen,
int lineIndex,
int dispIndex,
int thisChar)
{
textBuffer *buf = textD->buffer;
textBuffer *styleBuf = textD->styleBuffer;
int pos, style =
0;
if (lineStartPos == -
1 || buf ==
NULL)
return FILL_MASK;
pos = lineStartPos + min(lineIndex, lineLen);
if (lineIndex >= lineLen)
style =
FILL_MASK;
else if (styleBuf !=
NULL) {
style = (
unsigned char)BufGetCharacter(styleBuf, pos);
if (style == textD->unfinishedStyle) {
(textD->unfinishedHighlightCB)(textD, pos, textD->highlightCBArg);
style = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
}
if (inSelection(&buf->primary, pos, lineStartPos, dispIndex))
style |=
PRIMARY_MASK;
if (inSelection(&buf->highlight, pos, lineStartPos, dispIndex))
style |=
HIGHLIGHT_MASK;
if (inSelection(&buf->secondary, pos, lineStartPos, dispIndex))
style |=
SECONDARY_MASK;
if (buf->rangesetTable) {
int rangesetIndex = RangesetIndex1ofPos(buf->rangesetTable, pos, True);
style |= ((rangesetIndex <<
RANGESET_SHIFT) &
RANGESET_MASK);
}
if (textD->bgClass)
{
style |= (textD->bgClass[(
unsigned char)thisChar]<<
BACKLIGHT_SHIFT);
}
return style;
}
static int charWidth4(
const textDisp* textD,
const FcChar32* string,
int length, NFont *fontList)
{
if(string[
0] ==
0)
return 0;
int strWidth =
0;
if(fontList->minWidth == fontList->maxWidth && string[
0] <
128) {
strWidth += fontList->minWidth * length;
}
else {
XftFont *font = FindFont(fontList, string[
0]);
XGlyphInfo extents;
XftTextExtents32(XtDisplay(textD->w), font, string, length, &extents);
strWidth = extents.xOff;
}
return strWidth;
}
static NFont* styleFontList(
const textDisp* textD,
int style)
{
NFont *font;
if (style &
STYLE_LOOKUP_MASK)
font = textD->styleTable[(style &
STYLE_LOOKUP_MASK) -
ASCII_A].font;
else
font = textD->font;
return font;
}
static int inSelection(selection *sel,
int pos,
int lineStartPos,
int dispIndex)
{
return sel->selected &&
((!sel->rectangular &&
pos >= sel->start && pos < sel->end) ||
(sel->rectangular &&
pos >= sel->start && lineStartPos <= sel->end &&
dispIndex >= sel->rectStart && dispIndex < sel->rectEnd));
}
static int xyToPos(textDisp *textD,
int x,
int y,
int posType)
{
int charIndex, lineStart, lineLen, fontHeight;
int charWidth, charLen, charStyle, visLineNum, xStep, outIndex, inc;
FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
FcChar32 uc =
0;
NFont *font;
fontHeight = textD->ascent + textD->descent;
visLineNum = (y - textD->top) / fontHeight;
if (visLineNum <
0)
return textD->firstChar;
if (visLineNum >= textD->nVisibleLines)
visLineNum = textD->nVisibleLines -
1;
lineStart = textD->lineStarts[visLineNum];
if (lineStart == -
1)
return textD->buffer->length;
lineLen = visLineLength(textD, visLineNum);
char *lineStrAlloc;
const char *lineStr = BufGetRange2(textD->buffer, lineStart, lineStart + lineLen, &lineStrAlloc);
xStep = textD->left - textD->horizOffset;
outIndex =
0;
inc =
1;
for(charIndex=
0; charIndex<lineLen; charIndex+=inc) {
inc = getCharWidth(textD, lineStr+charIndex, &uc, lineLen-charIndex);
if(inc >
1) {
charLen =
1;
expandedChar[
0] = uc;
}
else {
charLen = BufExpandCharacter4(lineStr[charIndex],
outIndex,
expandedChar,
textD->buffer->tabDist, textD->buffer->nullSubsChar);
}
charStyle = styleOfPos(textD, lineStart, lineLen, charIndex, outIndex,
lineStr[charIndex]);
font = styleFontList(textD, charStyle);
charWidth = charWidth4(textD, expandedChar, charLen, font);
if (x < xStep + (posType ==
CURSOR_POS ? charWidth/
2 : charWidth)) {
NEditFree(lineStrAlloc);
return lineStart + charIndex;
}
xStep += charWidth;
outIndex += charLen;
}
NEditFree(lineStrAlloc);
return lineStart + lineLen;
}
static void xyToUnconstrainedPos(textDisp *textD,
int x,
int y,
int *row,
int *column,
int posType)
{
int fontHeight = textD->ascent + textD->descent;
int fontWidth = textD->font->maxWidth;
*row = (y - textD->top) / fontHeight;
if (*row <
0) *row =
0;
if (*row >= textD->nVisibleLines) *row = textD->nVisibleLines -
1;
*column = ((x-textD->left) + textD->horizOffset +
(posType ==
CURSOR_POS ? fontWidth/
2 :
0)) / fontWidth;
if (*column <
0) *column =
0;
}
static void offsetLineStarts(textDisp *textD,
int newTopLineNum)
{
int oldTopLineNum = textD->topLineNum;
int oldFirstChar = textD->firstChar;
int lineDelta = newTopLineNum - oldTopLineNum;
int nVisLines = textD->nVisibleLines;
int *lineStarts = textD->lineStarts;
int i, lastLineNum;
textBuffer *buf = textD->buffer;
if (lineDelta ==
0)
return;
lastLineNum = oldTopLineNum + nVisLines -
1;
if (newTopLineNum < oldTopLineNum && newTopLineNum < -lineDelta) {
textD->firstChar = TextDCountForwardNLines(textD,
0, newTopLineNum-
1,
True);
}
else if (newTopLineNum < oldTopLineNum) {
textD->firstChar = TextDCountBackwardNLines(textD, textD->firstChar,
-lineDelta);
}
else if (newTopLineNum < lastLineNum) {
textD->firstChar = lineStarts[newTopLineNum - oldTopLineNum];
}
else if (newTopLineNum-lastLineNum < textD->nBufferLines-newTopLineNum) {
textD->firstChar = TextDCountForwardNLines(textD,
lineStarts[nVisLines-
1], newTopLineNum - lastLineNum, True);
}
else {
textD->firstChar = TextDCountBackwardNLines(textD, buf->length,
textD->nBufferLines - newTopLineNum +
1);
}
if (lineDelta <
0 && -lineDelta < nVisLines) {
for (i=nVisLines-
1; i >= -lineDelta; i--)
lineStarts[i] = lineStarts[i+lineDelta];
calcLineStarts(textD,
0, -lineDelta);
}
else if (lineDelta >
0 && lineDelta < nVisLines) {
for (i=
0; i<nVisLines-lineDelta; i++)
lineStarts[i] = lineStarts[i+lineDelta];
calcLineStarts(textD, nVisLines-lineDelta, nVisLines-
1);
}
else
calcLineStarts(textD,
0, nVisLines);
calcLastChar(textD);
textD->topLineNum = newTopLineNum;
offsetAbsLineNum(textD, oldFirstChar);
}
static void updateLineStarts(textDisp *textD,
int pos,
int charsInserted,
int charsDeleted,
int linesInserted,
int linesDeleted,
int *scrolled)
{
int *lineStarts = textD->lineStarts;
int i, lineOfPos, lineOfEnd, nVisLines = textD->nVisibleLines;
int charDelta = charsInserted - charsDeleted;
int lineDelta = linesInserted - linesDeleted;
if (pos + charsDeleted < textD->firstChar) {
textD->topLineNum += lineDelta;
for (i=
0; i<nVisLines && lineStarts[i] != -
1; i++)
lineStarts[i] += charDelta;
textD->firstChar += charDelta;
textD->lastChar += charDelta;
*scrolled = False;
return;
}
if (pos < textD->firstChar) {
if (posToVisibleLineNum(textD, pos + charsDeleted, &lineOfEnd) &&
++lineOfEnd < nVisLines && lineStarts[lineOfEnd] != -
1) {
textD->topLineNum = max(
1, textD->topLineNum + lineDelta);
textD->firstChar = TextDCountBackwardNLines(textD,
lineStarts[lineOfEnd] + charDelta, lineOfEnd);
}
else {
if (textD->topLineNum > textD->nBufferLines + lineDelta) {
textD->topLineNum =
1;
textD->firstChar =
0;
}
else
textD->firstChar = TextDCountForwardNLines(textD,
0,
textD->topLineNum -
1, True);
}
calcLineStarts(textD,
0, nVisLines-
1);
calcLastChar(textD);
*scrolled = True;
return;
}
if (pos <= textD->lastChar) {
posToVisibleLineNum(textD, pos, &lineOfPos);
if (lineDelta ==
0) {
for (i=lineOfPos+
1; i<nVisLines && lineStarts[i]!= -
1; i++)
lineStarts[i] += charDelta;
}
else if (lineDelta >
0) {
for (i=nVisLines-
1; i>=lineOfPos+lineDelta+
1; i--)
lineStarts[i] = lineStarts[i-lineDelta] +
(lineStarts[i-lineDelta] == -
1 ?
0 : charDelta);
}
else {
for (i=max(
0,lineOfPos+
1); i<nVisLines+lineDelta; i++)
lineStarts[i] = lineStarts[i-lineDelta] +
(lineStarts[i-lineDelta] == -
1 ?
0 : charDelta);
}
if (linesInserted >=
0)
calcLineStarts(textD, lineOfPos +
1, lineOfPos + linesInserted);
if (lineDelta <
0)
calcLineStarts(textD, nVisLines+lineDelta, nVisLines);
calcLastChar(textD);
*scrolled = False;
return;
}
if (emptyLinesVisible(textD)) {
posToVisibleLineNum(textD, pos, &lineOfPos);
calcLineStarts(textD, lineOfPos, lineOfPos+linesInserted);
calcLastChar(textD);
*scrolled = False;
return;
}
*scrolled = False;
}
static void calcLineStarts(textDisp *textD,
int startLine,
int endLine)
{
int startPos, bufLen = textD->buffer->length;
int line, lineEnd, nextLineStart, nVis = textD->nVisibleLines;
int *lineStarts = textD->lineStarts;
if (nVis ==
0)
return;
if (endLine <
0) endLine =
0;
if (endLine >= nVis) endLine = nVis -
1;
if (startLine <
0) startLine =
0;
if (startLine >=nVis) startLine = nVis -
1;
if (startLine > endLine)
return;
if (startLine ==
0) {
lineStarts[
0] = textD->firstChar;
startLine =
1;
}
startPos = lineStarts[startLine-
1];
if (startPos == -
1) {
for (line=startLine; line<=endLine; line++)
lineStarts[line] = -
1;
return;
}
for (line=startLine; line<=endLine; line++) {
findLineEnd(textD, startPos, True, &lineEnd, &nextLineStart);
startPos = nextLineStart;
if (startPos >= bufLen) {
if (line ==
0 || (lineStarts[line-
1] != bufLen &&
lineEnd != nextLineStart)) {
lineStarts[line] = bufLen;
line++;
}
break;
}
lineStarts[line] = startPos;
}
for (; line<=endLine; line++)
lineStarts[line] = -
1;
}
static void calcLastChar(textDisp *textD)
{
int i;
for (i=textD->nVisibleLines-
1; i>
0 && textD->lineStarts[i]== -
1; i--);
textD->lastChar = i <
0 ?
0 :
TextDEndOfLine(textD, textD->lineStarts[i], True);
}
void TextDImposeGraphicsExposeTranslation(textDisp *textD,
int *xOffset,
int *yOffset)
{
if (textD->graphicsExposeQueue) {
graphicExposeTranslationEntry *thisGEQEntry = textD->graphicsExposeQueue->next;
if (thisGEQEntry) {
*xOffset += thisGEQEntry->horizontal;
*yOffset += thisGEQEntry->vertical;
}
}
}
Boolean TextDPopGraphicExposeQueueEntry(textDisp *textD)
{
graphicExposeTranslationEntry *removedGEQEntry = textD->graphicsExposeQueue;
if (removedGEQEntry) {
textD->graphicsExposeQueue = removedGEQEntry->next;
NEditFree(removedGEQEntry);
}
return(removedGEQEntry?True:False);
}
void TextDTranlateGraphicExposeQueue(textDisp *textD,
int xOffset,
int yOffset, Boolean appendEntry)
{
graphicExposeTranslationEntry *newGEQEntry =
NULL;
if (appendEntry) {
newGEQEntry = (graphicExposeTranslationEntry *)NEditMalloc(
sizeof(graphicExposeTranslationEntry));
newGEQEntry->next =
NULL;
newGEQEntry->horizontal = xOffset;
newGEQEntry->vertical = yOffset;
}
if (textD->graphicsExposeQueue) {
graphicExposeTranslationEntry *iter = textD->graphicsExposeQueue;
while (iter->next) {
iter->next->horizontal += xOffset;
iter->next->vertical += yOffset;
iter = iter->next;
}
if (appendEntry) {
iter->next = (
struct graphicExposeTranslationEntry *)newGEQEntry;
}
}
else {
if (appendEntry) {
textD->graphicsExposeQueue = newGEQEntry;
}
}
}
static void setScroll(textDisp *textD,
int topLineNum,
int horizOffset,
int updateVScrollBar,
int updateHScrollBar)
{
int fontHeight = textD->ascent + textD->descent;
int origHOffset = textD->horizOffset;
int lineDelta = textD->topLineNum - topLineNum;
int xOffset, yOffset, srcX, srcY, dstX, dstY, width, height;
int exactHeight = textD->height - textD->height %
(textD->ascent + textD->descent);
if (XtWindow(textD->w) ==
0 || (textD->horizOffset == horizOffset &&
textD->topLineNum == topLineNum))
return;
blankCursorProtrusions(textD);
offsetLineStarts(textD, topLineNum);
textD->horizOffset = horizOffset;
if (updateVScrollBar && textD->vScrollBar !=
NULL) {
updateVScrollBarRange(textD);
}
if (updateHScrollBar && textD->hScrollBar !=
NULL) {
updateHScrollBarRange(textD);
}
xOffset = origHOffset - textD->horizOffset;
yOffset = lineDelta * fontHeight;
if(
1) {
TextDTranlateGraphicExposeQueue(textD, xOffset, yOffset, False);
TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
textD->height);
}
else {
srcX = textD->left + (xOffset >=
0 ?
0 : -xOffset);
dstX = textD->left + (xOffset >=
0 ? xOffset :
0);
width = textD->width - abs(xOffset);
srcY = textD->top + (yOffset >=
0 ?
0 : -yOffset);
dstY = textD->top + (yOffset >=
0 ? yOffset :
0);
height = exactHeight - abs(yOffset);
resetClipRectangles(textD);
TextDTranlateGraphicExposeQueue(textD, xOffset, yOffset, True);
XCopyArea(XtDisplay(textD->w), XtWindow(textD->w), XtWindow(textD->w),
textD->gc, srcX, srcY, width, height, dstX, dstY);
if (yOffset >
0) {
TextDRedisplayRect(textD, textD->left, textD->top,
textD->width, yOffset);
}
else if (yOffset <
0) {
TextDRedisplayRect(textD, textD->left, textD->top +
textD->height + yOffset, textD->width, -yOffset);
}
if (xOffset >
0) {
TextDRedisplayRect(textD, textD->left, textD->top,
xOffset, textD->height);
}
else if (xOffset <
0) {
TextDRedisplayRect(textD, textD->left + textD->width + xOffset,
textD->top, -xOffset, textD->height);
}
int left, right;
TextDCursorLR(textD, &left, &right);
textDRedisplayRange(textD, left, right);
}
if (lineDelta !=
0) {
redrawLineNumbers(textD, textD->top, textD->height, True);
TextDRedrawCalltip(textD,
0);
}
HandleAllPendingGraphicsExposeNoExposeEvents((TextWidget)textD->w,
NULL);
}
static void updateVScrollBarRange(textDisp *textD)
{
int sliderSize, sliderMax, sliderValue;
if (textD->vScrollBar ==
NULL)
return;
sliderSize = max(textD->nVisibleLines,
1);
sliderValue = textD->topLineNum;
sliderMax = max(textD->nBufferLines +
2 +
TEXT_OF_TEXTD(textD).cursorVPadding,
sliderSize + sliderValue);
XtVaSetValues(textD->vScrollBar,
XmNmaximum, sliderMax,
XmNsliderSize, sliderSize,
XmNpageIncrement, max(
1, textD->nVisibleLines -
1),
XmNvalue, sliderValue,
NULL);
}
static int updateHScrollBarRange(textDisp *textD)
{
int i, maxWidth =
0, sliderMax, sliderWidth;
int origHOffset = textD->horizOffset;
if (textD->hScrollBar ==
NULL || !XtIsManaged(textD->hScrollBar))
return False;
for (i=
0; i<textD->nVisibleLines && textD->lineStarts[i]!= -
1; i++)
maxWidth = max(measureVisLine(textD, i), maxWidth);
if (maxWidth < textD->width + textD->horizOffset && textD->horizOffset >
0)
textD->horizOffset = max(
0, maxWidth - textD->width);
sliderWidth = textD->width;
sliderMax = max(maxWidth, sliderWidth + textD->horizOffset);
XtVaSetValues(textD->hScrollBar,
XmNmaximum, sliderMax,
XmNsliderSize, sliderWidth,
XmNpageIncrement, max(textD->width -
100,
10),
XmNvalue, textD->horizOffset,
NULL);
return origHOffset != textD->horizOffset;
}
void TextDSetLineNumberArea(textDisp *textD,
int lineNumLeft,
int lineNumWidth,
int textLeft)
{
int newWidth = textD->width + textD->left - textLeft;
textD->lineNumLeft = lineNumLeft;
textD->lineNumWidth = lineNumWidth;
textD->left = textLeft;
XClearWindow(XtDisplay(textD->w), XtWindow(textD->w));
resetAbsLineNum(textD);
TextDResize(textD, newWidth, textD->height);
TextDRedisplayRect(textD,
0, textD->top,
INT_MAX, textD->height);
}
static void redrawLineNumbers(textDisp *textD,
int top,
int height,
int clearAll)
{
int y, line, visLine, nCols, lineStart;
char lineNumString[
12];
int lineHeight = textD->ascent + textD->descent;
int charWidth = textD->font->maxWidth;
XRectangle clipRect;
if (textD->lineNumWidth ==
0 || XtWindow(textD->w) ==
0)
return;
clipRect.x =
0;
clipRect.y =
0;
clipRect.width = textD->lineNumWidth + textD->lineNumLeft;
clipRect.height = textD->height +
2*textD->top;
if(textD->d) {
XftDrawSetClipRectangles(textD->d,
0,
0, &clipRect,
1);
}
if (clearAll) {
XftDrawRect(
textD->d,
&textD->colorProfile->lineNoBgColor,
0,
0,
textD->lineNumLeft + textD->lineNumWidth,
2*top + height);
}
nCols = min(
11, textD->lineNumWidth / charWidth);
y = textD->top;
line = getAbsTopLineNum(textD);
for (visLine=
0; visLine < textD->nVisibleLines; visLine++) {
lineStart = textD->lineStarts[visLine];
if (lineStart != -
1 && (lineStart==
0 ||
BufGetCharacter(textD->buffer, lineStart-
1)==
'\n')) {
snprintf(lineNumString,
12,
"%*d", nCols, line);
XftDrawString8(
textD->d,
&textD->colorProfile->lineNoFgColor,
FontDefault(textD->font),
textD->lineNumLeft,
y + textD->ascent,
(FcChar8*)lineNumString,
strlen(lineNumString));
line++;
}
else {
if (visLine ==
0)
line++;
}
y += lineHeight;
}
}
static void vScrollCB(Widget w, XtPointer clientData, XtPointer callData)
{
textDisp *textD = (textDisp *)clientData;
int newValue = ((XmScrollBarCallbackStruct *)callData)->value;
int lineDelta = newValue - textD->topLineNum;
if (lineDelta ==
0)
return;
setScroll(textD, newValue, textD->horizOffset, False, True);
}
static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData)
{
textDisp *textD = (textDisp *)clientData;
int newValue = ((XmScrollBarCallbackStruct *)callData)->value;
if (newValue == textD->horizOffset)
return;
setScroll(textD, textD->topLineNum, newValue, False, False);
}
static void visibilityEH(Widget w, XtPointer data, XEvent *event,
Boolean *continueDispatch)
{
((textDisp *)data)->visibility = ((XVisibilityEvent *)event)->state;
}
static int max(
int i1,
int i2)
{
return i1 >= i2 ? i1 : i2;
}
static int min(
int i1,
int i2)
{
return i1 <= i2 ? i1 : i2;
}
static int countLines(
const char *string)
{
const char *c;
int lineCount =
0;
if (string ==
NULL)
return 0;
for (c=string; *c!=
'\0'; c++)
if (*c ==
'\n') lineCount++;
return lineCount;
}
static int measureVisLine(textDisp *textD,
int visLineNum)
{
textBuffer *buf = textD->buffer;
int i, width =
0, style, lineLen = visLineLength(textD, visLineNum);
int lineStartPos = textD->lineStarts[visLineNum];
char *free_lineStr;
const char *lineStr = BufGetRange2(buf, lineStartPos, lineStartPos + lineLen, &free_lineStr);
FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
FcChar32 uc;
int inc;
int charLen;
unsigned short indent =
0;
NFont *font;
for(i=
0;i<lineLen;i+=inc) {
inc = getCharWidth(textD, lineStr+i, &uc, lineLen - i);
if(inc >
1) {
charLen =
1;
expandedChar[
0] = uc;
indent += inc;
}
else {
charLen = BufExpandCharacter4(lineStr[i],
indent,
expandedChar,
buf->tabDist, buf->nullSubsChar);
indent += charLen;
}
if (textD->styleBuffer) {
style = (
unsigned char)BufGetCharacter(textD->styleBuffer,
lineStartPos+i) -
ASCII_A;
font = textD->styleTable[style].font;
}
else {
font = textD->font;
}
width += charWidth4(textD, expandedChar, charLen, font);
}
NEditFree(free_lineStr);
return width;
}
static int emptyLinesVisible(textDisp *textD)
{
return textD->nVisibleLines >
0 &&
textD->lineStarts[textD->nVisibleLines-
1] == -
1;
}
static void blankSingleCursorProtrusions(textDisp *textD)
{
int x, width, cursorX = textD->cursor->x, cursorY = textD->cursor->y;
int fontWidth = textD->font->maxWidth;
int fontHeight = textD->ascent + textD->descent;
int cursorWidth, left = textD->left, right = left + textD->width;
cursorWidth = (fontWidth/
3) *
2;
if (cursorX >= left-
1 && cursorX <= left + cursorWidth/
2 -
1) {
x = cursorX - cursorWidth/
2;
width = left - x;
}
else if (cursorX >= right - cursorWidth/
2 && cursorX <= right) {
x = right;
width = cursorX + cursorWidth/
2 +
2 - right;
}
else
return;
XClearArea(XtDisplay(textD->w), XtWindow(textD->w), x, cursorY,
width, fontHeight, False);
}
static void blankCursorProtrusions(textDisp *textD) {
if(textD->mcursorSize ==
1) {
blankSingleCursorProtrusions(textD);
}
else {
textCursor *origCursor = textD->cursor;
for(
int i=
0;i<textD->mcursorSize;i++) {
textD->cursor = textD->multicursor + i;
blankSingleCursorProtrusions(textD);
}
textD->cursor = origCursor;
}
}
static void allocateFixedFontGCs(textDisp *textD, Pixel bgPixel, Pixel fgPixel)
{
textD->gc = allocateGC(textD->w, GCForeground | GCBackground,
fgPixel, bgPixel,
0, GCClipMask, GCArcMode);
}
static GC allocateGC(Widget w,
unsigned long valueMask,
unsigned long foreground,
unsigned long background, Font font,
unsigned long dynamicMask,
unsigned long dontCareMask)
{
XGCValues gcValues;
gcValues.font = font;
gcValues.background = background;
gcValues.foreground = foreground;
#if defined(XlibSpecificationRelease) && XlibSpecificationRelease >
4
return XtAllocateGC(w,
0, valueMask, &gcValues, dynamicMask,
dontCareMask);
#else
return XCreateGC(XtDisplay(w), RootWindowOfScreen(XtScreen(w)),
valueMask, &gcValues);
#endif
}
static void releaseGC(Widget w,
GC gc)
{
#if defined(XlibSpecificationRelease) && XlibSpecificationRelease >
4
XtReleaseGC(w, gc);
#else
XFreeGC(XtDisplay(w), gc);
#endif
}
static void resetClipRectangles(textDisp *textD)
{
XRectangle clipRect;
Display *display = XtDisplay(textD->w);
clipRect.x = textD->left;
clipRect.y = textD->top;
clipRect.width = textD->width;
clipRect.height = textD->height - textD->height %
(textD->ascent + textD->descent);
XSetClipRectangles(display, textD->gc,
0,
0,
&clipRect,
1, Unsorted);
if(textD->d) {
XftDrawSetClipRectangles(textD->d,
0,
0, &clipRect,
1);
}
}
static int visLineLength(textDisp *textD,
int visLineNum)
{
int nextLineStart, lineStartPos = textD->lineStarts[visLineNum];
if (lineStartPos == -
1)
return 0;
if (visLineNum+
1 >= textD->nVisibleLines)
return textD->lastChar - lineStartPos;
nextLineStart = textD->lineStarts[visLineNum+
1];
if (nextLineStart == -
1)
return textD->lastChar - lineStartPos;
if (wrapUsesCharacter(textD, nextLineStart-
1))
return nextLineStart-
1 - lineStartPos;
return nextLineStart - lineStartPos;
}
static int findWrapRange(textDisp *textD,
const char *deletedText,
int pos,
int nInserted,
int nDeleted,
int *modRangeStart,
int *modRangeEnd,
int *linesInserted,
int *linesDeleted)
{
int length, retPos, retLines, retLineStart, retLineEnd;
textBuffer *deletedTextBuf, *buf = textD->buffer;
int nVisLines = textD->nVisibleLines;
int *lineStarts = textD->lineStarts;
int countFrom, countTo, lineStart, adjLineStart, i;
int visLineNum =
0, nLines =
0;
int nl =
0;
if (pos >= textD->firstChar && pos <= textD->lastChar) {
for (i=nVisLines-
1; i>
0; i--) {
if (lineStarts[i] != -
1 && pos >= lineStarts[i])
break;
}
if (i >
0) {
countFrom = lineStarts[i-
1];
visLineNum = i-
1;
}
else
countFrom = BufStartOfLine(buf, pos);
}
else
countFrom = BufStartOfLine(buf, pos);
lineStart = countFrom;
*modRangeStart = countFrom;
while (True) {
wrappedLineCounter(textD, buf, lineStart, buf->length,
1, True,
0,
&retPos, &retLines, &retLineStart, &retLineEnd,
NULL);
if(pos == retLineEnd) {
nl =
1;
}
if (retPos >= buf->length) {
countTo = buf->length;
*modRangeEnd = countTo;
if (retPos != retLineEnd)
nLines++;
break;
}
else
lineStart = retPos;
nLines++;
if (lineStart > pos + nInserted &&
BufGetCharacter(buf, lineStart-
1) ==
'\n') {
countTo = lineStart;
*modRangeEnd = lineStart;
break;
}
if (textD->suppressResync)
continue;
if (lineStart <= pos) {
while (visLineNum<nVisLines && lineStarts[visLineNum] < lineStart)
visLineNum++;
if (visLineNum < nVisLines && lineStarts[visLineNum] == lineStart) {
countFrom = lineStart;
nLines =
0;
if (visLineNum+
1 < nVisLines && lineStarts[visLineNum+
1] != -
1)
*modRangeStart = min(pos, lineStarts[visLineNum+
1]-
1);
else
*modRangeStart = countFrom;
}
else
*modRangeStart = min(*modRangeStart, lineStart-
1);
}
else if (lineStart > pos + nInserted) {
adjLineStart = lineStart - nInserted + nDeleted;
while (visLineNum<nVisLines && lineStarts[visLineNum]<adjLineStart)
visLineNum++;
if (visLineNum < nVisLines && lineStarts[visLineNum] != -
1 &&
lineStarts[visLineNum] == adjLineStart) {
countTo = TextDEndOfLine(textD, lineStart, True);
*modRangeEnd = lineStart;
break;
}
}
}
*linesInserted = nLines;
if (textD->suppressResync) {
*linesDeleted = textD->nLinesDeleted;
textD->suppressResync =
0;
return nl;
}
length = (pos-countFrom) + nDeleted +(countTo-(pos+nInserted));
deletedTextBuf = BufCreatePreallocated(length);
if (pos > countFrom)
BufCopyFromBuf(textD->buffer, deletedTextBuf, countFrom, pos,
0);
if (nDeleted !=
0)
BufInsert(deletedTextBuf, pos-countFrom, deletedText);
if (countTo > pos+nInserted)
BufCopyFromBuf(textD->buffer, deletedTextBuf,
pos+nInserted, countTo, pos-countFrom+nDeleted);
wrappedLineCounter(textD, deletedTextBuf,
0, length,
INT_MAX, True,
countFrom, &retPos, &retLines, &retLineStart, &retLineEnd,
NULL);
BufFree(deletedTextBuf);
*linesDeleted = retLines;
textD->suppressResync =
0;
return nl;
}
static void measureDeletedLines(textDisp *textD,
int pos,
int nDeleted)
{
int retPos, retLines, retLineStart, retLineEnd;
textBuffer *buf = textD->buffer;
int nVisLines = textD->nVisibleLines;
int *lineStarts = textD->lineStarts;
int countFrom, lineStart;
int nLines =
0, i;
if (pos >= textD->firstChar && pos <= textD->lastChar) {
for (i=nVisLines-
1; i>
0; i--)
if (lineStarts[i] != -
1 && pos >= lineStarts[i])
break;
if (i >
0) {
countFrom = lineStarts[i-
1];
}
else
countFrom = BufStartOfLine(buf, pos);
}
else
countFrom = BufStartOfLine(buf, pos);
lineStart = countFrom;
while (True) {
wrappedLineCounter(textD, buf, lineStart, buf->length,
1, True,
0,
&retPos, &retLines, &retLineStart, &retLineEnd,
NULL);
if (retPos >= buf->length) {
if (retPos != retLineEnd)
nLines++;
break;
}
else
lineStart = retPos;
nLines++;
if (lineStart > pos + nDeleted &&
BufGetCharacter(buf, lineStart-
1) ==
'\n') {
break;
}
}
textD->nLinesDeleted = nLines;
textD->suppressResync =
1;
}
static void wrappedLineCounter(
const textDisp* textD,
const textBuffer* buf,
int startPos,
int maxPos,
int maxLines,
Boolean startPosIsLineStart,
int styleBufOffset,
int* retPos,
int* retLines,
int* retLineStart,
int* retLineEnd,
Boolean *retWrap)
{
int lineStart, newLineStart =
0, b, p, colNum, wrapMargin;
int maxWidth, width, countPixels, i, foundBreak;
int nLines =
0, tabDist = textD->buffer->tabDist;
FcChar32 c;
char nullSubsChar = textD->buffer->nullSubsChar;
if(retWrap) {
*retWrap = False;
}
if (textD->fixedFontWidth != -
1 || textD->wrapMargin !=
0) {
countPixels = False;
wrapMargin = textD->wrapMargin !=
0 ? textD->wrapMargin :
textD->width / textD->fixedFontWidth;
maxWidth =
INT_MAX;
}
else {
countPixels = True;
wrapMargin =
INT_MAX;
maxWidth = textD->width;
}
if (startPosIsLineStart)
lineStart = startPos;
else
lineStart = TextDStartOfLine(textD, startPos);
colNum =
0;
width =
0;
int inc =
1;
for (p=lineStart; p<buf->length; p+=inc) {
c = getCharacter32(textD, buf, p, &inc);
if ((
char)c ==
'\n') {
if (p >= maxPos) {
*retPos = maxPos;
*retLines = nLines;
*retLineStart = lineStart;
*retLineEnd = maxPos;
return;
}
nLines++;
if (nLines >= maxLines) {
*retPos = p +
1;
*retLines = nLines;
*retLineStart = p +
1;
*retLineEnd = p;
return;
}
lineStart = p +
1;
colNum =
0;
width =
0;
}
else if(c !=
0) {
colNum += BufCharWidth((
char)c, colNum, tabDist, nullSubsChar);
if (countPixels)
width += measurePropChar(textD, c, colNum, p+styleBufOffset);
}
if (colNum > wrapMargin || width > maxWidth) {
if(retWrap) {
*retWrap = True;
retWrap =
NULL;
}
foundBreak = False;
for (b=p; b>=lineStart; b--) {
c = BufGetCharacter(buf, b);
if ((
char)c ==
'\t' || (
char)c ==
' ') {
newLineStart = b +
1;
if (countPixels) {
colNum =
0;
width =
0;
int charLen;
for (i=b+
1; i<p+
1; i+=charLen) {
width += measurePropChar(textD,
getCharacter32(textD, buf, i, &charLen), colNum,
i+styleBufOffset);
colNum++;
}
}
else
colNum = BufCountDispChars(buf, b+
1, p+
1);
foundBreak = True;
break;
}
}
if (!foundBreak) {
newLineStart = max(p, lineStart+
1);
colNum = BufCharWidth((
char)c, colNum, tabDist, nullSubsChar);
if (countPixels)
width = measurePropChar(textD, c, colNum, p+styleBufOffset);
}
if (p >= maxPos) {
*retPos = maxPos;
*retLines = maxPos < newLineStart ? nLines : nLines +
1;
*retLineStart = maxPos < newLineStart ? lineStart :
newLineStart;
*retLineEnd = maxPos;
return;
}
nLines++;
if (nLines >= maxLines) {
*retPos = foundBreak ? b +
1 : max(p, lineStart+
1);
*retLines = nLines;
*retLineStart = lineStart;
*retLineEnd = foundBreak ? b : p;
return;
}
lineStart = newLineStart;
}
}
*retPos = buf->length;
*retLines = nLines;
*retLineStart = lineStart;
*retLineEnd = buf->length;
return;
}
static int measurePropChar(
const textDisp* textD, FcChar32 c,
int colNum,
int pos)
{
int style;
textBuffer *styleBuf = textD->styleBuffer;
NFont *font =
NULL;
if (styleBuf) {
style = (
unsigned char)BufGetCharacter(styleBuf, pos);
if (style == textD->unfinishedStyle) {
(textD->unfinishedHighlightCB)(textD, pos, textD->highlightCBArg);
style = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
if (style &
STYLE_LOOKUP_MASK) {
font = textD->styleTable[(style &
STYLE_LOOKUP_MASK) -
ASCII_A].font;
}
}
if(!font) {
font = textD->font;
}
int charLen;
FcChar32 expChar[
MAX_EXP_CHAR_LEN];
if(c <
128) {
charLen = BufExpandCharacter4(c, colNum, expChar,
textD->buffer->tabDist, textD->buffer->nullSubsChar);
if(font->minWidth == font->maxWidth) {
return font->minWidth;
}
else {
XGlyphInfo extents;
XftTextExtents32(XtDisplay(textD->w), font->fonts->font, expChar, charLen, &extents);
return extents.xOff;
}
}
else {
charLen =
1;
expChar[
0] = c;
}
return charWidth4(textD, expChar, charLen, font);
}
static void findLineEnd(textDisp *textD,
int startPos,
int startPosIsLineStart,
int *lineEnd,
int *nextLineStart)
{
int retLines, retLineStart;
if (!textD->continuousWrap) {
*lineEnd = BufEndOfLine(textD->buffer, startPos);
*nextLineStart = min(textD->buffer->length, *lineEnd +
1);
return;
}
wrappedLineCounter(textD, textD->buffer, startPos, textD->buffer->length,
1, startPosIsLineStart,
0, nextLineStart, &retLines,
&retLineStart, lineEnd,
NULL);
return;
}
static int wrapUsesCharacter(textDisp *textD,
int lineEndPos)
{
char c;
if (!textD->continuousWrap || lineEndPos == textD->buffer->length)
return True;
c = BufGetCharacter(textD->buffer, lineEndPos);
return c ==
'\n' || ((c ==
'\t' || c ==
' ') &&
lineEndPos +
1 != textD->buffer->length);
}
static void hideOrShowHScrollBar(textDisp *textD)
{
if (textD->continuousWrap && (textD->wrapMargin ==
0 || textD->wrapMargin *
FontDefault(textD->font)->max_advance_width < textD->width))
XtUnmanageChild(textD->hScrollBar);
else
XtManageChild(textD->hScrollBar);
}
static int rangeTouchesRectSel(selection *sel,
int rangeStart,
int rangeEnd)
{
return sel->selected && sel->rectangular && sel->end >= rangeStart &&
sel->start <= rangeEnd;
}
static void extendRangeForStyleMods(textDisp *textD,
int *start,
int *end)
{
selection *sel = &textD->styleBuffer->primary;
int extended = False;
if (sel->selected) {
if (sel->start < *start) {
*start = sel->start;
extended = True;
}
if (sel->end > *end) {
*end = sel->end;
extended = True;
}
}
if (textD->fixedFontWidth == -
1 && extended)
*end = BufEndOfLine(textD->buffer, *end) +
1;
}
static XftColor allocBGColor(Widget w,
char *colorName,
int *ok)
{
int r,g,b;
*ok =
1;
XftColor color;
color.pixel = AllocColor(w, colorName, &r, &g, &b);
color.color.red = r;
color.color.green = g;
color.color.blue = b;
color.color.alpha = 0xFFFF;
return color;
}
static XftColor* getRangesetColor(textDisp *textD,
int ind, XftColor *bground)
{
textBuffer *buf;
RangesetTable *tab;
XftColor color;
char *color_name;
int valid;
if (ind >
0) {
ind--;
buf = textD->buffer;
tab = buf->rangesetTable;
Rangeset *rangeset =
NULL;
valid = RangesetTableGetColorValid(tab, ind, &color, &rangeset);
if (valid ==
0) {
color_name = RangesetTableGetColorName(tab, ind);
if (color_name)
color = allocBGColor(textD->w, color_name, &valid);
rangeset = RangesetTableAssignColorPixel(tab, ind, color, valid);
}
if (valid >
0) {
return RangesetGetColor(rangeset);
}
}
return bground;
}
void TextDSetupBGClasses(Widget w, XmString str, XftColor **pp_bgClassPixel,
unsigned char **pp_bgClass, XftColor bgPixelDefault)
{
unsigned char bgClass[
256];
XftColor bgClassPixel[
256];
int class_no =
0;
char *semicol;
char *s = (
char *)str;
size_t was_semicol;
int lo, hi, dummy;
char *pos;
Boolean is_good = True;
NEditFree(*pp_bgClass);
NEditFree(*pp_bgClassPixel);
*pp_bgClassPixel =
NULL;
*pp_bgClass =
NULL;
if (!s)
return;
memset(bgClassPixel,
0,
sizeof bgClassPixel);
memset(bgClass,
0,
sizeof bgClass);
bgClassPixel[
0] = bgPixelDefault;
while (s && class_no <
255) {
class_no++;
was_semicol =
0;
is_good = True;
if ((semicol = (
char *)strchr(s,
';'))) {
*semicol =
'\0';
was_semicol =
1;
}
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);
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');
bgClassPixel[class_no] = allocBGColor(w, pos, &dummy);
}
if (!is_good) {
}
if (was_semicol)
*semicol =
';';
s = semicol + was_semicol;
}
class_no++;
*pp_bgClass = (
unsigned char *)NEditMalloc(
256);
*pp_bgClassPixel = (XftColor *)NEditMalloc(class_no *
sizeof (XftColor));
if (!*pp_bgClass || !*pp_bgClassPixel) {
NEditFree(*pp_bgClass);
NEditFree(*pp_bgClassPixel);
return;
}
memcpy(*pp_bgClass, bgClass,
256);
memcpy(*pp_bgClassPixel, bgClassPixel, class_no *
sizeof (XftColor));
}
void TextDSetHighlightCursorLine(textDisp *textD, Boolean state)
{
textD->highlightCursorLine = state;
}
void TextDSetIndentRainbow(textDisp *textD, Boolean indentRainbow)
{
textD->indentRainbow = indentRainbow;
}
#define ANSI_ESC_MAX_PARAM 16
#define ANSI_ESC_MAX_PARAM_LEN 4
#define ANSI_ESC_RESET 0
#define ANSI_ESC_BOLD 1
#define ANSI_ESC_ITALIC 3
#define ANSI_ESC_RESET_BOLD 22
#define ANSI_ESC_RESET_ITALIC 23
#define ANSI_STYLE_SET(style, value)
if(style <
0) style = value
static int parseEscapeSequence(textBuffer *buf,
size_t pos, ansiStyle *style)
{
char c1 = BufGetCharacter(buf, pos);
char c2 = BufGetCharacter(buf, pos+
1);
if(c1 !=
'\e' || c2 !=
'[')
return 0;
int param[
ANSI_ESC_MAX_PARAM];
int nparam =
0;
char paramDig[
ANSI_ESC_MAX_PARAM_LEN];
int paramDigLen =
0;
size_t i = pos+
2;
while(nparam <
ANSI_ESC_MAX_PARAM) {
char c = BufGetCharacter(buf, i++);
if(c >=
'0' && c <=
'9') {
if(paramDigLen >=
ANSI_ESC_MAX_PARAM_LEN)
break;
paramDig[paramDigLen++] = c -
'0';
}
else {
int iParam =
0;
int mul =
1;
for(
int j=paramDigLen-
1;j>=
0;j--) {
iParam += paramDig[j] * mul;
mul *=
10;
}
param[nparam++] = iParam;
paramDigLen =
0;
if(c !=
';')
break;
}
}
for(
int k=
0;k<nparam;k++) {
int p = param[k];
switch(p) {
case ANSI_ESC_RESET: {
ANSI_STYLE_SET(style->fg,
0);
ANSI_STYLE_SET(style->bg,
0);
ANSI_STYLE_SET(style->bold,
0);
ANSI_STYLE_SET(style->italic,
0);
k = nparam;
break;
}
case ANSI_ESC_BOLD: {
ANSI_STYLE_SET(style->bold,
1);
break;
}
case ANSI_ESC_ITALIC: {
ANSI_STYLE_SET(style->italic,
1);
break;
}
case ANSI_ESC_RESET_BOLD: {
ANSI_STYLE_SET(style->bold,
0);
break;
}
case ANSI_ESC_RESET_ITALIC: {
ANSI_STYLE_SET(style->bold,
0);
break;
}
default: {
if((p >=
30 && p <=
39) || (p >=
90 && p <=
97)) {
ANSI_STYLE_SET(style->fg, p);
}
else if((p >=
40 && p <=
49) || (p >=
100 && p <=
107)) {
ANSI_STYLE_SET(style->bg, p);
}
break;
}
}
}
if(style->fg != -
1 && style->bg != -
1 && style->bold != -
1 && style->italic) {
return 1;
}
return 0;
}
static void extendAnsiStyle(ansiStyle *style, ansiStyle *ext)
{
if(ext->fg >=
0) {
style->fg = ext->fg;
}
if(ext->bg >=
0) {
style->bg = ext->bg;
}
if(ext->bold >=
0) style->bold = ext->bold;
if(ext->italic >=
0) style->italic = ext->italic;
}
static void findActiveAnsiStyle(textDisp *textD,
ssize_t pos, ansiStyle *style)
{
textBuffer *buf = textD->buffer;
ssize_t prev_esc;
size_t prev_esc_pos;
BufEscPos2Index(buf,
0,
0, pos, &prev_esc, &prev_esc_pos);
if(prev_esc <
0) {
return;
}
for(
ssize_t i=prev_esc;i>=
0;i--) {
if(parseEscapeSequence(buf, prev_esc_pos, style)) {
break;
}
prev_esc_pos -= buf->ansi_escpos[i];
}
}
static void ansiFgToColorIndex(textDisp *textD,
short fg, XftColor *color)
{
if(fg >=
30 && fg <=
37) {
*color = textD->colorProfile->ansiColors[fg-
30];
}
else if(fg >=
90 && fg <=
97) {
*color = textD->colorProfile->ansiColors[fg-
90];
}
}
static void ansiBgToColorIndex(textDisp *textD,
short bg, XftColor *color)
{
if(bg >=
40 && bg <=
47) {
*color = textD->colorProfile->ansiColors[bg-
40];
}
else if(bg >=
100 && bg <=
107) {
*color = textD->colorProfile->ansiColors[bg-
100];
}
}
static void getFontMinMax(NFont *font,
int *min,
int *max) {
XftFont *xftFont = FontDefault(font);
int fontMin = xftFont->max_advance_width;
int fontMax =
0;
for(
int i=
32;i<
127;i++) {
XGlyphInfo extents;
FcChar8 c = i;
XftTextExtents8(font->display, xftFont, &c,
1, &extents);
if(extents.xOff < fontMin) {
fontMin = extents.xOff;
}
if(extents.xOff > fontMax) {
fontMax = extents.xOff;
}
}
*min = fontMin;
*max = fontMax;
}
NFont *FontCreate(Display *dp, FcPattern *pattern)
{
if(!pattern) {
return NULL;
}
FcResult result;
pattern = FcPatternDuplicate(pattern);
FcPattern *match = XftFontMatch(dp, DefaultScreen(dp), pattern, &result);
double sz =
0;
result = FcPatternGetDouble (pattern,
FC_SIZE,
0, &sz);
if(result != FcResultMatch) {
FcPatternGetDouble (match,
FC_SIZE,
0, &sz);
}
XftFont *defaultFont = XftFontOpenPattern(dp, match);
if(!defaultFont) {
FcPatternDestroy(match);
return NULL;
}
NFont *font = NEditMalloc(
sizeof(NFont));
font->display = dp;
font->pattern = pattern;
font->fail =
NULL;
font->size = sz;
font->ref =
1;
NFontList *list = NEditMalloc(
sizeof(NFontList));
list->font = defaultFont;
list->next =
NULL;
font->fonts = list;
getFontMinMax(font, &font->minWidth, &font->maxWidth);
return font;
}
NFont *FontFromName(Display *dp,
const char *name)
{
FcPattern *pattern = FcNameParse((FcChar8*)name);
if(!pattern) {
return NULL;
}
NFont *font = FontCreate(dp, pattern);
FcPatternDestroy(pattern);
return font;
}
XftFont *FontListAddFontForChar(NFont *f, FcChar32 c)
{
FcCharSet *charset = FcCharSetCreate();
FcValue value;
value.type = FcTypeCharSet;
value.u.c = charset;
FcCharSetAddChar(charset, c);
if(!FcCharSetHasChar(charset, c)) {
FcCharSetDestroy(charset);
return f->fonts->font;
}
FcPattern *pattern = FcPatternDuplicate(f->pattern);
FcPatternAdd(pattern,
FC_CHARSET, value,
0);
FcResult result;
FcPattern *match = XftFontMatch (
f->display, DefaultScreen(f->display), pattern, &result);
if(!match) {
FcPatternDestroy(pattern);
FontAddFail(f, charset);
return f->fonts->font;
}
XftFont *newFont = XftFontOpenPattern(f->display, match);
if(!newFont || !FcCharSetHasChar(newFont->charset, c)) {
FcPatternDestroy(pattern);
FcPatternDestroy(match);
if(newFont) {
XftFontClose(f->display, newFont);
}
FontAddFail(f, charset);
return f->fonts->font;
}
FcCharSetDestroy(charset);
NFontList *newElm = NEditMalloc(
sizeof(NFontList));
newElm->font = newFont;
newElm->next =
NULL;
NFontList *elm = f->fonts;
NFontList *last =
NULL;
while(elm) {
last = elm;
elm = elm->next;
}
last->next = newElm;
return newFont;
}
XftFont *FindFont(NFont *f, FcChar32 c)
{
if(c <
128) {
return f->fonts->font;
}
NCharSetList *fail = f->fail;
while(fail) {
if(FcCharSetHasChar(fail->charset, c)) {
return f->fonts->font;
}
fail = fail->next;
}
NFontList *elm = f->fonts;
while(elm) {
if(FcCharSetHasChar(elm->font->charset, c)) {
return elm->font;
}
elm = elm->next;
}
return FontListAddFontForChar(f, c);
}
XftFont *FontDefault(NFont *f) {
return f->fonts->font;
}
void FontAddFail(NFont *f, FcCharSet *c)
{
NCharSetList *elm = f->fail;
NCharSetList *last = elm;
while(elm) {
last = elm;
elm = elm->next;
}
NCharSetList *newElm = NEditMalloc(
sizeof(NCharSetList));
newElm->charset = c;
newElm->next =
NULL;
if(last) {
last->next = newElm;
}
else {
f->fail = newElm;
}
}
void FontDestroy(NFont *f)
{
NCharSetList *c = f->fail;
NCharSetList *nc;
while(c) {
FcCharSetDestroy(c->charset);
nc = c->next;
NEditFree(c);
c = nc;
}
NFontList *l = f->fonts;
NFontList *nl;
while(l) {
XftFontClose(f->display, l->font);
nl = l->next;
NEditFree(l);
l = nl;
}
FcPatternDestroy(f->pattern);
NEditFree(f);
}
NFont *FontRef(NFont *font) {
font->ref++;
return font;
}
void FontUnref(NFont *font) {
if(--font->ref ==
0) {
FontDestroy(font);
}
}