• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CyclopsMC / IntegratedDynamics / 39481534387

20 Oct 2026 07:12PM UTC coverage: 48.406% (-0.3%) from 48.683%
39481534387

Pull #1766

github

claude
Keep typed expressions as typed, also on the card

Typing (x: integer) => x.add(3) showed x + 3 once the text lost focus,
as the text was printed again from the tree. Typed text is now kept:
in the editor, through undo and redo, and on the written card, which
stores it next to the tree. It is only shown while it still reads as
the same tree, and otherwise the tree is printed as before, such as
after a label it uses changed. A slot or parameter edit that changes
the tree prints it from then on. Text in the usual form is not stored,
and plain operators are still written as classic cards, without text.

ExpressionParser.tokenize records where each node was read, so typed
text maps each character to its node, as printed text does, for its
colors, highlights and opening the node under the cursor.

A Format button between Redo and Copy writes the expression in its
usual form, applying typed text first if it parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y
Pull Request #1766: Expression cards in the Logic Programmer, editable as text

4875 of 12816 branches covered (38.04%)

Branch coverage included in aggregate %.

15819 of 29935 relevant lines covered (52.84%)

2.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.27
/src/main/java/org/cyclops/integrateddynamics/core/evaluate/variable/ValueObjectTypeItemStack.java
1
package org.cyclops.integrateddynamics.core.evaluate.variable;
2

3
import lombok.ToString;
4
import net.minecraft.advancements.critereon.ItemPredicate;
5
import net.minecraft.core.registries.BuiltInRegistries;
6
import net.minecraft.nbt.CompoundTag;
7
import net.minecraft.nbt.Tag;
8
import net.minecraft.network.chat.Component;
9
import net.minecraft.network.chat.MutableComponent;
10
import net.minecraft.world.item.ItemStack;
11
import org.cyclops.commoncapabilities.api.capability.itemhandler.ItemMatch;
12
import org.cyclops.cyclopscore.helper.ItemStackHelpers;
13
import org.cyclops.integrateddynamics.api.advancement.criterion.ValuePredicate;
14
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
15
import org.cyclops.integrateddynamics.api.evaluate.variable.*;
16
import org.cyclops.integrateddynamics.core.logicprogrammer.ValueTypeItemStackLPElement;
17
import org.cyclops.integrateddynamics.core.logicprogrammer.ValueTypeLPElementBase;
18

19
import java.util.Objects;
20
import java.util.Optional;
21

22
/**
23
 * Value type with values that are itemstacks.
24
 * @author rubensworks
25
 */
26
public class ValueObjectTypeItemStack extends ValueObjectTypeBase<ValueObjectTypeItemStack.ValueItemStack> implements
27
        IValueTypeNamed<ValueObjectTypeItemStack.ValueItemStack>,
28
        IValueTypeUniquelyNamed<ValueObjectTypeItemStack.ValueItemStack>,
