📄 textdisp.c
字号:
charLen = BufExpandCharacter(lineStr[charIndex], outIndex, expandedChar, textD->buffer->tabDist, textD->buffer->nullSubsChar); charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex, lineStr[charIndex]); xStep += stringWidth(textD, expandedChar, charLen, charStyle); outIndex += charLen; } *x = xStep; XtFree(lineStr); return True;}/*** If the text widget is maintaining a line number count appropriate to "pos"** return the line and column numbers of pos, otherwise return False. If** continuous wrap mode is on, returns the absolute line number (as opposed to** the wrapped line number which is used for scrolling). THIS ROUTINE ONLY** WORKS FOR DISPLAYED LINES AND, IN CONTINUOUS WRAP MODE, ONLY WHEN THE** ABSOLUTE LINE NUMBER IS BEING MAINTAINED. Otherwise, it returns False.*/int TextDPosToLineAndCol(textDisp *textD, int pos, int *lineNum, int *column){ textBuffer *buf = textD->buffer; /* In continuous wrap mode, the absolute (non-wrapped) line count is maintained separately, as needed. Only return it if we're actually keeping track of it and pos is in the displayed text */ 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; } /* Only return the data if pos is within the displayed text */ if (!posToVisibleLineNum(textD, pos, lineNum)) return False; *column = BufCountDispChars(buf, textD->lineStarts[*lineNum], pos); *lineNum += textD->topLineNum; return True;}/*** Return True if position (x, y) is inside of the primary selection*/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);}/*** Correct a column number based on an unconstrained position (as returned by** TextDXYToUnconstrainedPosition) to be relative to the last actual newline** in the buffer before the row and column position given, rather than the** last line start created by line wrapping. This is an adapter** for rectangular selections and code written before continuous wrap mode,** which thinks that the unconstrained column is the number of characters** from the last newline. Obviously this is time consuming, because it** invloves character re-counting.*/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);}/*** Correct a row number from an unconstrained position (as returned by** TextDXYToUnconstrainedPosition) to a straight number of newlines from the** top line of the display. Because rectangular selections are based on** newlines, rather than display wrapping, and anywhere a rectangular selection** needs a row, it needs it in terms of un-wrapped lines.*/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]);}/*** Scroll the display to bring insertion cursor into view.**** Note: it would be nice to be able to do this without counting lines twice** (setScroll counts them too) and/or to count from the most efficient** starting point, but the efficiency of this routine is not as important to** the overall performance of the text display.*/void TextDMakeInsertPosVisible(textDisp *textD){ int hOffset, topLine, x, y; int cursorPos = textD->cursorPos; int linesFromTop = 0, do_padding = 1; int cursorVPadding = (int)TEXT_OF_TEXTD(textD).cursorVPadding; hOffset = textD->horizOffset; topLine = textD->topLineNum; /* Don't do padding if this is a mouse operation */ do_padding = ((TEXT_OF_TEXTD(textD).dragState == NOT_CLICKED) && (cursorVPadding > 0)); /* Find the new top line number */ if (cursorPos < textD->firstChar) { topLine -= TextDCountLines(textD, cursorPos, textD->firstChar, False); /* linesFromTop = 0; */ } 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 { /* Avoid extra counting if cursorVPadding is disabled */ if (do_padding) linesFromTop = TextDCountLines(textD, textD->firstChar, cursorPos, True); } if (topLine < 1) { fprintf(stderr, "internal consistency check tl1 failed\n"); topLine = 1; } if (do_padding) { /* Keep the cursor away from the top or bottom of screen. */ 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)); } } /* Find the new setting for horizontal offset (this is a bit ungraceful). If the line is visible, just use TextDPositionToXY to get the position to scroll to, otherwise, do the vertical scrolling first, then the horizontal */ if (!TextDPositionToXY(textD, cursorPos, &x, &y)) { setScroll(textD, topLine, hOffset, True, True); if (!TextDPositionToXY(textD, cursorPos, &x, &y)) return; /* Give up, it's not worth it (but why does it fail?) */ } if (x > textD->left + textD->width) hOffset += x - (textD->left + textD->width); else if (x < textD->left) hOffset += x - textD->left; /* Do the scroll */ setScroll(textD, topLine, hOffset, True, True);}/*** Return the current preferred column along with the current** visible line index (-1 if not visible) and the lineStartPos** of the current insert position.*/int TextDPreferredColumn(textDisp *textD, int *visLineNum, int *lineStartPos){ int column; /* Find the position of the start of the line. Use the line starts array if possible, to avoid unbounded line-counting in continuous wrap mode */ if (posToVisibleLineNum(textD, textD->cursorPos, visLineNum)) { *lineStartPos = textD->lineStarts[*visLineNum]; } else { *lineStartPos = TextDStartOfLine(textD, textD->cursorPos); *visLineNum = -1; } /* Decide what column to move to, if there's a preferred column use that */ column = textD->cursorPreferredCol >= 0 ? textD->cursorPreferredCol : BufCountDispChars(textD->buffer, *lineStartPos, textD->cursorPos); return(column);}/*** Return the insert position of the requested column given** the lineStartPos.*/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);}/*** Cursor movement functions*/int TextDMoveRight(textDisp *textD){ if (textD->cursorPos >= textD->buffer->length) return False; TextDSetInsertPosition(textD, textD->cursorPos + 1); return True;}int TextDMoveLeft(textDisp *textD){ if (textD->cursorPos <= 0) return False; TextDSetInsertPosition(textD, textD->cursorPos - 1); return True;}int TextDMoveUp(textDisp *textD, int absolute){ int lineStartPos, column, prevLineStartPos, newPos, visLineNum; /* Find the position of the start of the line. Use the line starts array if possible, to avoid unbounded line-counting in continuous wrap mode */ if (absolute) { lineStartPos = BufStartOfLine(textD->buffer, textD->cursorPos); visLineNum = -1; } else if (posToVisibleLineNum(textD, textD->cursorPos, &visLineNum)) lineStartPos = textD->lineStarts[visLineNum]; else { lineStartPos = TextDStartOfLine(textD, textD->cursorPos); visLineNum = -1; } if (lineStartPos == 0) return False; /* Decide what column to move to, if there's a preferred column use that */ column = textD->cursorPreferredCol >= 0 ? textD->cursorPreferredCol : BufCountDispChars(textD->buffer, lineStartPos, textD->cursorPos); /* count forward from the start of the previous line to reach the column */ 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)); /* move the cursor */ TextDSetInsertPosition(textD, newPos); /* if a preferred column wasn't aleady established, establish it */ textD->cursorPreferredCol = column; return True;}int TextDMoveDown(textDisp *textD, int absolute){ int lineStartPos, column, nextLineStartPos, newPos, visLineNum; if (textD->cursorPos == textD->buffer->length) return False; if (absolute) { lineStartPos = BufStartOfLine(textD->buffer, textD->cursorPos); visLineNum = -1; } else if (posToVisibleLineNum(textD, textD->cursorPos, &visLineNum)) lineStartPos = textD->lineStarts[visLineNum]; else { lineStartPos = TextDStartOfLine(textD, textD->cursorPos); visLineNum = -1; } column = textD->cursorPreferredCol >= 0 ? textD->cursorPreferredCol : BufCountDispChars(textD->buffer, lineStartPos, textD->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->cursorPreferredCol = column; return True;}/*** Same as BufCountLines, but takes in to account wrapping if wrapping is** turned on. If the caller knows that startPos is at a line start, it** can pass "startPosIsLineStart" as True to make the call more efficient** by avoiding the additional step of scanning back to the last newline.*/int TextDCountLines(textDisp *textD, int startPos, int endPos, int startPosIsLineStart){ int retLines, retPos, retLineStart, retLineEnd; /* If we're not wrapping use simple (and more efficient) BufCountLines */ if (!textD->continuousWrap) return BufCountLines(textD->buffer, startPos, endPos); wrappedLineCounter(textD, textD->buffer, startPos, endPos, INT_MAX, startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, &retLineEnd); return retLines;}/*** Same as BufCountForwardNLines, but takes in to account line breaks when** wrapping is turned on. If the caller knows that startPos is at a line start,** it can pass "startPosIsLineStart" as True to make the call more efficient** by avoiding the additional step of scanning back to the last newline.*/int TextDCountForwardNLines(textDisp *textD, int startPos, int nLines, int startPosIsLineStart){ int retLines, retPos, retLineStart, retLineEnd; /* if we're not wrapping use more efficient BufCountForwardNLines */ if (!textD->continuousWrap) return BufCountForwardNLines(textD->buffer, startPos, nLines); /* wrappedLineCounter can't handle the 0 lines case */ if (nLines == 0) return startPos;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -