aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMitchell Foral <unknown>2021-10-22 15:58:17 +1100
committerMitchell Foral <unknown>2021-10-22 15:58:17 +1100
commit1c2f3fb6ce528add154abce1791d56ce7a94271c (patch)
tree113769c983cb307b9ba44873b0f9d4fdcaff76ab
parent67759806434b36d47d5f08810854a661f2e992d1 (diff)
downloadscintilla-mirror-1c2f3fb6ce528add154abce1791d56ce7a94271c.tar.gz
Add CARETSTYLE_CURSES to draw more than 1 caret on curses terminal.
-rw-r--r--doc/ScintillaDoc.html11
-rw-r--r--doc/ScintillaHistory.html3
-rw-r--r--include/Scintilla.h1
-rw-r--r--include/Scintilla.iface1
-rw-r--r--include/ScintillaTypes.h1
-rw-r--r--src/EditView.cxx30
-rw-r--r--src/Editor.cxx2
-rw-r--r--src/PositionCache.cxx15
-rw-r--r--src/ViewStyle.cxx18
-rw-r--r--src/ViewStyle.h4
10 files changed, 71 insertions, 15 deletions
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html
index ecd1068eb..77412022a 100644
--- a/doc/ScintillaDoc.html
+++ b/doc/ScintillaDoc.html
@@ -3797,8 +3797,8 @@ struct Sci_TextToFind {
<p><b id="SCI_SETCARETSTYLE">SCI_SETCARETSTYLE(int caretStyle)</b><br />
<b id="SCI_GETCARETSTYLE">SCI_GETCARETSTYLE &rarr; int</b><br />
The style of the caret can be set with <code>SCI_SETCARETSTYLE</code>.
- There are separate styles for insert mode (lower 4-bits, <code>CARETSTYLE_INS_MASK</code>) and
- overtype mode (bit 4).
+ There are separate styles for insert mode (lower 4-bits, <code>CARETSTYLE_INS_MASK</code>),
+ overtype mode (bit 4), and curses mode (bit 5).
<table class="standard" summary="Caret Styles">
<tbody valign="top">
@@ -3828,6 +3828,13 @@ struct Sci_TextToFind {
<td>Draws an overstrike caret as a block. This should be ored with one of the first three styles.</td>
</tr>
<tr>
+ <th align="left"><code>CARETSTYLE_CURSES</code></th>
+ <td>32</td>
+ <td>Draws carets that cannot be drawn in a curses (terminal) environment (such as additional carets),
+ and draws them as blocks. The main caret is left to be drawn by the terminal itself. This setting is
+ typically a standalone setting.</td>
+ </tr>
+ <tr>
<th align="left"><code>CARETSTYLE_BLOCK_AFTER</code></th>
<td>256</td>
<td>When the caret end of a range is at the end and a block caret style is chosen, draws the block
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 09afbe849..b4b7c6a56 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -578,6 +578,9 @@
Add DEL to standard set of space characters for word operations.
</li>
<li>
+ Add CARETSTYLE_CURSES to draw more than 1 caret on curses terminal.
+ </li>
+ <li>
On GTK, fix potential crash when closing Scintilla instances due to releasing global settings object.
</li>
<li>
diff --git a/include/Scintilla.h b/include/Scintilla.h
index a10c9ed82..b46e886b6 100644
--- a/include/Scintilla.h
+++ b/include/Scintilla.h
@@ -907,6 +907,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define CARETSTYLE_BLOCK 2
#define CARETSTYLE_OVERSTRIKE_BAR 0
#define CARETSTYLE_OVERSTRIKE_BLOCK 0x10
+#define CARETSTYLE_CURSES 0x20
#define CARETSTYLE_INS_MASK 0xF
#define CARETSTYLE_BLOCK_AFTER 0x100
#define SCI_SETCARETSTYLE 2512
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
index 7ce5e2408..f2ef2d33e 100644
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -2489,6 +2489,7 @@ val CARETSTYLE_LINE=1
val CARETSTYLE_BLOCK=2
val CARETSTYLE_OVERSTRIKE_BAR=0
val CARETSTYLE_OVERSTRIKE_BLOCK=0x10
+val CARETSTYLE_CURSES=0x20
val CARETSTYLE_INS_MASK=0xF
val CARETSTYLE_BLOCK_AFTER=0x100
diff --git a/include/ScintillaTypes.h b/include/ScintillaTypes.h
index 910cd5ec8..917878474 100644
--- a/include/ScintillaTypes.h
+++ b/include/ScintillaTypes.h
@@ -439,6 +439,7 @@ enum class CaretStyle {
Block = 2,
OverstrikeBar = 0,
OverstrikeBlock = 0x10,
+ Curses = 0x20,
InsMask = 0xF,
BlockAfter = 0x100,
};
diff --git a/src/EditView.cxx b/src/EditView.cxx
index 762aa8187..30db6fb0d 100644
--- a/src/EditView.cxx
+++ b/src/EditView.cxx
@@ -1639,7 +1639,7 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt
}
const bool caretBlinkState = (model.caret.active && model.caret.on) || (!additionalCaretsBlink && !mainCaret);
const bool caretVisibleState = additionalCaretsVisible || mainCaret;
- if ((xposCaret >= 0) && vsDraw.IsCaretVisible() &&
+ if ((xposCaret >= 0) && vsDraw.IsCaretVisible(mainCaret) &&
(drawDrag || (caretBlinkState && caretVisibleState))) {
bool canDrawBlockCaret = true;
bool drawBlockCaret = false;
@@ -1663,7 +1663,8 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt
if (xposCaret > 0)
caretWidthOffset = 0.51f; // Move back so overlaps both character cells.
xposCaret += xStart;
- const ViewStyle::CaretShape caretShape = drawDrag ? ViewStyle::CaretShape::line : vsDraw.CaretShapeForMode(model.inOverstrike);
+ const ViewStyle::CaretShape caretShape = drawDrag ? ViewStyle::CaretShape::line :
+ vsDraw.CaretShapeForMode(model.inOverstrike, mainCaret);
if (drawDrag) {
/* Dragging text, use a line caret */
rcCaret.left = std::round(xposCaret - caretWidthOffset);
@@ -1736,6 +1737,21 @@ static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, c
}
}
+// On the curses platform, the terminal is drawing its own caret, so if the caret is within
+// the main selection, do not draw the selection at that position.
+// Use iDoc from DrawBackground and DrawForeground here because TextSegment has been adjusted
+// such that, if the caret is inside the main selection, the beginning or end of that selection
+// is at the end of a text segment.
+// This function should only be called if iDoc is within the main selection.
+static InSelection CharacterInCursesSelection(Sci::Position iDoc, const EditModel &model, const ViewStyle &vsDraw) {
+ const SelectionPosition &posCaret = model.sel.RangeMain().caret;
+ const bool caretAtStart = posCaret < model.sel.RangeMain().anchor && posCaret.Position() == iDoc;
+ const bool caretAtEnd = posCaret > model.sel.RangeMain().anchor &&
+ vsDraw.DrawCaretInsideSelection(false, false) &&
+ model.pdoc->MovePositionOutsideChar(posCaret.Position() - 1, -1) == iDoc;
+ return (caretAtStart || caretAtEnd) ? InSelection::inNone : InSelection::inMain;
+}
+
void EditView::DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart,
int subLine, std::optional<ColourRGBA> background) const {
@@ -1746,7 +1762,7 @@ void EditView::DrawBackground(Surface *surface, const EditModel &model, const Vi
// Does not take margin into account but not significant
const XYPOSITION xStartVisible = static_cast<XYPOSITION>(subLineStart-xStart);
- BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, selBackDrawn, model.pdoc, &model.reprs, nullptr);
+ BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, selBackDrawn, model.pdoc, &model.reprs, &vsDraw);
const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background;
@@ -1769,7 +1785,9 @@ void EditView::DrawBackground(Surface *surface, const EditModel &model, const Vi
if (rcSegment.right > rcLine.right)
rcSegment.right = rcLine.right;
- const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc);
+ InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc);
+ if (FlagSet(vsDraw.caret.style, CaretStyle::Curses) && (inSelection == InSelection::inMain))
+ inSelection = CharacterInCursesSelection(iDoc, model, vsDraw);
const bool inHotspot = model.hotspot.Valid() && model.hotspot.ContainsCharacter(iDoc);
ColourRGBA textBack = TextBackground(model, vsDraw, ll, background, inSelection,
inHotspot, ll->styles[i], i);
@@ -2013,7 +2031,9 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
}
}
}
- const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc);
+ InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc);
+ if (FlagSet(vsDraw.caret.style, CaretStyle::Curses) && (inSelection == InSelection::inMain))
+ inSelection = CharacterInCursesSelection(iDoc, model, vsDraw);
const std::optional<ColourRGBA> selectionFore = SelectionForeground(model, vsDraw, inSelection);
if (selectionFore) {
textFore = *selectionFore;
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 485eaef87..ce5a70ce5 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -7592,7 +7592,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
return vs.ElementColour(Element::Caret)->OpaqueRGB();
case Message::SetCaretStyle:
- if (static_cast<CaretStyle>(wParam) <= (CaretStyle::Block | CaretStyle::OverstrikeBlock | CaretStyle::BlockAfter))
+ if (static_cast<CaretStyle>(wParam) <= (CaretStyle::Block | CaretStyle::OverstrikeBlock | CaretStyle::Curses | CaretStyle::BlockAfter))
vs.caret.style = static_cast<CaretStyle>(wParam);
else
/* Default to the line caret */
diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx
index 13e4ab2b2..587ffdd3b 100644
--- a/src/PositionCache.cxx
+++ b/src/PositionCache.cxx
@@ -696,6 +696,21 @@ BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lin
Insert(portion.end.Position() - posLineStart);
}
}
+ // On the curses platform, the terminal is drawing its own caret, so add breaks around the
+ // caret in the main selection in order to help prevent the selection from being drawn in
+ // the caret's cell.
+ if (pvsDraw && FlagSet(pvsDraw->caret.style, CaretStyle::Curses) && !psel->RangeMain().Empty()) {
+ const Sci::Position caretPos = psel->RangeMain().caret.Position();
+ const Sci::Position anchorPos = psel->RangeMain().anchor.Position();
+ if (caretPos < anchorPos) {
+ const Sci::Position nextPos = pdoc->MovePositionOutsideChar(caretPos + 1, 1);
+ Insert(nextPos - posLineStart);
+ } else if (caretPos > anchorPos && pvsDraw->DrawCaretInsideSelection(false, false)) {
+ const Sci::Position prevPos = pdoc->MovePositionOutsideChar(caretPos - 1, -1);
+ if (prevPos > anchorPos)
+ Insert(prevPos - posLineStart);
+ }
+ }
}
if (pvsDraw && pvsDraw->indicatorsSetFore) {
for (const IDecoration *deco : pdoc->decorations->View()) {
diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx
index 5273841ed..1458ea96f 100644
--- a/src/ViewStyle.cxx
+++ b/src/ViewStyle.cxx
@@ -661,11 +661,14 @@ bool ViewStyle::SetWrapIndentMode(WrapIndentMode wrapIndentMode_) noexcept {
bool ViewStyle::IsBlockCaretStyle() const noexcept {
return ((caret.style & CaretStyle::InsMask) == CaretStyle::Block) ||
- FlagSet(caret.style, CaretStyle::OverstrikeBlock);
+ FlagSet(caret.style, CaretStyle::OverstrikeBlock) ||
+ FlagSet(caret.style, CaretStyle::Curses);
}
-bool ViewStyle::IsCaretVisible() const noexcept {
- return caret.width > 0 && caret.style != CaretStyle::Invisible;
+bool ViewStyle::IsCaretVisible(bool isMainSelection) const noexcept {
+ return caret.width > 0 &&
+ ((caret.style & CaretStyle::InsMask) != CaretStyle::Invisible ||
+ (FlagSet(caret.style, CaretStyle::Curses) && !isMainSelection)); // only draw additional selections in curses mode
}
bool ViewStyle::DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept {
@@ -673,14 +676,19 @@ bool ViewStyle::DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOv
return false;
return ((caret.style & CaretStyle::InsMask) == CaretStyle::Block) ||
(inOverstrike && FlagSet(caret.style, CaretStyle::OverstrikeBlock)) ||
- imeCaretBlockOverride;
+ imeCaretBlockOverride ||
+ FlagSet(caret.style, CaretStyle::Curses);
}
-ViewStyle::CaretShape ViewStyle::CaretShapeForMode(bool inOverstrike) const noexcept {
+ViewStyle::CaretShape ViewStyle::CaretShapeForMode(bool inOverstrike, bool isMainSelection) const noexcept {
if (inOverstrike) {
return (FlagSet(caret.style, CaretStyle::OverstrikeBlock)) ? CaretShape::block : CaretShape::bar;
}
+ if (FlagSet(caret.style, CaretStyle::Curses) && !isMainSelection) {
+ return CaretShape::block;
+ }
+
const CaretStyle caretStyle = caret.style & CaretStyle::InsMask;
return (caretStyle <= CaretStyle::Block) ? static_cast<CaretShape>(caretStyle) : CaretShape::line;
}
diff --git a/src/ViewStyle.h b/src/ViewStyle.h
index de56c0895..f799c4943 100644
--- a/src/ViewStyle.h
+++ b/src/ViewStyle.h
@@ -235,9 +235,9 @@ public:
enum class CaretShape { invisible, line, block, bar };
bool IsBlockCaretStyle() const noexcept;
- bool IsCaretVisible() const noexcept;
+ bool IsCaretVisible(bool isMainSelection) const noexcept;
bool DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept;
- CaretShape CaretShapeForMode(bool inOverstrike) const noexcept;
+ CaretShape CaretShapeForMode(bool inOverstrike, bool isMainSelection) const noexcept;
private:
void AllocStyles(size_t sizeNew);