29
        IValueTypeNullable<ValueObjectTypeItemStack.ValueItemStack> {
30

31
    public ValueObjectTypeItemStack() {
32
        // TODO: in next major, prefix the global interact names of operators on items with item instead of itemstack,
33
        //  as expressions call this type item. This keeps the saved unique name, but changes names that scripts use.
34
        super("itemstack", ValueObjectTypeItemStack.ValueItemStack.class);
4 ✔
35
    }
1 ✔
36

37
    public static MutableComponent getItemStackDisplayNameUsSafe(ItemStack itemStack) throws NoSuchMethodException {
38
        return !itemStack.isEmpty()
×
39
                ? (itemStack.getHoverName().copy().append((itemStack.getCount() > 1 ? " (" + itemStack.getCount() + ")" : "")))
×
40
                : Component.literal("");
×
41
    }
42

43
    public static MutableComponent getItemStackDisplayNameSafe(ItemStack itemStack) {
44
        // Certain mods may call client-side only methods,
45
        // so call a server-side-safe fallback method if that fails.
46
        try {
47
            return getItemStackDisplayNameUsSafe(itemStack);
×
48
        } catch (NoSuchMethodException e) {
×
49
            return Component.translatable(itemStack.getDescriptionId());
×
50
        }
51
    }
52

53
    @Override
54
    public ValueItemStack getDefault() {
55
        return ValueItemStack.of(ItemStack.EMPTY);
×
56
    }
57

58
    @Override
59
    public MutableComponent toCompactString(ValueItemStack value) {
60
        return ValueObjectTypeItemStack.getItemStackDisplayNameSafe(value.getRawValue());
×
61
    }
62

63
    @Override
64
    public Tag serialize(ValueDeseralizationContext valueDeseralizationContext, ValueItemStack value) {
65
        CompoundTag tag = new CompoundTag();
4 ✔
66
        ItemStack itemStack = value.getRawValue();
3 ✔
67
        if(!itemStack.isEmpty()) {
3 ✔
68
            tag.putInt("count", itemStack.getCount());
5 ✔
69
            int count = itemStack.getCount();
3 ✔
70
            if (itemStack.getCount() > 99) {
4 ✔
71
                tag.putInt("ExtendedCount", count);
4 ✔
72
                itemStack = itemStack.copy();
3 ✔
73
                itemStack.setCount(99);
3 ✔
74
            }
75
            return itemStack.save(valueDeseralizationContext.holderLookupProvider(), tag);
6 ✔
76
        }
77
        return tag;
2 ✔
78
    }
79

80
    @Override
81
    public ValueItemStack deserialize(ValueDeseralizationContext valueDeseralizationContext, Tag value) {
82
        if (value instanceof CompoundTag tag && !tag.isEmpty()) {
9 !
83
            // Forge returns air for tags with negative count,
84
            // so we set it to 1 for deserialization and fix it afterwards.
85
            int realCount = tag.getInt("count");
4 ✔
86
            // Consider the tag immutable, to avoid changes elsewhere
87
            tag = tag.copy();
3 ✔
88
            tag.putInt("count", 1);
4 ✔
89
            ItemStack itemStack = ItemStack.parseOptional(valueDeseralizationContext.holderLookupProvider(), tag);
5 ✔
90
            if (!itemStack.isEmpty()) {
3 ✔
91
                itemStack.setCount(realCount);
3 ✔
92
            }
93
            if (tag.contains("ExtendedCount", Tag.TAG_INT)) {
5 ✔
94
                itemStack.setCount(tag.getInt("ExtendedCount"));
5 ✔
95
            }
96
            return ValueItemStack.of(itemStack);
3 ✔
97
        } else {
98
            return ValueItemStack.of(ItemStack.EMPTY);
3 ✔
99
        }
100
    }
101

102
    @Override
103
    public String getName(ValueItemStack a) {
104
        return toCompactString(a).getString();
×
105
    }
106

107
    @Override
108
    public boolean isNull(ValueItemStack a) {
109
        return a.getRawValue().isEmpty();
×
110
    }
111

112
    @Override
113
    public ValueTypeLPElementBase createLogicProgrammerElement() {
114
        return new ValueTypeItemStackLPElement<>(this, new ValueTypeItemStackLPElement.IItemStackToValue<ValueObjectTypeItemStack.ValueItemStack>() {
12 ✔
115
            @Override
116
            public boolean isNullable() {
117
                return true;
×
118
            }
119

120
            @Override
121
            public Component validate(ItemStack itemStack) {
122
                return null;
×
123
            }
124

125
            @Override
126
            public ValueObjectTypeItemStack.ValueItemStack getValue(ItemStack itemStack) {
127
                return ValueObjectTypeItemStack.ValueItemStack.of(itemStack);
×
128
            }
129

130
            @Override
131
            public ItemStack getValueAsItemStack(ValueItemStack value) {
132
                return value.getRawValue();
×
133
            }
134
        });
135
    }
136

137
    @Override
138
    public ValueItemStack materialize(ValueItemStack value) throws EvaluationException {
139
        return ValueItemStack.of(value.getRawValue().copy());
5 ✔
140
    }
141

142
    @Override
143
    public String getUniqueName(ValueItemStack value) {
144
        ItemStack itemStack = value.getRawValue();
×
145
        return !itemStack.isEmpty() ? BuiltInRegistries.ITEM.getKey(itemStack.getItem()).toString() : "";
×
146
    }
147

148
    @ToString
5 ✔
149
    public static class ValueItemStack extends ValueBase {
150

151
        private final ItemStack itemStack;
152

153
        private ValueItemStack(ItemStack itemStack) {
154
            super(ValueTypes.OBJECT_ITEMSTACK);
3 ✔
155
            this.itemStack = Objects.requireNonNull(itemStack, "Attempted to create a ValueItemStack for a null ItemStack.");
6 ✔
156
        }
1 ✔
157

158
        public static ValueItemStack of(ItemStack itemStack) {
159
            return new ValueItemStack(itemStack);
5 ✔
160
        }
161

162
        public ItemStack getRawValue() {
163
            return itemStack;
3 ✔
164
        }
165

166
        @Override
167
        public boolean equals(Object o) {
168
            return o instanceof ValueItemStack && ItemMatch.areItemStacksEqual(((ValueItemStack) o).itemStack, this.itemStack, ItemMatch.EXACT);
15 !
169
        }
170

171
        @Override
172
        public int hashCode() {
173
            return 37 + ItemStackHelpers.getItemStackHashCode(itemStack);
×
174
        }
175
    }
176

177
    public static class ValueItemStackPredicate extends ValuePredicate<ValueItemStack> {
178

179
        private final Optional<ItemPredicate> itemPredicate;
180

181
        public ValueItemStackPredicate(Optional<ItemPredicate> itemPredicate) {
182
            super(Optional.of(ValueTypes.OBJECT_ITEMSTACK), Optional.empty(), Optional.empty());
6 ✔
183
            this.itemPredicate = itemPredicate;
3 ✔
184
        }
1 ✔
185

186
        public Optional<ItemPredicate> getItemPredicate() {
187
            return itemPredicate;
×
188
        }
189

190
        @Override
191
        protected boolean testTyped(ValueItemStack value) {
192
            return super.testTyped(value) && (itemPredicate.isEmpty() || itemPredicate.get().test(value.getRawValue()));
20 !
193
        }
194
    }
195

196
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc