Skip to content

Commit

Permalink
Bugfix CodeInput's sizing
Browse files Browse the repository at this point in the history
* Doesn't pass tests
* Breaks placeholder text (maintain two text structs)
* Disables syntax highlighting in ModuleView
  • Loading branch information
ArthaTi committed Oct 21, 2024
1 parent c18f27b commit cc656ed
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 34 deletions.
18 changes: 17 additions & 1 deletion source/fluid/code_input.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import fluid.input;
import fluid.utils;
import fluid.style;
import fluid.backend;
import fluid.typeface;
import fluid.text_input;


Expand Down Expand Up @@ -133,6 +134,12 @@ class CodeInput : TextInput {

}

override TextRuler rulerAt(size_t index) {

return contentLabel.text.rulerAt(index);

}

override bool multiline() const {

return true;
Expand All @@ -152,6 +159,14 @@ class CodeInput : TextInput {

}

protected override inout(Rope) value() inout {
return text;
}

protected override void replace(size_t start, size_t end, Rope value) {
text.replace(start, end, value);
}

override void resizeImpl(Vector2 available) {

assert(text.hasFastEdits);
Expand All @@ -160,11 +175,12 @@ class CodeInput : TextInput {

typeface.setSize(io.dpi, style.fontSize);

this.text.value = super.text.value;
text.indentWidth = indentWidth * typeface.advance(' ').x / io.hidpiScale.x;
text.resize(available);
minSize = text.size;

assert(this.text.isMeasured);

}

override void drawImpl(Rectangle outer, Rectangle inner) {
Expand Down
2 changes: 2 additions & 0 deletions source/fluid/label.d
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class Label : Node {
text.resize(available, !isWrapDisabled);
minSize = text.size;

assert(text.isMeasured);

}

protected override void drawImpl(Rectangle outer, Rectangle inner) {
Expand Down
2 changes: 1 addition & 1 deletion source/fluid/module_view.d
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ private bindbc.SharedLib runSharedLibrary(string path) @system {
CodeInput dlangInput(void delegate() @safe submitted = null) @trusted {

auto language = treeSitterLanguage!"d";
auto highlighter = new TreeSitterHighlighter(language, dlangQuery);
auto highlighter = null;//new TreeSitterHighlighter(language, dlangQuery);

return codeInput(
.layout!(1, "fill"),
Expand Down
26 changes: 23 additions & 3 deletions source/fluid/text.d
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,9 @@ struct StyledText(StyleRange = TextStyleSlice[]) {
}

/// Clear the cache.
private void clearCache(Typeface typeface, float lineWidth) {
private void clearCache(Typeface typeface, float lineWidth)
in (typeface)
do {

auto ruler = TextRuler(typeface, lineWidth);
ruler.startLine();
Expand Down Expand Up @@ -422,7 +424,9 @@ struct StyledText(StyleRange = TextStyleSlice[]) {
/// splitter = Function to use to split words.
/// space = Limit for the space of the region the text shouldn't cross, in dots.
/// wrap = If true, text should be limited by a bounding box.
private void measure(alias splitter = Typeface.defaultWordChunks)(Vector2 space, bool wrap) {
private void measure(alias splitter = Typeface.defaultWordChunks)(Vector2 space, bool wrap)
out (; isMeasured)
do {

auto style = node.pickStyle;
auto typeface = style.getTypeface;
Expand Down Expand Up @@ -530,6 +534,15 @@ struct StyledText(StyleRange = TextStyleSlice[]) {
// the bounding box
ruler = requireRulerAt(value.length);
_sizeDots = ruler.textSize;
_updateRangeStart = 0;
_updateRangeEnd = 0;

}

bool isMeasured() const {

return _cache !is _cache.init
&& _updateRangeStart == _updateRangeEnd;

}

Expand All @@ -539,12 +552,17 @@ struct StyledText(StyleRange = TextStyleSlice[]) {
/// `requireRulerAt` will do the same, but it will also cache the result value for faster subsequent lookup. The
/// regular `rulerAt` overload is recommended for most cases.
///
/// For this function to work, measurement data must be available; make sure `resize` was called beforehand. This
/// will be checked at runtime.
///
/// Returns:
/// Text ruler with text measurement data from the start of the text to the given character, not including
/// queried character.
/// Params:
/// index = Index of the requested character.
CachedTextRuler rulerAt(size_t index) {
CachedTextRuler rulerAt(size_t index)
in (_cache !is _cache.init, "Text was not measured. Call `resize()` first.")
do {

// BUG This may end up in the middle of a word and break
// TODO Custom text breaking
Expand All @@ -554,6 +572,8 @@ struct StyledText(StyleRange = TextStyleSlice[]) {
auto ruler = query(&_cache, index).front;
bool started;

assert(ruler.typeface !is null);

const start = ruler.point.length;
const end = index;

Expand Down
79 changes: 51 additions & 28 deletions source/fluid/text_input.d
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,6 @@ class TextInput : InputNode!Node, FluidScrollable {
invariant(_bufferNode is null || _bufferNode.left.value.sameTail(_buffer[0 .. _usedBufferSize]),
"_bufferNode must be in sync with _buffer");

/// Value of the text input.
Rope _value;

/// Available horizontal space.
float _availableWidth = float.nan;

Expand Down Expand Up @@ -282,15 +279,19 @@ class TextInput : InputNode!Node, FluidScrollable {
static class ContentLabel : Label {

this() {

super("");
}

protected inout(Rope) value() inout {
return text;
}

override bool hoveredImpl(Rectangle, Vector2) const {
protected void replace(size_t start, size_t end, Rope value) {
text.replace(start, end, value);
}

override bool hoveredImpl(Rectangle, Vector2) const {
return false;

}

override void drawImpl(Rectangle outer, Rectangle inner) {
Expand Down Expand Up @@ -363,7 +364,7 @@ class TextInput : InputNode!Node, FluidScrollable {
/// Returns: The value used by this input.
inout(Rope) value() inout {

return _value;
return contentLabel.value;

}

Expand Down Expand Up @@ -402,7 +403,9 @@ class TextInput : InputNode!Node, FluidScrollable {
/// start = Low index, inclusive; First index to delete.
/// end = High index, exclusive; First index after the newly inserted fragment.
/// newValue = Value to insert.
void replace(size_t start, size_t end, Rope newValue) {
void replace(size_t start, size_t end, Rope newValue)
in (start <= end, "Start must be lower than end")
do {

auto withoutLineFeeds = Typeface.lineSplitter(newValue).joiner;

Expand All @@ -413,9 +416,9 @@ class TextInput : InputNode!Node, FluidScrollable {

}

const oldValue = _value[start..end];
const oldValue = contentLabel.value[start..end];

_value = _value.replace(start, end, newValue);
contentLabel.replace(start, end, newValue);

// Caret index is affected
if (caretIndex > start) {
Expand Down Expand Up @@ -790,6 +793,7 @@ class TextInput : InputNode!Node, FluidScrollable {
minSize = size;

// Set the label text
version (none) // TODO TODO TODO
contentLabel.text = value == "" ? placeholder : value;

const isFill = layout.nodeAlign[0] == NodeAlign.fill;
Expand Down Expand Up @@ -1071,30 +1075,49 @@ class TextInput : InputNode!Node, FluidScrollable {

}

// Check if the caret follows unbreakable characters
const head = unbreakableChars(
valueBeforeCaret.wordBack(true)
);
// TODO move this logic to Text
version (none) {

// If the caret is surrounded by unbreakable characters, include them in the output to make sure the
// word is wrapped correctly
const tail = preferNextLine || !head.empty
? unbreakableChars(valueAfterCaret)
: Rope.init;
// Check if the caret follows unbreakable characters
const head = unbreakableChars(
valueBeforeCaret.wordBack(true)
);

auto typeface = style.getTypeface;
auto ruler = textRuler();
auto slice = value[0 .. caretIndex + tail.length];
// If the caret is surrounded by unbreakable characters, include them in the output to make sure the
// word is wrapped correctly
const tail = preferNextLine || !head.empty
? unbreakableChars(valueAfterCaret)
: Rope.init;

auto typeface = style.getTypeface;
auto ruler = textRuler();
auto slice = value[0 .. caretIndex + tail.length];

// Measure text until the caret; include the word that follows to keep proper wrapping
typeface.measure(ruler, slice, multiline);

// Measure text until the caret; include the word that follows to keep proper wrapping
typeface.measure(ruler, slice, multiline);
auto caretPosition = ruler.caret.start;

auto caretPosition = ruler.caret.start;
// Measure the word itself, and remove it
caretPosition.x -= typeface.measure(tail[]).x;

// Measure the word itself, and remove it
caretPosition.x -= typeface.measure(tail[]).x;
return caretPosition;

}
else {
auto ruler = rulerAt(caretIndex);
return ruler.caret.start;
}

}

/// Returns: A text ruler measuring text between the start and a chosen character.
/// See_Also: `Text.rulerAt`
/// Params:
/// index = Index of the requested character.
TextRuler rulerAt(size_t index) {

return caretPosition;
return contentLabel.text.rulerAt(index);

}

Expand Down
2 changes: 1 addition & 1 deletion source/fluid/typeface.d
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ interface Typeface {
}

// Split each word
else foreach (word; chunkWords(text)) {
else foreach (word; range) {

const penPosition = ruler.addWord(word);
if (const ret = yield(word, penPosition)) return ret;
Expand Down

0 comments on commit cc656ed

Please sign in to comment.