aboutsummaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java32
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/AbstractionEngineGame.java64
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/Theme.java34
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java59
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Button.java176
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/GridBoardActor.java68
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java154
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Logo.java58
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Penguin.java160
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Player.java22
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Wall.java22
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/config/KeyBinds.java42
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java16
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/life/CellState.java54
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java226
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/life/LifeInput.java4
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/life/LifeSystem.java122
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java86
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java228
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/ScrollLogo.java228
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/FrameState.java4
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java12
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ActorHolder.java (renamed from core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/GridEntityRef.java)7
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ExternalWorldEntityRef.java12
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/InterpolatedPosition.java18
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GameWorldManagementSystem.java100
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java74
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java119
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/InputSystem.java104
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java128
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/CursorStyle.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorModifier.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorTextArea.java434
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/InputStrategy.java10
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/KeyEvent.java6
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LambdaEditor.java94
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LineNumberMode.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/RenderState.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/EditorBuffer.java18
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/Mode.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimConfig.java56
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimEngine.java286
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/buffer/TextAreaBuffer.java92
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java1172
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/CommandAction.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/HandleResult.java42
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/InsertModeHandler.java28
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/ModeHandler.java4
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/MotionAction.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java582
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/SearchModeHandler.java56
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualLineModeHandler.java146
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualModeHandler.java226
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/Register.java4
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/RegisterType.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoManager.java74
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoState.java4
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java186
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchDirection.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchIterator.java96
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/ModeState.java18
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/NormalState.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/PendingOperator.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/SearchState.java10
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualLineState.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualState.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/status/StatusFormatter.java80
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/utils/FontHelper.java36
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/utils/FunctionUtils.java44
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/utils/TimerUtils.java34
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java118
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/entity/EntityType.java74
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/entity/EntityTypeGridCollidable.java8
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/GridCollidable.java94
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java30
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/GridMomentum.java6
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/GridPosition.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java54
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java130
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridIndexSystem.java6
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java18
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java26
-rw-r--r--core/src/main/java/coffee/liz/ecs/DAGWorld.java224
-rw-r--r--core/src/main/java/coffee/liz/ecs/math/Mat2.java148
-rw-r--r--core/src/main/java/coffee/liz/ecs/math/Vec2.java134
-rw-r--r--core/src/main/java/coffee/liz/ecs/math/Vec2f.java68
-rw-r--r--core/src/main/java/coffee/liz/ecs/math/Vec2i.java76
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/Component.java6
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/Entity.java154
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/System.java36
-rw-r--r--core/src/main/java/coffee/liz/ecs/model/World.java80
-rw-r--r--core/src/main/java/coffee/liz/lambda/LambdaDriver.java104
-rw-r--r--core/src/main/java/coffee/liz/lambda/ast/Expression.java24
-rw-r--r--core/src/main/java/coffee/liz/lambda/ast/Macro.java2
-rw-r--r--core/src/main/java/coffee/liz/lambda/ast/SourceCode.java32
-rw-r--r--core/src/main/java/coffee/liz/lambda/ast/SourceComment.java12
-rw-r--r--core/src/main/java/coffee/liz/lambda/ast/SourceSpan.java14
-rw-r--r--core/src/main/java/coffee/liz/lambda/bind/ExternalBinding.java12
-rw-r--r--core/src/main/java/coffee/liz/lambda/bind/Tick.java14
-rw-r--r--core/src/main/java/coffee/liz/lambda/bind/ToChurch.java42
-rw-r--r--core/src/main/java/coffee/liz/lambda/eval/Environment.java154
-rw-r--r--core/src/main/java/coffee/liz/lambda/eval/EvaluationDepthExceededException.java10
-rw-r--r--core/src/main/java/coffee/liz/lambda/eval/NormalOrderEvaluator.java140
-rw-r--r--core/src/main/java/coffee/liz/lambda/eval/Thunk.java22
-rw-r--r--core/src/main/java/coffee/liz/lambda/eval/Value.java60
-rw-r--r--core/src/main/java/coffee/liz/lambda/format/Formatter.java356
-rw-r--r--core/src/main/java/com/kotcrab/vis/ui/widget/EditorHighlightTextAreaBridge.java50
107 files changed, 4456 insertions, 4381 deletions
diff --git a/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java b/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java
index c6e7a49..806d05e 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java
@@ -16,21 +16,21 @@ import java.util.Map;
/** Grid world implementation for the abstraction engine. */
@Log4j2
public class AbstractionEngineGridWorld extends DAGWorld<GridInputState> {
- /** Initialize world with systems and player. */
- public AbstractionEngineGridWorld(final Vec2<Integer> gridDimensions) {
- super(Map.of(GridMovementSystem.class, new GridMovementSystem(), GridPhysicsSystem.class,
- new GridPhysicsSystem(), GridIndexSystem.class, new GridIndexSystem(gridDimensions),
- GridCollisionPropagatationSystem.class, new GridCollisionPropagatationSystem()));
- }
+ /** Initialize world with systems and player. */
+ public AbstractionEngineGridWorld(final Vec2<Integer> gridDimensions) {
+ super(Map.of(GridMovementSystem.class, new GridMovementSystem(), GridPhysicsSystem.class,
+ new GridPhysicsSystem(), GridIndexSystem.class, new GridIndexSystem(gridDimensions),
+ GridCollisionPropagatationSystem.class, new GridCollisionPropagatationSystem()));
+ }
- /**
- * Update world with input state. For now our grid world is a "step function",
- * so we shouldn't (yet) care about the amount of time between steps.
- *
- * @param state
- * the {@link GridInputState}
- */
- public void update(final GridInputState state) {
- update(state, Duration.ZERO);
- }
+ /**
+ * Update world with input state. For now our grid world is a "step function",
+ * so we shouldn't (yet) care about the amount of time between steps.
+ *
+ * @param state
+ * the {@link GridInputState}
+ */
+ public void update(final GridInputState state) {
+ update(state, Duration.ZERO);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/AbstractionEngineGame.java b/core/src/main/java/coffee/liz/abstractionengine/app/AbstractionEngineGame.java
index 9aa61ec..d0ba1f3 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/AbstractionEngineGame.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/AbstractionEngineGame.java
@@ -13,42 +13,42 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.utils.viewport.FitViewport;
public class AbstractionEngineGame extends Game {
- public static final Vec2<Float> WORLD_SIZE = Vec2f.builder().x(800f).y(800f).build();
+ public static final Vec2<Float> WORLD_SIZE = Vec2f.builder().x(800f).y(800f).build();
- public SpriteBatch batch;
- public BitmapFont font;
- public FitViewport viewport;
- public ShapeRenderer shapeRenderer;
- public Settings settings = Settings.builder().build();
+ public SpriteBatch batch;
+ public BitmapFont font;
+ public FitViewport viewport;
+ public ShapeRenderer shapeRenderer;
+ public Settings settings = Settings.builder().build();
- /**
- * Game initialization hook.
- */
- public void create() {
- viewport = new FitViewport(WORLD_SIZE.getX(), WORLD_SIZE.getY());
- batch = new SpriteBatch();
- shapeRenderer = new ShapeRenderer();
- font = FontHelper.initFont(24, FontHelper.MONO,
- AbstractionEngineGame.WORLD_SIZE.getY() / Gdx.graphics.getHeight());
+ /**
+ * Game initialization hook.
+ */
+ public void create() {
+ viewport = new FitViewport(WORLD_SIZE.getX(), WORLD_SIZE.getY());
+ batch = new SpriteBatch();
+ shapeRenderer = new ShapeRenderer();
+ font = FontHelper.initFont(24, FontHelper.MONO,
+ AbstractionEngineGame.WORLD_SIZE.getY() / Gdx.graphics.getHeight());
- this.setScreen(new ScrollLogo(this));
+ this.setScreen(new ScrollLogo(this));
- viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
- }
+ viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
+ }
- /**
- * Game render hook.
- */
- public void render() {
- super.render();
- }
+ /**
+ * Game render hook.
+ */
+ public void render() {
+ super.render();
+ }
- /**
- * Game cleanup hook.
- */
- public void dispose() {
- batch.dispose();
- font.dispose();
- shapeRenderer.dispose();
- }
+ /**
+ * Game cleanup hook.
+ */
+ public void dispose() {
+ batch.dispose();
+ font.dispose();
+ shapeRenderer.dispose();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/Theme.java b/core/src/main/java/coffee/liz/abstractionengine/app/Theme.java
index bc653fd..1d3f449 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/Theme.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/Theme.java
@@ -4,26 +4,26 @@ import com.badlogic.gdx.graphics.Color;
// TODO: Make this part of the {@link Settings}
public final class Theme {
- public static final Color BG = Color.valueOf("2d2523");
- public static final Color BG_PATTERN = Color.valueOf("241e1c");
- public static final Color SURFACE = Color.valueOf("3b312f");
- public static final Color SURFACE_ALT = Color.valueOf("463a37");
+ public static final Color BG = Color.valueOf("2d2523");
+ public static final Color BG_PATTERN = Color.valueOf("241e1c");
+ public static final Color SURFACE = Color.valueOf("3b312f");
+ public static final Color SURFACE_ALT = Color.valueOf("463a37");
- public static final Color FG = Color.valueOf("f9efea");
- public static final Color MUTED = Color.valueOf("cbb8b1");
+ public static final Color FG = Color.valueOf("f9efea");
+ public static final Color MUTED = Color.valueOf("cbb8b1");
- public static final Color BORDER = Color.valueOf("f1e6e0");
- public static final Color BORDER_LIGHT = Color.valueOf("6e5b57");
- public static final Color BORDER_DARK = Color.valueOf("120d0c");
+ public static final Color BORDER = Color.valueOf("f1e6e0");
+ public static final Color BORDER_LIGHT = Color.valueOf("6e5b57");
+ public static final Color BORDER_DARK = Color.valueOf("120d0c");
- public static final Color PRIMARY = Color.valueOf("f06aa6");
- public static final Color PRIMARY_LIGHT = Color.valueOf("ff97c8");
- public static final Color PRIMARY_DARK = Color.valueOf("d94b8e");
+ public static final Color PRIMARY = Color.valueOf("f06aa6");
+ public static final Color PRIMARY_LIGHT = Color.valueOf("ff97c8");
+ public static final Color PRIMARY_DARK = Color.valueOf("d94b8e");
- public static final Color SECONDARY = Color.valueOf("b69cff");
- public static final Color SECONDARY_LIGHT = Color.valueOf("d7c8ff");
- public static final Color SECONDARY_DARK = Color.valueOf("8f78d6");
+ public static final Color SECONDARY = Color.valueOf("b69cff");
+ public static final Color SECONDARY_LIGHT = Color.valueOf("d7c8ff");
+ public static final Color SECONDARY_DARK = Color.valueOf("8f78d6");
- private Theme() {
- }
+ private Theme() {
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java
new file mode 100644
index 0000000..5c964a2
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java
@@ -0,0 +1,59 @@
+package coffee.liz.abstractionengine.app.actor;
+
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.math.Vec2i;
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.Animation;
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.TextureRegion;
+import com.badlogic.gdx.scenes.scene2d.Actor;
+import lombok.Getter;
+
+public class Abstraction extends Actor {
+ private static final Vec2<Integer> ABSTRACTION_FRAMES = Vec2i.builder().x(1).y(4).build();
+
+ private final Texture texture;
+ @Getter
+ private final Animation<TextureRegion> animation;
+ private float stateTime = 0f;
+
+ /**
+ * Creates a penguin actor.
+ */
+ public Abstraction() {
+ this.texture = new Texture(Gdx.files.internal("sprites/abstraction.png"));
+ final TextureRegion[][] tmp = TextureRegion.split(texture, texture.getWidth() / ABSTRACTION_FRAMES.getX(),
+ texture.getHeight() / ABSTRACTION_FRAMES.getY());
+ final TextureRegion[] anim = {
+ tmp[0][0],
+ tmp[1][0],
+ tmp[2][0],
+ tmp[3][0]
+ };
+ this.animation = new Animation<>(0.25f, anim);
+ }
+
+ /**
+ * Actor draw hook.
+ *
+ * @param batch
+ * parent batch
+ * @param parentAlpha
+ * parent alpha multiplier
+ */
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ final TextureRegion frame = this.animation.getKeyFrame(stateTime, true);
+ final Color c = getColor();
+ batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
+ batch.draw(frame, getX(), getY(), getWidth(), getHeight());
+ }
+
+ @Override
+ public void act(final float delta) {
+ super.act(delta);
+ stateTime += delta;
+ }
+}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Button.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Button.java
index a7416b9..271e40f 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Button.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Button.java
@@ -17,110 +17,110 @@ import lombok.Setter;
@RequiredArgsConstructor
public class Button extends Actor {
- private static final float ALPHA = 0.85f;
- private static final float BORDER_WIDTH = 1f;
+ private static final float ALPHA = 0.85f;
+ private static final float BORDER_WIDTH = 1f;
- private final ShapeRenderer shapeRenderer;
- private final BitmapFont font;
- private final String text;
+ private final ShapeRenderer shapeRenderer;
+ private final BitmapFont font;
+ private final String text;
- @Setter
- private Runnable onClick;
+ @Setter
+ private Runnable onClick;
- @Getter
- private boolean hovered = false;
- @Getter
- private boolean pressed = false;
+ @Getter
+ private boolean hovered = false;
+ @Getter
+ private boolean pressed = false;
- private final GlyphLayout layout = new GlyphLayout();
- private final Color bgColor = new Color();
- private final Color borderColor = new Color();
+ private final GlyphLayout layout = new GlyphLayout();
+ private final Color bgColor = new Color();
+ private final Color borderColor = new Color();
- /**
- * Actor draw hook.
- *
- * @param batch
- * parent batch
- * @param parentAlpha
- * parent alpha multiplier
- */
- @Override
- public void draw(final Batch batch, final float parentAlpha) {
- batch.end();
+ /**
+ * Actor draw hook.
+ *
+ * @param batch
+ * parent batch
+ * @param parentAlpha
+ * parent alpha multiplier
+ */
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ batch.end();
- Gdx.gl.glEnable(GL20.GL_BLEND);
- Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
+ Gdx.gl.glEnable(GL20.GL_BLEND);
+ Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
- shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
- shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
+ shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
+ shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
- final float effectiveAlpha = parentAlpha * ALPHA * getColor().a;
- computeColors(effectiveAlpha);
+ final float effectiveAlpha = parentAlpha * ALPHA * getColor().a;
+ computeColors(effectiveAlpha);
- shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
- shapeRenderer.setColor(borderColor);
- shapeRenderer.rect(getX(), getY(), getWidth(), getHeight());
- shapeRenderer.setColor(bgColor);
- shapeRenderer.rect(getX() + BORDER_WIDTH, getY() + BORDER_WIDTH, getWidth() - BORDER_WIDTH * 2,
- getHeight() - BORDER_WIDTH * 2);
- shapeRenderer.end();
+ shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
+ shapeRenderer.setColor(borderColor);
+ shapeRenderer.rect(getX(), getY(), getWidth(), getHeight());
+ shapeRenderer.setColor(bgColor);
+ shapeRenderer.rect(getX() + BORDER_WIDTH, getY() + BORDER_WIDTH, getWidth() - BORDER_WIDTH * 2,
+ getHeight() - BORDER_WIDTH * 2);
+ shapeRenderer.end();
- Gdx.gl.glDisable(GL20.GL_BLEND);
+ Gdx.gl.glDisable(GL20.GL_BLEND);
- batch.begin();
+ batch.begin();
- layout.setText(font, text);
- final float textX = getX() + (getWidth() - layout.width) / 2f;
- final float textY = getY() + (getHeight() + layout.height) / 2f;
+ layout.setText(font, text);
+ final float textX = getX() + (getWidth() - layout.width) / 2f;
+ final float textY = getY() + (getHeight() + layout.height) / 2f;
- final Color textColor = hovered ? Theme.FG : Theme.MUTED;
- font.setColor(textColor.r, textColor.g, textColor.b, effectiveAlpha);
- font.draw(batch, text, textX, textY);
- }
+ final Color textColor = hovered ? Theme.FG : Theme.MUTED;
+ font.setColor(textColor.r, textColor.g, textColor.b, effectiveAlpha);
+ font.draw(batch, text, textX, textY);
+ }
- private void computeColors(final float alpha) {
- if (hovered) {
- bgColor.set(Theme.SURFACE_ALT).a = alpha;
- borderColor.set(Theme.PRIMARY).a = alpha;
- } else {
- bgColor.set(Theme.SURFACE).a = alpha;
- borderColor.set(Theme.BORDER_LIGHT).a = alpha;
- }
- }
+ private void computeColors(final float alpha) {
+ if (hovered) {
+ bgColor.set(Theme.SURFACE_ALT).a = alpha;
+ borderColor.set(Theme.PRIMARY).a = alpha;
+ } else {
+ bgColor.set(Theme.SURFACE).a = alpha;
+ borderColor.set(Theme.BORDER_LIGHT).a = alpha;
+ }
+ }
- /**
- * Enables input handling for the button.
- */
- public void addButtonListener() {
- addListener(new InputListener() {
- @Override
- public boolean touchDown(final InputEvent event, final float x, final float y, final int pointer,
- final int button) {
- pressed = true;
- return true;
- }
+ /**
+ * Enables input handling for the button.
+ */
+ public void addButtonListener() {
+ addListener(new InputListener() {
+ @Override
+ public boolean touchDown(final InputEvent event, final float x, final float y, final int pointer,
+ final int button) {
+ pressed = true;
+ return true;
+ }
- @Override
- public void touchUp(final InputEvent event, final float x, final float y, final int pointer,
- final int button) {
- if (pressed && hovered && onClick != null) {
- onClick.run();
- }
- pressed = false;
- }
+ @Override
+ public void touchUp(final InputEvent event, final float x, final float y, final int pointer,
+ final int button) {
+ if (pressed && hovered && onClick != null) {
+ onClick.run();
+ }
+ pressed = false;
+ }
- @Override
- public void enter(final InputEvent event, final float x, final float y, final int pointer,
- final Actor fromActor) {
- hovered = true;
- }
+ @Override
+ public void enter(final InputEvent event, final float x, final float y, final int pointer,
+ final Actor fromActor) {
+ hovered = true;
+ }
- @Override
- public void exit(final InputEvent event, final float x, final float y, final int pointer,
- final Actor toActor) {
- hovered = false;
- pressed = false;
- }
- });
- }
+ @Override
+ public void exit(final InputEvent event, final float x, final float y, final int pointer,
+ final Actor toActor) {
+ hovered = false;
+ pressed = false;
+ }
+ });
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/GridBoardActor.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/GridBoardActor.java
deleted file mode 100644
index a4317e0..0000000
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/GridBoardActor.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package coffee.liz.abstractionengine.app.actor;
-
-import coffee.liz.abstractionengine.app.Theme;
-import coffee.liz.abstractionengine.entity.EntityType;
-import coffee.liz.ecs.math.Mat2;
-import coffee.liz.ecs.math.Vec2;
-import coffee.liz.ecs.math.Vec2f;
-import com.badlogic.gdx.graphics.Color;
-import com.badlogic.gdx.graphics.g2d.Batch;
-import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
-import com.badlogic.gdx.scenes.scene2d.Actor;
-import lombok.RequiredArgsConstructor;
-import lombok.Setter;
-
-import java.util.List;
-
-@RequiredArgsConstructor
-public class GridBoardActor extends Actor {
- private final ShapeRenderer shapeRenderer;
- private final Vec2<Integer> gridSize;
-
- @Setter
- private Vec2<Float> cellSize;
-
- @Setter
- private List<RenderableEntity> entities = List.of();
-
- @Override
- public void draw(final Batch batch, final float parentAlpha) {
- batch.end();
-
- shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
- shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
- shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
-
- if (cellSize != null) {
- final float dotRadius = Math.min(cellSize.getX(), cellSize.getY()) * 0.07f;
- shapeRenderer.setColor(Theme.BORDER);
- Mat2.init(gridSize, pos -> {
- final Vec2<Float> center = pos.floatValue().plus(Vec2f.builder().x(0.5f).y(0.5f).build())
- .scale(cellSize);
- shapeRenderer.circle(center.getX(), center.getY(), dotRadius);
- return center;
- });
- }
-
- for (final RenderableEntity entity : entities) {
- shapeRenderer.setColor(getEntityColor(entity.entityType()));
- shapeRenderer.rect(entity.position().getX(), entity.position().getY(), entity.size().getX(),
- entity.size().getY());
- }
-
- shapeRenderer.end();
- batch.begin();
- }
-
- private static Color getEntityColor(final EntityType type) {
- return switch (type) {
- case WALL -> Theme.MUTED;
- case PLAYER -> Theme.PRIMARY;
- case ABSTRACTION -> Theme.SECONDARY;
- default -> Color.GREEN;
- };
- }
-
- public record RenderableEntity(EntityType entityType, Vec2<Float> position, Vec2<Float> size) {
- }
-}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java
index ab3fcbb..c4bb5e3 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java
@@ -28,92 +28,92 @@ import static com.badlogic.gdx.math.MathUtils.clamp;
@RequiredArgsConstructor
public class LifeGridActor extends Actor {
- private final ShapeRenderer shapeRenderer;
- private final World<LifeInput> world;
- private final Vec2<Integer> gridDimensions;
- private final Settings settings;
- private final Color cellColor = new Color();
+ private final ShapeRenderer shapeRenderer;
+ private final World<LifeInput> world;
+ private final Vec2<Integer> gridDimensions;
+ private final Settings settings;
+ private final Color cellColor = new Color();
- @Setter
- private Viewport viewport;
- @Setter
- private Vec2<Float> parallaxOffset = Vec2f.ZERO;
+ @Setter
+ private Viewport viewport;
+ @Setter
+ private Vec2<Float> parallaxOffset = Vec2f.ZERO;
- /**
- * Actor update hook.
- *
- * @param delta
- * time since last frame
- */
- @Override
- public void act(final float delta) {
- super.act(delta);
- if (viewport == null) {
- return;
- }
+ /**
+ * Actor update hook.
+ *
+ * @param delta
+ * time since last frame
+ */
+ @Override
+ public void act(final float delta) {
+ super.act(delta);
+ if (viewport == null) {
+ return;
+ }
- final Vec2<Float> cellSize = computeCellSize();
- final Set<Vec2<Integer>> forcedAlive = computeForcedAlive(cellSize);
- world.update(new LifeInput(forcedAlive, settings), Duration.ofMillis((int) (delta * 1000)));
- }
+ final Vec2<Float> cellSize = computeCellSize();
+ final Set<Vec2<Integer>> forcedAlive = computeForcedAlive(cellSize);
+ world.update(new LifeInput(forcedAlive, settings), Duration.ofMillis((int) (delta * 1000)));
+ }
- /**
- * Actor draw hook.
- *
- * @param batch
- * parent batch
- * @param parentAlpha
- * parent alpha multiplier
- */
- @Override
- public void draw(final Batch batch, final float parentAlpha) {
- if (viewport == null) {
- return;
- }
- batch.end();
+ /**
+ * Actor draw hook.
+ *
+ * @param batch
+ * parent batch
+ * @param parentAlpha
+ * parent alpha multiplier
+ */
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ if (viewport == null) {
+ return;
+ }
+ batch.end();
- shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
- shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
- shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
- drawCells(computeCellSize());
- shapeRenderer.end();
+ shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
+ shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
+ shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
+ drawCells(computeCellSize());
+ shapeRenderer.end();
- batch.begin();
- }
+ batch.begin();
+ }
- private Vec2<Float> computeCellSize() {
- return Vec2f.builder().x(viewport.getWorldWidth() / gridDimensions.getX())
- .y(viewport.getWorldHeight() / gridDimensions.getY()).build();
- }
+ private Vec2<Float> computeCellSize() {
+ return Vec2f.builder().x(viewport.getWorldWidth() / gridDimensions.getX())
+ .y(viewport.getWorldHeight() / gridDimensions.getY()).build();
+ }
- private Set<Vec2<Integer>> computeForcedAlive(final Vec2<Float> cellSize) {
- final Vector3 cursorPosition = viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
- final Vec2<Integer> gridPosition = Vec2f.builder().x(cursorPosition.x).y(cursorPosition.y).build()
- .transform(x -> clamp(x, 0.0f, viewport.getWorldWidth() - 0.001f),
- y -> clamp(y, 0.0f, viewport.getWorldHeight() - 0.001f))
- .scale(cellSize.transform(x -> 1 / x, y -> 1 / y)).intValue();
- return Stream.of(gridPosition)
- .flatMap(pos -> Stream.of(Vec2i.ZERO, Vec2i.EAST, Vec2i.WEST, Vec2i.NORTH, Vec2i.SOUTH).map(pos::plus))
- .collect(Collectors.toSet());
- }
+ private Set<Vec2<Integer>> computeForcedAlive(final Vec2<Float> cellSize) {
+ final Vector3 cursorPosition = viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
+ final Vec2<Integer> gridPosition = Vec2f.builder().x(cursorPosition.x).y(cursorPosition.y).build()
+ .transform(x -> clamp(x, 0.0f, viewport.getWorldWidth() - 0.001f),
+ y -> clamp(y, 0.0f, viewport.getWorldHeight() - 0.001f))
+ .scale(cellSize.transform(x -> 1 / x, y -> 1 / y)).intValue();
+ return Stream.of(gridPosition)
+ .flatMap(pos -> Stream.of(Vec2i.ZERO, Vec2i.EAST, Vec2i.WEST, Vec2i.NORTH, Vec2i.SOUTH).map(pos::plus))
+ .collect(Collectors.toSet());
+ }
- private void drawCells(final Vec2<Float> cellSize) {
- world.query(Set.of(GridPosition.class, CellState.class)).forEach(entity -> {
- final CellState state = entity.get(CellState.class);
- final Vec2<Integer> gridPos = entity.get(GridPosition.class).getPosition();
- final Vec2<Float> drawPos = gridPos.floatValue().scale(cellSize).plus(parallaxOffset);
+ private void drawCells(final Vec2<Float> cellSize) {
+ world.query(Set.of(GridPosition.class, CellState.class)).forEach(entity -> {
+ final CellState state = entity.get(CellState.class);
+ final Vec2<Integer> gridPos = entity.get(GridPosition.class).getPosition();
+ final Vec2<Float> drawPos = gridPos.floatValue().scale(cellSize).plus(parallaxOffset);
- final float alivePercentage = state.getAlivePercentage();
- if (alivePercentage <= 0.0f) {
- return;
- }
- shapeRenderer.setColor(interpolateColor(alivePercentage));
- shapeRenderer.rect(drawPos.getX(), drawPos.getY(), cellSize.getX(), cellSize.getY());
- });
- }
+ final float alivePercentage = state.getAlivePercentage();
+ if (alivePercentage <= 0.0f) {
+ return;
+ }
+ shapeRenderer.setColor(interpolateColor(alivePercentage));
+ shapeRenderer.rect(drawPos.getX(), drawPos.getY(), cellSize.getX(), cellSize.getY());
+ });
+ }
- private Color interpolateColor(final float alivePercentage) {
- final float interpolation = alivePercentage * alivePercentage * alivePercentage;
- return cellColor.set(Theme.BG_PATTERN).lerp(Theme.FG, interpolation);
- }
+ private Color interpolateColor(final float alivePercentage) {
+ final float interpolation = alivePercentage * alivePercentage * alivePercentage;
+ return cellColor.set(Theme.BG_PATTERN).lerp(Theme.FG, interpolation);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Logo.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Logo.java
index e8bf025..80f04cb 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Logo.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Logo.java
@@ -8,36 +8,36 @@ import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Disposable;
public class Logo extends Actor implements Disposable {
- private final Texture texture;
+ private final Texture texture;
- /**
- * Creates a logo actor.
- */
- public Logo() {
- this.texture = new Texture(Gdx.files.internal("sprites/logo.png"));
- setSize(texture.getWidth(), texture.getHeight());
- }
+ /**
+ * Creates a logo actor.
+ */
+ public Logo() {
+ this.texture = new Texture(Gdx.files.internal("sprites/logo.png"));
+ setSize(texture.getWidth(), texture.getHeight());
+ }
- /**
- * Actor draw hook.
- *
- * @param batch
- * parent batch
- * @param parentAlpha
- * parent alpha multiplier
- */
- @Override
- public void draw(final Batch batch, final float parentAlpha) {
- final Color c = getColor();
- batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
- batch.draw(texture, getX(), getY(), getWidth(), getHeight());
- }
+ /**
+ * Actor draw hook.
+ *
+ * @param batch
+ * parent batch
+ * @param parentAlpha
+ * parent alpha multiplier
+ */
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ final Color c = getColor();
+ batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
+ batch.draw(texture, getX(), getY(), getWidth(), getHeight());
+ }
- /**
- * Releases actor resources.
- */
- @Override
- public void dispose() {
- texture.dispose();
- }
+ /**
+ * Releases actor resources.
+ */
+ @Override
+ public void dispose() {
+ texture.dispose();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Penguin.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Penguin.java
index 4a557e7..932ac41 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Penguin.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Penguin.java
@@ -13,95 +13,95 @@ import com.badlogic.gdx.utils.Disposable;
import lombok.Getter;
public class Penguin extends Actor implements Disposable {
- private static final Vec2<Integer> PENGUIN_FRAMES = Vec2i.builder().x(8).y(4).build();
+ private static final Vec2<Integer> PENGUIN_FRAMES = Vec2i.builder().x(8).y(4).build();
- private final Texture texture;
- @Getter
- private final Animation<TextureRegion> tobaganning;
- @Getter
- private final Animation<TextureRegion> eepy;
- @Getter
- private final Animation<TextureRegion> eeping;
- private Animation<TextureRegion> currentAnimation;
- private float stateTime = 0f;
+ private final Texture texture;
+ @Getter
+ private final Animation<TextureRegion> tobaganning;
+ @Getter
+ private final Animation<TextureRegion> eepy;
+ @Getter
+ private final Animation<TextureRegion> eeping;
+ private Animation<TextureRegion> currentAnimation;
+ private float stateTime = 0f;
- /**
- * Creates a penguin actor.
- */
- public Penguin() {
- this.texture = new Texture(Gdx.files.internal("sprites/penguins.png"));
- final TextureRegion[][] tmp = TextureRegion.split(texture, texture.getWidth() / PENGUIN_FRAMES.getX(),
- texture.getHeight() / PENGUIN_FRAMES.getY());
+ /**
+ * Creates a penguin actor.
+ */
+ public Penguin() {
+ this.texture = new Texture(Gdx.files.internal("sprites/penguins.png"));
+ final TextureRegion[][] tmp = TextureRegion.split(texture, texture.getWidth() / PENGUIN_FRAMES.getX(),
+ texture.getHeight() / PENGUIN_FRAMES.getY());
- final TextureRegion[] tobaggonTextureRegion = new TextureRegion[2];
- tobaggonTextureRegion[0] = tmp[2][7];
- tobaggonTextureRegion[1] = tmp[3][6];
+ final TextureRegion[] tobaggonTextureRegion = new TextureRegion[2];
+ tobaggonTextureRegion[0] = tmp[2][7];
+ tobaggonTextureRegion[1] = tmp[3][6];
- final TextureRegion[] eepyTextureRegion = new TextureRegion[2];
- eepyTextureRegion[0] = tmp[2][3];
- eepyTextureRegion[1] = tmp[3][3];
+ final TextureRegion[] eepyTextureRegion = new TextureRegion[2];
+ eepyTextureRegion[0] = tmp[2][3];
+ eepyTextureRegion[1] = tmp[3][3];
- final TextureRegion[] eepingTextureRegion = new TextureRegion[2];
- eepingTextureRegion[0] = tmp[0][2];
- eepingTextureRegion[1] = tmp[1][2];
+ final TextureRegion[] eepingTextureRegion = new TextureRegion[2];
+ eepingTextureRegion[0] = tmp[0][2];
+ eepingTextureRegion[1] = tmp[1][2];
- this.tobaganning = new Animation<>(0.25f, tobaggonTextureRegion);
- this.eepy = new Animation<>(0.45f, eepyTextureRegion);
- this.eeping = new Animation<>(0.45f, eepingTextureRegion);
- this.currentAnimation = tobaganning;
- }
+ this.tobaganning = new Animation<>(0.25f, tobaggonTextureRegion);
+ this.eepy = new Animation<>(0.45f, eepyTextureRegion);
+ this.eeping = new Animation<>(0.45f, eepingTextureRegion);
+ this.currentAnimation = tobaganning;
+ }
- /**
- * Actor update hook.
- *
- * @param delta
- * time since last frame
- */
- @Override
- public void act(final float delta) {
- super.act(delta);
- stateTime += delta;
- }
+ /**
+ * Actor update hook.
+ *
+ * @param delta
+ * time since last frame
+ */
+ @Override
+ public void act(final float delta) {
+ super.act(delta);
+ stateTime += delta;
+ }
- /**
- * Actor draw hook.
- *
- * @param batch
- * parent batch
- * @param parentAlpha
- * parent alpha multiplier
- */
- @Override
- public void draw(final Batch batch, final float parentAlpha) {
- final TextureRegion frame = currentAnimation.getKeyFrame(stateTime, true);
- final Color c = getColor();
- batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
- batch.draw(frame, getX(), getY(), getWidth(), getHeight());
- }
+ /**
+ * Actor draw hook.
+ *
+ * @param batch
+ * parent batch
+ * @param parentAlpha
+ * parent alpha multiplier
+ */
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ final TextureRegion frame = currentAnimation.getKeyFrame(stateTime, true);
+ final Color c = getColor();
+ batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
+ batch.draw(frame, getX(), getY(), getWidth(), getHeight());
+ }
- /**
- * Sets the current animation state.
- *
- * @param state
- * new state
- */
- public void setState(final State state) {
- this.currentAnimation = switch (state) {
- case EEPY -> eepy;
- case EEPING -> eeping;
- case TOBAGGON -> tobaganning;
- };
- }
+ /**
+ * Sets the current animation state.
+ *
+ * @param state
+ * new state
+ */
+ public void setState(final State state) {
+ this.currentAnimation = switch (state) {
+ case EEPY -> eepy;
+ case EEPING -> eeping;
+ case TOBAGGON -> tobaganning;
+ };
+ }
- /**
- * Releases actor resources.
- */
- @Override
- public void dispose() {
- texture.dispose();
- }
+ /**
+ * Releases actor resources.
+ */
+ @Override
+ public void dispose() {
+ texture.dispose();
+ }
- public enum State {
- EEPY, EEPING, TOBAGGON
- }
+ public enum State {
+ EEPY, EEPING, TOBAGGON
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Player.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Player.java
new file mode 100644
index 0000000..fb63b0d
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Player.java
@@ -0,0 +1,22 @@
+package coffee.liz.abstractionengine.app.actor;
+
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.scenes.scene2d.Actor;
+import com.badlogic.gdx.scenes.scene2d.InputListener;
+import com.badlogic.gdx.scenes.scene2d.Stage;
+
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public class Player extends Actor {
+ private Stage stage;
+
+ public Player() {
+ addListener(new InputListener());
+ }
+
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ // batch.
+ }
+}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Wall.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Wall.java
new file mode 100644
index 0000000..2848a8e
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Wall.java
@@ -0,0 +1,22 @@
+package coffee.liz.abstractionengine.app.actor;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.scenes.scene2d.Actor;
+
+public class Wall extends Actor {
+ private final Texture texture;
+
+ public Wall() {
+ this.texture = new Texture(Gdx.files.internal("sprites/wall.png"));
+ }
+
+ @Override
+ public void draw(final Batch batch, final float parentAlpha) {
+ final Color c = getColor();
+ batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
+ batch.draw(texture, getX(), getY(), getWidth(), getHeight());
+ }
+}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/config/KeyBinds.java b/core/src/main/java/coffee/liz/abstractionengine/app/config/KeyBinds.java
index 598e1a8..06ae70d 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/config/KeyBinds.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/config/KeyBinds.java
@@ -17,27 +17,27 @@ import java.util.function.Predicate;
@RequiredArgsConstructor
@Getter
public class KeyBinds {
- @Builder.Default
- private Set<Integer> moveUpKeys = Set.of(Input.Keys.K, Input.Keys.UP, Input.Keys.W);
- @Builder.Default
- private Set<Integer> moveDownKeys = Set.of(Input.Keys.J, Input.Keys.DOWN, Input.Keys.S);
- @Builder.Default
- private Set<Integer> moveLeftKeys = Set.of(Input.Keys.H, Input.Keys.LEFT, Input.Keys.A);
- @Builder.Default
- private Set<Integer> moveRightKeys = Set.of(Input.Keys.L, Input.Keys.RIGHT, Input.Keys.D);
+ @Builder.Default
+ private Set<Integer> moveUpKeys = Set.of(Input.Keys.K, Input.Keys.UP, Input.Keys.W);
+ @Builder.Default
+ private Set<Integer> moveDownKeys = Set.of(Input.Keys.J, Input.Keys.DOWN, Input.Keys.S);
+ @Builder.Default
+ private Set<Integer> moveLeftKeys = Set.of(Input.Keys.H, Input.Keys.LEFT, Input.Keys.A);
+ @Builder.Default
+ private Set<Integer> moveRightKeys = Set.of(Input.Keys.L, Input.Keys.RIGHT, Input.Keys.D);
- public Set<Action> filterActiveActions(final Predicate<Integer> isDown) {
- final Set<Action> actions = new HashSet<>();
- Map.of(moveUpKeys, Action.MOVE_UP, moveDownKeys, Action.MOVE_DOWN, moveRightKeys, Action.MOVE_RIGHT,
- moveLeftKeys, Action.MOVE_LEFT).forEach((keys, action) -> {
- if (keys.stream().anyMatch(isDown)) {
- actions.add(action);
- }
- });
- return actions;
- }
+ public Set<Action> filterActiveActions(final Predicate<Integer> isDown) {
+ final Set<Action> actions = new HashSet<>();
+ Map.of(moveUpKeys, Action.MOVE_UP, moveDownKeys, Action.MOVE_DOWN, moveRightKeys, Action.MOVE_RIGHT,
+ moveLeftKeys, Action.MOVE_LEFT).forEach((keys, action) -> {
+ if (keys.stream().anyMatch(isDown)) {
+ actions.add(action);
+ }
+ });
+ return actions;
+ }
- public enum Action {
- MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT;
- }
+ public enum Action {
+ MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java b/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java
index dd09c21..7662700 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java
@@ -8,13 +8,13 @@ import lombok.Getter;
@AllArgsConstructor
@Getter
public class Settings {
- @Builder.Default
- private boolean skipIntro = true;
- @Builder.Default
- private boolean playMusic = true;
- @Builder.Default
- private boolean vimMode = true;
+ @Builder.Default
+ private boolean skipIntro = true;
+ @Builder.Default
+ private boolean playMusic = true;
+ @Builder.Default
+ private boolean vimMode = true;
- @Builder.Default
- private KeyBinds keyBinds = KeyBinds.builder().build();
+ @Builder.Default
+ private KeyBinds keyBinds = KeyBinds.builder().build();
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/life/CellState.java b/core/src/main/java/coffee/liz/abstractionengine/app/life/CellState.java
index 025cde0..bd07629 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/life/CellState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/life/CellState.java
@@ -5,36 +5,36 @@ import lombok.Getter;
@Getter
public class CellState implements Component {
- private static final float EPS = 1.0e-4f;
+ private static final float EPS = 1.0e-4f;
- public static final CellState LIVE = new CellState(1.0f);
- public static final CellState DEAD = new CellState(0.0f);
+ public static final CellState LIVE = new CellState(1.0f);
+ public static final CellState DEAD = new CellState(0.0f);
- private final float alivePercentage;
+ private final float alivePercentage;
- /**
- * Creates a cell state with a normalized alive percentage.
- *
- * @param alivePercentage
- * alive value in the range [0, 1]
- */
- public CellState(final float alivePercentage) {
- this.alivePercentage = clamp(alivePercentage);
- }
+ /**
+ * Creates a cell state with a normalized alive percentage.
+ *
+ * @param alivePercentage
+ * alive value in the range [0, 1]
+ */
+ public CellState(final float alivePercentage) {
+ this.alivePercentage = clamp(alivePercentage);
+ }
- /**
- * Returns true when the cell is considered alive.
- *
- * @return whether the cell is alive
- */
- public boolean isAlive() {
- return alivePercentage >= (1.0f - EPS);
- }
+ /**
+ * Returns true when the cell is considered alive.
+ *
+ * @return whether the cell is alive
+ */
+ public boolean isAlive() {
+ return alivePercentage >= (1.0f - EPS);
+ }
- private static float clamp(final float value) {
- if (value <= 0.0f) {
- return 0.0f;
- }
- return Math.min(value, 1.0f);
- }
+ private static float clamp(final float value) {
+ if (value <= 0.0f) {
+ return 0.0f;
+ }
+ return Math.min(value, 1.0f);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java
index b57db71..5660ff3 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java
@@ -17,142 +17,142 @@ import java.util.Set;
import java.util.stream.IntStream;
public class EntropyAudioSystem implements System<LifeInput> {
- private static final int SAMPLE_RATE = 44100;
- private static final int CHUNKS_X = 4;
- private static final int CHUNKS_Y = 4;
- private static final int NUM_CHUNKS = CHUNKS_X * CHUNKS_Y;
- private static final Duration AUDIO_THREAD_TIMEOUT = Duration.ofMillis(20);
+ private static final int SAMPLE_RATE = 44100;
+ private static final int CHUNKS_X = 4;
+ private static final int CHUNKS_Y = 4;
+ private static final int NUM_CHUNKS = CHUNKS_X * CHUNKS_Y;
+ private static final Duration AUDIO_THREAD_TIMEOUT = Duration.ofMillis(20);
- private static final int[] PENTATONIC_INTERVALS = {0, 3, 5, 7, 10};
- private static final float BASE_FREQUENCY = 110f;
- private static final float[] FREQUENCIES = new float[NUM_CHUNKS];
- static {
- for (int i = 0; i < NUM_CHUNKS; i++) {
- final int octave = i / PENTATONIC_INTERVALS.length;
- final int degree = i % PENTATONIC_INTERVALS.length;
- final int semitones = octave * 12 + PENTATONIC_INTERVALS[degree];
- FREQUENCIES[i] = BASE_FREQUENCY * (float) Math.pow(2.0, semitones / 12.0);
- }
- }
+ private static final int[] PENTATONIC_INTERVALS = {0, 3, 5, 7, 10};
+ private static final float BASE_FREQUENCY = 110f;
+ private static final float[] FREQUENCIES = new float[NUM_CHUNKS];
+ static {
+ for (int i = 0; i < NUM_CHUNKS; i++) {
+ final int octave = i / PENTATONIC_INTERVALS.length;
+ final int degree = i % PENTATONIC_INTERVALS.length;
+ final int semitones = octave * 12 + PENTATONIC_INTERVALS[degree];
+ FREQUENCIES[i] = BASE_FREQUENCY * (float) Math.pow(2.0, semitones / 12.0);
+ }
+ }
- private static final float MIN_PULSE_RATE = 1.0f;
- private static final float MAX_PULSE_RATE = 8.0f;
- private static final float MASTER_VOLUME = 0.15f;
- private static final float SMOOTHING_FACTOR = 0.0005f;
+ private static final float MIN_PULSE_RATE = 1.0f;
+ private static final float MAX_PULSE_RATE = 8.0f;
+ private static final float MASTER_VOLUME = 0.15f;
+ private static final float SMOOTHING_FACTOR = 0.0005f;
- private final AudioDevice device = Gdx.audio.newAudioDevice(SAMPLE_RATE, true);
- private final float[] targetEntropies = new float[NUM_CHUNKS];
- private final float[] smoothedEntropies = new float[NUM_CHUNKS];
- private final float[] phases = new float[NUM_CHUNKS];
- private final float[] pulsePhases = new float[NUM_CHUNKS];
+ private final AudioDevice device = Gdx.audio.newAudioDevice(SAMPLE_RATE, true);
+ private final float[] targetEntropies = new float[NUM_CHUNKS];
+ private final float[] smoothedEntropies = new float[NUM_CHUNKS];
+ private final float[] phases = new float[NUM_CHUNKS];
+ private final float[] pulsePhases = new float[NUM_CHUNKS];
- private final Thread audioThread;
- private volatile boolean running = true;
+ private final Thread audioThread;
+ private volatile boolean running = true;
- public EntropyAudioSystem() {
- audioThread = new Thread(this::audioLoop, "EntropyAudio");
- audioThread.setDaemon(true);
- }
+ public EntropyAudioSystem() {
+ audioThread = new Thread(this::audioLoop, "EntropyAudio");
+ audioThread.setDaemon(true);
+ }
- @Override
- public Collection<Class<? extends System<LifeInput>>> getDependencies() {
- return Set.of(LifeSystem.class);
- }
+ @Override
+ public Collection<Class<? extends System<LifeInput>>> getDependencies() {
+ return Set.of(LifeSystem.class);
+ }
- @Override
- public void update(final World<LifeInput> world, final LifeInput state, final Duration dt) {
- if (!state.getGameInstructions().isPlayMusic()) {
- running = false;
- return;
- }
+ @Override
+ public void update(final World<LifeInput> world, final LifeInput state, final Duration dt) {
+ if (!state.getGameInstructions().isPlayMusic()) {
+ running = false;
+ return;
+ }
- if (!audioThread.isAlive()) {
- audioThread.start();
- running = true;
- }
+ if (!audioThread.isAlive()) {
+ audioThread.start();
+ running = true;
+ }
- final LifeSystem lifeSystem = world.getSystem(LifeSystem.class);
- final Vec2<Integer> gridDimensions = lifeSystem.getDimensions();
- final List<List<Set<Entity>>> rows = lifeSystem.getRows();
+ final LifeSystem lifeSystem = world.getSystem(LifeSystem.class);
+ final Vec2<Integer> gridDimensions = lifeSystem.getDimensions();
+ final List<List<Set<Entity>>> rows = lifeSystem.getRows();
- final Vec2<Integer> chunkDimensions = Vec2i.builder().x(gridDimensions.getX() / CHUNKS_X)
- .y(gridDimensions.getY() / CHUNKS_Y).build();
+ final Vec2<Integer> chunkDimensions = Vec2i.builder().x(gridDimensions.getX() / CHUNKS_X)
+ .y(gridDimensions.getY() / CHUNKS_Y).build();
- for (int cy = 0; cy < CHUNKS_Y; cy++) {
- for (int cx = 0; cx < CHUNKS_X; cx++) {
- final int chunkIndex = cy * CHUNKS_X + cx;
- final Vec2<Integer> chunk = Vec2i.builder().x(cx).y(cy).build();
- final Vec2<Integer> bottomLeft = chunkDimensions.scale(chunk);
- final Vec2<Integer> topRight = bottomLeft.plus(chunkDimensions);
+ for (int cy = 0; cy < CHUNKS_Y; cy++) {
+ for (int cx = 0; cx < CHUNKS_X; cx++) {
+ final int chunkIndex = cy * CHUNKS_X + cx;
+ final Vec2<Integer> chunk = Vec2i.builder().x(cx).y(cy).build();
+ final Vec2<Integer> bottomLeft = chunkDimensions.scale(chunk);
+ final Vec2<Integer> topRight = bottomLeft.plus(chunkDimensions);
- final long alive = IntStream.range(bottomLeft.getY(), topRight.getY())
- .mapToLong(y -> IntStream.range(bottomLeft.getX(), topRight.getX()).mapToLong(
- x -> rows.get(y).get(x).stream().filter(e -> e.get(CellState.class).isAlive()).count())
- .sum())
- .sum();
- targetEntropies[chunkIndex] = computeShannonEntropy(
- alive / (float) (chunkDimensions.getY() * chunkDimensions.getX()));
- }
- }
- }
+ final long alive = IntStream.range(bottomLeft.getY(), topRight.getY())
+ .mapToLong(y -> IntStream.range(bottomLeft.getX(), topRight.getX()).mapToLong(
+ x -> rows.get(y).get(x).stream().filter(e -> e.get(CellState.class).isAlive()).count())
+ .sum())
+ .sum();
+ targetEntropies[chunkIndex] = computeShannonEntropy(
+ alive / (float) (chunkDimensions.getY() * chunkDimensions.getX()));
+ }
+ }
+ }
- private float computeShannonEntropy(final float p) {
- if (p <= 0.0f || p >= 1.0f) {
- return 0.0f;
- }
+ private float computeShannonEntropy(final float p) {
+ if (p <= 0.0f || p >= 1.0f) {
+ return 0.0f;
+ }
- final float entropy = -p * MathUtils.log2(p) - (1 - p) * MathUtils.log2(1 - p);
- return MathUtils.clamp(entropy, 0f, 1f);
- }
+ final float entropy = -p * MathUtils.log2(p) - (1 - p) * MathUtils.log2(1 - p);
+ return MathUtils.clamp(entropy, 0f, 1f);
+ }
- private void audioLoop() {
- final int bufferSize = 2048;
- final float[] buffer = new float[bufferSize];
- final float dtPerSample = 1.0f / SAMPLE_RATE;
+ private void audioLoop() {
+ final int bufferSize = 2048;
+ final float[] buffer = new float[bufferSize];
+ final float dtPerSample = 1.0f / SAMPLE_RATE;
- while (running) {
- for (int i = 0; i < bufferSize; i++) {
- float sample = 0.0f;
+ while (running) {
+ for (int i = 0; i < bufferSize; i++) {
+ float sample = 0.0f;
- for (int c = 0; c < NUM_CHUNKS; c++) {
- final float target = targetEntropies[c];
- smoothedEntropies[c] += (target - smoothedEntropies[c]) * SMOOTHING_FACTOR;
- final float entropy = smoothedEntropies[c];
+ for (int c = 0; c < NUM_CHUNKS; c++) {
+ final float target = targetEntropies[c];
+ smoothedEntropies[c] += (target - smoothedEntropies[c]) * SMOOTHING_FACTOR;
+ final float entropy = smoothedEntropies[c];
- if (entropy < 0.01f) {
- continue;
- }
+ if (entropy < 0.01f) {
+ continue;
+ }
- final float frequency = FREQUENCIES[c];
- final float pulseRate = MIN_PULSE_RATE + entropy * (MAX_PULSE_RATE - MIN_PULSE_RATE);
- final float volume = entropy * MASTER_VOLUME;
+ final float frequency = FREQUENCIES[c];
+ final float pulseRate = MIN_PULSE_RATE + entropy * (MAX_PULSE_RATE - MIN_PULSE_RATE);
+ final float volume = entropy * MASTER_VOLUME;
- phases[c] += frequency * dtPerSample;
- if (phases[c] > 1.0f) {
- phases[c] -= 1.0f;
- }
+ phases[c] += frequency * dtPerSample;
+ if (phases[c] > 1.0f) {
+ phases[c] -= 1.0f;
+ }
- pulsePhases[c] += pulseRate * dtPerSample;
- if (pulsePhases[c] > 1.0f) {
- pulsePhases[c] -= 1.0f;
- }
+ pulsePhases[c] += pulseRate * dtPerSample;
+ if (pulsePhases[c] > 1.0f) {
+ pulsePhases[c] -= 1.0f;
+ }
- final float wave = (float) Math.sin(phases[c] * 2 * Math.PI);
- final float pulse = 0.5f + 0.5f * (float) Math.sin(pulsePhases[c] * 2 * Math.PI);
- sample += wave * volume * pulse;
- }
+ final float wave = (float) Math.sin(phases[c] * 2 * Math.PI);
+ final float pulse = 0.5f + 0.5f * (float) Math.sin(pulsePhases[c] * 2 * Math.PI);
+ sample += wave * volume * pulse;
+ }
- buffer[i] = Math.max(-1.0f, Math.min(1.0f, sample));
- }
+ buffer[i] = Math.max(-1.0f, Math.min(1.0f, sample));
+ }
- device.writeSamples(buffer, 0, bufferSize);
- }
- }
+ device.writeSamples(buffer, 0, bufferSize);
+ }
+ }
- @Override
- public void close() {
- running = false;
- FunctionUtils.wrapCheckedException(() -> audioThread.join(AUDIO_THREAD_TIMEOUT));
- device.dispose();
- }
+ @Override
+ public void close() {
+ running = false;
+ FunctionUtils.wrapCheckedException(() -> audioThread.join(AUDIO_THREAD_TIMEOUT));
+ device.dispose();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeInput.java b/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeInput.java
index 36a1276..4007274 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeInput.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeInput.java
@@ -10,6 +10,6 @@ import java.util.Set;
@RequiredArgsConstructor
@Data
public class LifeInput {
- private final Set<Vec2<Integer>> forceAliveCells;
- private final Settings gameInstructions;
+ private final Set<Vec2<Integer>> forceAliveCells;
+ private final Settings gameInstructions;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeSystem.java
index aea42c9..dcb6fb9 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/life/LifeSystem.java
@@ -12,74 +12,74 @@ import java.util.Set;
/** Conway's game of life */
public class LifeSystem extends BaseGridIndexSystem<LifeInput> {
- public final static int MAX_DECAY_STEPS = 12;
- private final static float DECAY_STEP = 1.0f / MAX_DECAY_STEPS;
- private final static Vec2<Integer> CONVOLUTION_RADIUS = Vec2i.builder().x(1).y(1).build();
+ public final static int MAX_DECAY_STEPS = 12;
+ private final static float DECAY_STEP = 1.0f / MAX_DECAY_STEPS;
+ private final static Vec2<Integer> CONVOLUTION_RADIUS = Vec2i.builder().x(1).y(1).build();
- private final static Duration BETWEEN_UPDATES = Duration.ofMillis(200);
+ private final static Duration BETWEEN_UPDATES = Duration.ofMillis(200);
- private Duration sinceUpdate = Duration.ZERO;
+ private Duration sinceUpdate = Duration.ZERO;
- /**
- * Creates a life system.
- *
- * @param dimensions
- * grid size
- */
- public LifeSystem(final Vec2<Integer> dimensions) {
- super(dimensions);
- }
+ /**
+ * Creates a life system.
+ *
+ * @param dimensions
+ * grid size
+ */
+ public LifeSystem(final Vec2<Integer> dimensions) {
+ super(dimensions);
+ }
- /**
- * Advances the simulation.
- *
- * @param world
- * world to update
- * @param state
- * input state for this tick
- * @param dt
- * time step
- */
- @Override
- public void update(final World<LifeInput> world, final LifeInput state, final Duration dt) {
- super.update(world, state, dt);
+ /**
+ * Advances the simulation.
+ *
+ * @param world
+ * world to update
+ * @param state
+ * input state for this tick
+ * @param dt
+ * time step
+ */
+ @Override
+ public void update(final World<LifeInput> world, final LifeInput state, final Duration dt) {
+ super.update(world, state, dt);
- sinceUpdate = sinceUpdate.plus(dt);
- if (BETWEEN_UPDATES.compareTo(sinceUpdate) <= 0) {
- Mat2.convolveTorus(this.rows, CONVOLUTION_RADIUS, () -> 0, (entities, rel, prev) -> {
- if (rel.equals(Vec2i.ZERO)) {
- return prev;
- }
- return entities.stream().findFirst().map(entity -> entity.get(CellState.class))
- .map(cellState -> prev + (cellState.isAlive() ? 1 : 0)).orElse(prev);
- }, (entities, neighboringAliveCells) -> entities.stream().findFirst().map(entity -> {
- final CellState cellState = entity.get(CellState.class);
- final float decay = cellState.getAlivePercentage();
+ sinceUpdate = sinceUpdate.plus(dt);
+ if (BETWEEN_UPDATES.compareTo(sinceUpdate) <= 0) {
+ Mat2.convolveTorus(this.rows, CONVOLUTION_RADIUS, () -> 0, (entities, rel, prev) -> {
+ if (rel.equals(Vec2i.ZERO)) {
+ return prev;
+ }
+ return entities.stream().findFirst().map(entity -> entity.get(CellState.class))
+ .map(cellState -> prev + (cellState.isAlive() ? 1 : 0)).orElse(prev);
+ }, (entities, neighboringAliveCells) -> entities.stream().findFirst().map(entity -> {
+ final CellState cellState = entity.get(CellState.class);
+ final float decay = cellState.getAlivePercentage();
- final boolean alive = cellState.isAlive();
- final boolean diesNow = alive && (neighboringAliveCells < 2 || neighboringAliveCells > 3);
- final boolean spawnsNow = !alive && neighboringAliveCells == 3;
- final boolean stillAlive = alive && !diesNow;
+ final boolean alive = cellState.isAlive();
+ final boolean diesNow = alive && (neighboringAliveCells < 2 || neighboringAliveCells > 3);
+ final boolean spawnsNow = !alive && neighboringAliveCells == 3;
+ final boolean stillAlive = alive && !diesNow;
- final CellState nextState;
- if (spawnsNow || stillAlive) {
- nextState = CellState.LIVE;
- } else {
- nextState = new CellState(decay - DECAY_STEP);
- }
+ final CellState nextState;
+ if (spawnsNow || stillAlive) {
+ nextState = CellState.LIVE;
+ } else {
+ nextState = new CellState(decay - DECAY_STEP);
+ }
- entity.add(nextState);
- return entity;
- }));
- sinceUpdate = Duration.ZERO;
- }
+ entity.add(nextState);
+ return entity;
+ }));
+ sinceUpdate = Duration.ZERO;
+ }
- state.getForceAliveCells().forEach(cell -> {
- if (!inBounds(cell)) {
- return;
- }
- final Set<Entity> entities = rows.get(cell.getY()).get(cell.getX());
- entities.forEach(e -> e.add(CellState.LIVE));
- });
- }
+ state.getForceAliveCells().forEach(cell -> {
+ if (!inBounds(cell)) {
+ return;
+ }
+ final Set<Entity> entities = rows.get(cell.getY()).get(cell.getX());
+ entities.forEach(e -> e.add(CellState.LIVE));
+ });
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java
index cbdf51a..70bb973 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java
@@ -3,7 +3,7 @@ package coffee.liz.abstractionengine.app.screen;
import coffee.liz.abstractionengine.app.AbstractionEngineGame;
import coffee.liz.abstractionengine.app.screen.game.FrameState;
import coffee.liz.abstractionengine.app.screen.game.GameScreenWorld;
-import coffee.liz.abstractionengine.app.screen.game.system.GameWorldManagementSystem;
+import coffee.liz.abstractionengine.app.screen.game.system.GridWorldBridgeSystem;
import coffee.liz.abstractionengine.app.screen.game.system.RenderSystem;
import coffee.liz.abstractionengine.app.utils.FunctionUtils;
import coffee.liz.ecs.math.Vec2;
@@ -17,54 +17,54 @@ import java.time.Duration;
@RequiredArgsConstructor
public class GameScreen implements Screen {
- private final AbstractionEngineGame game;
- private static final Vec2<Integer> GAME_GRID_SIZE = Vec2i.builder().x(20).y(20).build();
+ private final AbstractionEngineGame game;
+ private static final Vec2<Integer> GAME_GRID_SIZE = Vec2i.builder().x(20).y(20).build();
- private GameScreenWorld outerWorld;
- private FitViewport viewport;
- private RenderSystem renderSystem;
+ private GameScreenWorld outerWorld;
+ private FitViewport viewport;
+ private RenderSystem renderSystem;
- @Override
- public void show() {
- viewport = new FitViewport(AbstractionEngineGame.WORLD_SIZE.getX(), AbstractionEngineGame.WORLD_SIZE.getY());
- outerWorld = new GameScreenWorld(GAME_GRID_SIZE, viewport, game.settings);
- outerWorld.getSystem(GameWorldManagementSystem.class).populateLevel();
- renderSystem = outerWorld.getSystem(RenderSystem.class);
- Gdx.input.setInputProcessor(renderSystem.getInputProcessor());
- viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
- renderSystem.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
- render(0);
- }
+ @Override
+ public void show() {
+ viewport = new FitViewport(AbstractionEngineGame.WORLD_SIZE.getX(), AbstractionEngineGame.WORLD_SIZE.getY());
+ outerWorld = new GameScreenWorld(GAME_GRID_SIZE, viewport, game.settings);
+ outerWorld.getSystem(GridWorldBridgeSystem.class).initLevel();
+ renderSystem = outerWorld.getSystem(RenderSystem.class);
+ Gdx.input.setInputProcessor(renderSystem.getInputProcessor());
+ viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
+ renderSystem.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
+ render(0);
+ }
- @Override
- public void render(final float delta) {
- viewport.apply();
- final FrameState state = FrameState.builder().settings(game.settings).isKeyPressed(Gdx.input::isKeyPressed)
- .build();
- outerWorld.update(state, Duration.ofMillis((long) (delta * 1000)));
- }
+ @Override
+ public void render(final float delta) {
+ viewport.apply();
+ final FrameState state = FrameState.builder().settings(game.settings).isKeyPressed(Gdx.input::isKeyPressed)
+ .build();
+ outerWorld.update(state, Duration.ofMillis((long) (delta * 1000)));
+ }
- @Override
- public void resize(final int width, final int height) {
- viewport.update(width, height, true);
- renderSystem.resize(width, height);
- }
+ @Override
+ public void resize(final int width, final int height) {
+ viewport.update(width, height, true);
+ renderSystem.resize(width, height);
+ }
- @Override
- public void pause() {
- }
+ @Override
+ public void pause() {
+ }
- @Override
- public void resume() {
- }
+ @Override
+ public void resume() {
+ }
- @Override
- public void hide() {
- dispose();
- }
+ @Override
+ public void hide() {
+ dispose();
+ }
- @Override
- public void dispose() {
- FunctionUtils.wrapCheckedException(outerWorld::close);
- }
+ @Override
+ public void dispose() {
+ FunctionUtils.wrapCheckedException(outerWorld::close);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java
index 30cc01f..46b5192 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java
@@ -29,140 +29,140 @@ import java.util.Set;
@RequiredArgsConstructor
public class MainMenu implements Screen {
- public static final Vec2<Integer> GRID_DIMENSIONS = Vec2i.builder().x(50).y(50).build();
+ public static final Vec2<Integer> GRID_DIMENSIONS = Vec2i.builder().x(50).y(50).build();
- private static final Vec2<Float> BUTTON_SIZE = AbstractionEngineGame.WORLD_SIZE.scale(1 / 4f, 1 / 15f);
- private static final float PARALLAX_STRENGTH = 3f;
+ private static final Vec2<Float> BUTTON_SIZE = AbstractionEngineGame.WORLD_SIZE.scale(1 / 4f, 1 / 15f);
+ private static final float PARALLAX_STRENGTH = 3f;
- private final World<LifeInput> world = new DAGWorld<>(Map.of(LifeSystem.class, new LifeSystem(GRID_DIMENSIONS),
- EntropyAudioSystem.class, new EntropyAudioSystem()));
- private final AbstractionEngineGame game;
+ private final World<LifeInput> world = new DAGWorld<>(Map.of(LifeSystem.class, new LifeSystem(GRID_DIMENSIONS),
+ EntropyAudioSystem.class, new EntropyAudioSystem()));
+ private final AbstractionEngineGame game;
- private final Set<Vec2<Integer>> initialAlive = createGliderPattern();
+ private final Set<Vec2<Integer>> initialAlive = createGliderPattern();
- private Stage stage;
- private LifeGridActor lifeGridActor;
+ private Stage stage;
+ private LifeGridActor lifeGridActor;
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void show() {
- Mat2.init(GRID_DIMENSIONS, pos -> world.createEntity().add(new GridPosition(pos))
- .add(initialAlive.contains(pos) ? CellState.LIVE : CellState.DEAD));
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void show() {
+ Mat2.init(GRID_DIMENSIONS, pos -> world.createEntity().add(new GridPosition(pos))
+ .add(initialAlive.contains(pos) ? CellState.LIVE : CellState.DEAD));
- stage = new Stage(game.viewport, game.batch);
- lifeGridActor = new LifeGridActor(game.shapeRenderer, world, GRID_DIMENSIONS, game.settings);
- lifeGridActor.setViewport(game.viewport);
- stage.addActor(lifeGridActor);
+ stage = new Stage(game.viewport, game.batch);
+ lifeGridActor = new LifeGridActor(game.shapeRenderer, world, GRID_DIMENSIONS, game.settings);
+ lifeGridActor.setViewport(game.viewport);
+ stage.addActor(lifeGridActor);
- final Button playButton = createButton("play", (game.viewport.getWorldWidth() - BUTTON_SIZE.getX()) / 2f,
- (game.viewport.getWorldHeight() - BUTTON_SIZE.getY()) / 2f);
- playButton.setOnClick(() -> game.setScreen(new GameScreen(game)));
- stage.addActor(playButton);
+ final Button playButton = createButton("play", (game.viewport.getWorldWidth() - BUTTON_SIZE.getX()) / 2f,
+ (game.viewport.getWorldHeight() - BUTTON_SIZE.getY()) / 2f);
+ playButton.setOnClick(() -> game.setScreen(new GameScreen(game)));
+ stage.addActor(playButton);
- Gdx.input.setInputProcessor(stage);
- }
+ Gdx.input.setInputProcessor(stage);
+ }
- private Button createButton(final String text, final float x, final float y) {
- final Button button = new Button(game.shapeRenderer, game.font, text);
- button.setPosition(x, y);
- button.setSize(BUTTON_SIZE.getX(), BUTTON_SIZE.getY());
- button.addButtonListener();
- return button;
- }
+ private Button createButton(final String text, final float x, final float y) {
+ final Button button = new Button(game.shapeRenderer, game.font, text);
+ button.setPosition(x, y);
+ button.setSize(BUTTON_SIZE.getX(), BUTTON_SIZE.getY());
+ button.addButtonListener();
+ return button;
+ }
- private static Set<Vec2<Integer>> createGliderPattern() {
- final int[][] downRight = {{0, 1, 0}, {0, 1, 1}, {1, 0, 1}};
- final int[][] downLeft = {{0, 1, 0}, {1, 1, 0}, {1, 0, 1}};
- final int[][] upRight = {{1, 0, 1}, {0, 1, 1}, {0, 1, 0}};
- final int[][] upLeft = {{1, 0, 1}, {1, 1, 0}, {0, 1, 0}};
+ private static Set<Vec2<Integer>> createGliderPattern() {
+ final int[][] downRight = {{0, 1, 0}, {0, 1, 1}, {1, 0, 1}};
+ final int[][] downLeft = {{0, 1, 0}, {1, 1, 0}, {1, 0, 1}};
+ final int[][] upRight = {{1, 0, 1}, {0, 1, 1}, {0, 1, 0}};
+ final int[][] upLeft = {{1, 0, 1}, {1, 1, 0}, {0, 1, 0}};
- final Set<Vec2<Integer>> pattern = new HashSet<>();
- stamp(pattern, upRight, 2, 2);
- stamp(pattern, upLeft, GRID_DIMENSIONS.getX() - 5, 2);
- stamp(pattern, downRight, 2, GRID_DIMENSIONS.getY() - 5);
- stamp(pattern, downLeft, GRID_DIMENSIONS.getX() - 5, GRID_DIMENSIONS.getY() - 5);
- return pattern;
- }
+ final Set<Vec2<Integer>> pattern = new HashSet<>();
+ stamp(pattern, upRight, 2, 2);
+ stamp(pattern, upLeft, GRID_DIMENSIONS.getX() - 5, 2);
+ stamp(pattern, downRight, 2, GRID_DIMENSIONS.getY() - 5);
+ stamp(pattern, downLeft, GRID_DIMENSIONS.getX() - 5, GRID_DIMENSIONS.getY() - 5);
+ return pattern;
+ }
- private static void stamp(final Set<Vec2<Integer>> cells, final int[][] pattern, final int offsetX,
- final int offsetY) {
- for (int y = 0; y < pattern.length; y++)
- for (int x = 0; x < pattern[y].length; x++)
- if (pattern[y][x] == 1)
- cells.add(Vec2i.builder().x(offsetX + x).y(offsetY + y).build());
- }
+ private static void stamp(final Set<Vec2<Integer>> cells, final int[][] pattern, final int offsetX,
+ final int offsetY) {
+ for (int y = 0; y < pattern.length; y++)
+ for (int x = 0; x < pattern[y].length; x++)
+ if (pattern[y][x] == 1)
+ cells.add(Vec2i.builder().x(offsetX + x).y(offsetY + y).build());
+ }
- /**
- * Screen render hook.
- *
- * @param delta
- * time since last frame
- */
- @Override
- public void render(final float delta) {
- game.viewport.apply();
+ /**
+ * Screen render hook.
+ *
+ * @param delta
+ * time since last frame
+ */
+ @Override
+ public void render(final float delta) {
+ game.viewport.apply();
- ScreenUtils.clear(Theme.BG);
+ ScreenUtils.clear(Theme.BG);
- updateParallax();
- stage.act(delta);
+ updateParallax();
+ stage.act(delta);
- stage.draw();
- }
+ stage.draw();
+ }
- private void updateParallax() {
- final Vector3 cursor = game.viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
- final Vec2<Float> worldSize = Vec2f.builder().x(game.viewport.getWorldWidth()).y(game.viewport.getWorldHeight())
- .build();
- final Vec2<Float> normalized = Vec2f.builder().x(cursor.x).y(cursor.y).build()
- .scale(worldSize.transform(x -> 1f / x, y -> 1f / y)).transform(x -> x - 0.5f, y -> y - 0.5f);
- final Vec2<Float> parallax = normalized.scale(-PARALLAX_STRENGTH, -PARALLAX_STRENGTH);
- lifeGridActor.setParallaxOffset(parallax);
- }
+ private void updateParallax() {
+ final Vector3 cursor = game.viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
+ final Vec2<Float> worldSize = Vec2f.builder().x(game.viewport.getWorldWidth()).y(game.viewport.getWorldHeight())
+ .build();
+ final Vec2<Float> normalized = Vec2f.builder().x(cursor.x).y(cursor.y).build()
+ .scale(worldSize.transform(x -> 1f / x, y -> 1f / y)).transform(x -> x - 0.5f, y -> y - 0.5f);
+ final Vec2<Float> parallax = normalized.scale(-PARALLAX_STRENGTH, -PARALLAX_STRENGTH);
+ lifeGridActor.setParallaxOffset(parallax);
+ }
- /**
- * Screen resize hook.
- *
- * @param width
- * new width in pixels
- * @param height
- * new height in pixels
- */
- @Override
- public void resize(final int width, final int height) {
- game.viewport.update(width, height, true);
- }
+ /**
+ * Screen resize hook.
+ *
+ * @param width
+ * new width in pixels
+ * @param height
+ * new height in pixels
+ */
+ @Override
+ public void resize(final int width, final int height) {
+ game.viewport.update(width, height, true);
+ }
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void pause() {
- }
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void pause() {
+ }
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void resume() {
- }
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void resume() {
+ }
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void hide() {
- dispose();
- }
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void hide() {
+ dispose();
+ }
- /**
- * Screen cleanup hook.
- */
- @Override
- public void dispose() {
- FunctionUtils.wrapCheckedException(world::close);
- stage.dispose();
- }
+ /**
+ * Screen cleanup hook.
+ */
+ @Override
+ public void dispose() {
+ FunctionUtils.wrapCheckedException(world::close);
+ stage.dispose();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/ScrollLogo.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/ScrollLogo.java
index bb8aef2..c0183d3 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/ScrollLogo.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/ScrollLogo.java
@@ -15,138 +15,138 @@ import java.time.Duration;
@RequiredArgsConstructor
public class ScrollLogo implements Screen {
- private static final Duration SHOW_FOR = Duration.ofSeconds(7);
- private static final float LOGO_HEIGHT = 70f;
- private static final float PENGUIN_SIZE = 20f;
- private static final float SCROLL_PERCENT = 0.4f;
- private static final float EEPY_PERCENT = 0.3f;
- private static final float EEP_PERCENT = 0.15f;
- private static final float FADE_PERCENT = 0.15f;
+ private static final Duration SHOW_FOR = Duration.ofSeconds(7);
+ private static final float LOGO_HEIGHT = 70f;
+ private static final float PENGUIN_SIZE = 20f;
+ private static final float SCROLL_PERCENT = 0.4f;
+ private static final float EEPY_PERCENT = 0.3f;
+ private static final float EEP_PERCENT = 0.15f;
+ private static final float FADE_PERCENT = 0.15f;
- private final AbstractionEngineGame game;
+ private final AbstractionEngineGame game;
- private Stage stage;
- private Logo logo;
- private Penguin penguin;
- private Group animationGroup;
+ private Stage stage;
+ private Logo logo;
+ private Penguin penguin;
+ private Group animationGroup;
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void show() {
- stage = new Stage(game.viewport, game.batch);
- logo = new Logo();
- penguin = new Penguin();
- animationGroup = new Group();
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void show() {
+ stage = new Stage(game.viewport, game.batch);
+ logo = new Logo();
+ penguin = new Penguin();
+ animationGroup = new Group();
- final float worldWidth = game.viewport.getWorldWidth();
- final float worldHeight = game.viewport.getWorldHeight();
- final float logoWidth = LOGO_HEIGHT * ((float) logo.getWidth() / logo.getHeight());
+ final float worldWidth = game.viewport.getWorldWidth();
+ final float worldHeight = game.viewport.getWorldHeight();
+ final float logoWidth = LOGO_HEIGHT * ((float) logo.getWidth() / logo.getHeight());
- logo.setSize(logoWidth, LOGO_HEIGHT);
- logo.setPosition(0, 0);
+ logo.setSize(logoWidth, LOGO_HEIGHT);
+ logo.setPosition(0, 0);
- penguin.setSize(PENGUIN_SIZE, PENGUIN_SIZE);
- penguin.setPosition((logoWidth - PENGUIN_SIZE) / 2f, -PENGUIN_SIZE - 6f);
- penguin.setState(Penguin.State.TOBAGGON);
+ penguin.setSize(PENGUIN_SIZE, PENGUIN_SIZE);
+ penguin.setPosition((logoWidth - PENGUIN_SIZE) / 2f, -PENGUIN_SIZE - 6f);
+ penguin.setState(Penguin.State.TOBAGGON);
- animationGroup.addActor(logo);
- animationGroup.addActor(penguin);
- animationGroup.setPosition((worldWidth - logoWidth) / 2f, worldHeight);
+ animationGroup.addActor(logo);
+ animationGroup.addActor(penguin);
+ animationGroup.setPosition((worldWidth - logoWidth) / 2f, worldHeight);
- stage.addActor(animationGroup);
+ stage.addActor(animationGroup);
- setupAnimations(worldWidth, worldHeight, logoWidth);
- }
+ setupAnimations(worldWidth, worldHeight, logoWidth);
+ }
- private void setupAnimations(final float worldWidth, final float worldHeight, final float logoWidth) {
- final float totalSeconds = SHOW_FOR.toMillis() / 1000f;
- final float scrollDuration = totalSeconds * SCROLL_PERCENT;
- final float eepyDuration = totalSeconds * EEPY_PERCENT;
- final float eepDuration = totalSeconds * EEP_PERCENT;
- final float fadeDuration = totalSeconds * FADE_PERCENT;
+ private void setupAnimations(final float worldWidth, final float worldHeight, final float logoWidth) {
+ final float totalSeconds = SHOW_FOR.toMillis() / 1000f;
+ final float scrollDuration = totalSeconds * SCROLL_PERCENT;
+ final float eepyDuration = totalSeconds * EEPY_PERCENT;
+ final float eepDuration = totalSeconds * EEP_PERCENT;
+ final float fadeDuration = totalSeconds * FADE_PERCENT;
- final float targetY = (worldHeight - LOGO_HEIGHT) / 2f;
+ final float targetY = (worldHeight - LOGO_HEIGHT) / 2f;
- animationGroup
- .addAction(Actions.sequence(Actions.moveTo((worldWidth - logoWidth) / 2f, targetY, scrollDuration),
- Actions.run(() -> penguin.setState(Penguin.State.EEPY)), Actions.delay(eepyDuration),
- Actions.run(() -> penguin.setState(Penguin.State.EEPING)), Actions.delay(eepDuration),
- Actions.fadeOut(fadeDuration), Actions.run(this::requestTransition)));
- }
+ animationGroup
+ .addAction(Actions.sequence(Actions.moveTo((worldWidth - logoWidth) / 2f, targetY, scrollDuration),
+ Actions.run(() -> penguin.setState(Penguin.State.EEPY)), Actions.delay(eepyDuration),
+ Actions.run(() -> penguin.setState(Penguin.State.EEPING)), Actions.delay(eepDuration),
+ Actions.fadeOut(fadeDuration), Actions.run(this::requestTransition)));
+ }
- /**
- * Screen render hook.
- *
- * @param delta
- * time since last frame
- */
- @Override
- public void render(final float delta) {
- game.viewport.apply();
- ScreenUtils.clear(Theme.BG);
- if (game.settings.isSkipIntro()) {
- requestTransition();
- return;
- }
+ /**
+ * Screen render hook.
+ *
+ * @param delta
+ * time since last frame
+ */
+ @Override
+ public void render(final float delta) {
+ game.viewport.apply();
+ ScreenUtils.clear(Theme.BG);
+ if (game.settings.isSkipIntro()) {
+ requestTransition();
+ return;
+ }
- stage.act(delta);
- stage.draw();
- }
+ stage.act(delta);
+ stage.draw();
+ }
- /**
- * Screen resize hook.
- *
- * @param width
- * new width in pixels
- * @param height
- * new height in pixels
- */
- @Override
- public void resize(final int width, final int height) {
- game.viewport.update(width, height, true);
- }
+ /**
+ * Screen resize hook.
+ *
+ * @param width
+ * new width in pixels
+ * @param height
+ * new height in pixels
+ */
+ @Override
+ public void resize(final int width, final int height) {
+ game.viewport.update(width, height, true);
+ }
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void pause() {
- }
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void pause() {
+ }
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void resume() {
- }
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void resume() {
+ }
- /**
- * Screen lifecycle hook.
- */
- @Override
- public void hide() {
- dispose();
- }
+ /**
+ * Screen lifecycle hook.
+ */
+ @Override
+ public void hide() {
+ dispose();
+ }
- /**
- * Screen cleanup hook.
- */
- @Override
- public void dispose() {
- if (logo != null) {
- logo.dispose();
- }
- if (penguin != null) {
- penguin.dispose();
- }
- if (stage != null) {
- stage.dispose();
- }
- }
+ /**
+ * Screen cleanup hook.
+ */
+ @Override
+ public void dispose() {
+ if (logo != null) {
+ logo.dispose();
+ }
+ if (penguin != null) {
+ penguin.dispose();
+ }
+ if (stage != null) {
+ stage.dispose();
+ }
+ }
- private void requestTransition() {
- game.setScreen(new MainMenu(game));
- }
+ private void requestTransition() {
+ game.setScreen(new MainMenu(game));
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/FrameState.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/FrameState.java
index 3f31530..275771f 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/FrameState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/FrameState.java
@@ -11,6 +11,6 @@ import java.util.function.Predicate;
@Getter
@RequiredArgsConstructor
public final class FrameState {
- private final Settings settings;
- private final Predicate<Integer> isKeyPressed;
+ private final Settings settings;
+ private final Predicate<Integer> isKeyPressed;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java
index a0c0b5b..137a5b0 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java
@@ -1,7 +1,7 @@
package coffee.liz.abstractionengine.app.screen.game;
import coffee.liz.abstractionengine.app.config.Settings;
-import coffee.liz.abstractionengine.app.screen.game.system.GameWorldManagementSystem;
+import coffee.liz.abstractionengine.app.screen.game.system.GridWorldBridgeSystem;
import coffee.liz.abstractionengine.app.screen.game.system.GridInterpolationSystem;
import coffee.liz.abstractionengine.app.screen.game.system.InputSystem;
import coffee.liz.abstractionengine.app.screen.game.system.RenderSystem;
@@ -12,9 +12,9 @@ import com.badlogic.gdx.utils.viewport.FitViewport;
import java.util.Map;
public class GameScreenWorld extends DAGWorld<FrameState> {
- public GameScreenWorld(final Vec2<Integer> gridSize, final FitViewport viewport, final Settings settings) {
- super(Map.of(InputSystem.class, new InputSystem(), GameWorldManagementSystem.class,
- new GameWorldManagementSystem(gridSize), GridInterpolationSystem.class, new GridInterpolationSystem(),
- RenderSystem.class, new RenderSystem(viewport, gridSize, settings)));
- }
+ public GameScreenWorld(final Vec2<Integer> gridSize, final FitViewport viewport, final Settings settings) {
+ super(Map.of(InputSystem.class, new InputSystem(), GridWorldBridgeSystem.class,
+ new GridWorldBridgeSystem(gridSize), GridInterpolationSystem.class, new GridInterpolationSystem(),
+ RenderSystem.class, new RenderSystem(viewport, gridSize, settings)));
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/GridEntityRef.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ActorHolder.java
index 788d530..ad9c432 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/GridEntityRef.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ActorHolder.java
@@ -1,11 +1,12 @@
package coffee.liz.abstractionengine.app.screen.game.component;
import coffee.liz.ecs.model.Component;
+import com.badlogic.gdx.scenes.scene2d.Actor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
-@RequiredArgsConstructor
@Getter
-public final class GridEntityRef implements Component {
- private final int gridEntityId;
+@RequiredArgsConstructor
+public class ActorHolder implements Component {
+ private final Actor actor;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ExternalWorldEntityRef.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ExternalWorldEntityRef.java
new file mode 100644
index 0000000..a544a70
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/ExternalWorldEntityRef.java
@@ -0,0 +1,12 @@
+package coffee.liz.abstractionengine.app.screen.game.component;
+
+import coffee.liz.ecs.model.Component;
+import coffee.liz.ecs.model.Entity;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public final class ExternalWorldEntityRef implements Component {
+ private final Entity entity;
+}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/InterpolatedPosition.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/InterpolatedPosition.java
deleted file mode 100644
index 6700575..0000000
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/component/InterpolatedPosition.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package coffee.liz.abstractionengine.app.screen.game.component;
-
-import coffee.liz.ecs.math.Vec2;
-import coffee.liz.ecs.model.Component;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@Getter
-public final class InterpolatedPosition implements Component {
- private final Vec2<Float> from;
- private final Vec2<Float> to;
- private final Vec2<Float> current;
-
- public static InterpolatedPosition atRest(final Vec2<Float> position) {
- return new InterpolatedPosition(position, position, position);
- }
-}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GameWorldManagementSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GameWorldManagementSystem.java
deleted file mode 100644
index 74355d1..0000000
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GameWorldManagementSystem.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package coffee.liz.abstractionengine.app.screen.game.system;
-
-import coffee.liz.abstractionengine.AbstractionEngineGridWorld;
-import coffee.liz.abstractionengine.app.screen.game.FrameState;
-import coffee.liz.abstractionengine.app.screen.game.component.GridEntityRef;
-import coffee.liz.abstractionengine.app.screen.game.component.InterpolatedPosition;
-import coffee.liz.abstractionengine.app.utils.FunctionUtils;
-import coffee.liz.abstractionengine.entity.EntityFactory;
-import coffee.liz.abstractionengine.entity.EntityType;
-import coffee.liz.abstractionengine.grid.component.GridInputState;
-import coffee.liz.abstractionengine.grid.component.GridPosition;
-import coffee.liz.ecs.math.Vec2;
-import coffee.liz.ecs.math.Vec2i;
-import coffee.liz.ecs.model.Entity;
-import coffee.liz.ecs.model.System;
-import coffee.liz.ecs.model.World;
-import lombok.Getter;
-
-import java.time.Duration;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class GameWorldManagementSystem implements System<FrameState> {
- private final AbstractionEngineGridWorld gridWorld;
- private final Vec2<Integer> gridSize;
- private final Map<Integer, Entity> gridToOuterMap = new HashMap<>();
-
- @Getter
- private boolean stepped = false;
-
- public GameWorldManagementSystem(final Vec2<Integer> gridSize) {
- this.gridSize = gridSize;
- this.gridWorld = new AbstractionEngineGridWorld(gridSize);
- }
-
- public void populateLevel() {
- EntityFactory.populateRect(gridSize, gridWorld, EntityFactory.Wall::addToWorld);
- EntityFactory.Player.addToWorld(gridWorld, Vec2i.builder().y(10).x(10).build());
- EntityFactory.Abstraction.addToWorld(gridWorld, Vec2i.builder().y(10).x(12).build());
- EntityFactory.Abstraction.addToWorld(gridWorld, Vec2i.builder().y(10).x(13).build());
- gridWorld.update(GridInputState.builder().movement(Vec2i.ZERO).build());
- }
-
- @Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
- return Set.of(InputSystem.class);
- }
-
- @Override
- public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
- final InputSystem inputSystem = world.getSystem(InputSystem.class);
- final Vec2<Integer> movement = inputSystem.getStepMovement();
-
- stepped = !movement.equals(Vec2i.ZERO);
- if (stepped) {
- final GridInputState gridInput = GridInputState.builder().movement(movement).build();
- gridWorld.update(gridInput);
- }
-
- syncEntities(world);
- }
-
- private void syncEntities(final World<FrameState> outerWorld) {
- final Set<Entity> gridEntities = gridWorld.query(Set.of(GridPosition.class, EntityType.class));
- final Set<Integer> seenGridIds = new HashSet<>();
-
- for (final Entity gridEntity : gridEntities) {
- seenGridIds.add(gridEntity.getId());
-
- if (!gridToOuterMap.containsKey(gridEntity.getId())) {
- final Entity outer = outerWorld.createEntity();
- final Vec2<Float> pos = gridEntity.get(GridPosition.class).getPosition().floatValue();
- outer.add(new GridEntityRef(gridEntity.getId()));
- outer.add(gridEntity.get(EntityType.class));
- outer.add(InterpolatedPosition.atRest(pos));
- gridToOuterMap.put(gridEntity.getId(), outer);
- } else if (stepped) {
- final Entity outer = gridToOuterMap.get(gridEntity.getId());
- final InterpolatedPosition current = outer.get(InterpolatedPosition.class);
- final Vec2<Float> newTarget = gridEntity.get(GridPosition.class).getPosition().floatValue();
- outer.add(new InterpolatedPosition(current.getCurrent(), newTarget, current.getCurrent()));
- }
- }
-
- final Set<Integer> removedIds = new HashSet<>(gridToOuterMap.keySet());
- removedIds.removeAll(seenGridIds);
- for (final int removedId : removedIds) {
- final Entity outer = gridToOuterMap.remove(removedId);
- outerWorld.removeEntity(outer);
- }
- }
-
- @Override
- public void close() {
- FunctionUtils.wrapCheckedException(gridWorld::close);
- }
-}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java
index 2e4826d..0d2d34b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java
@@ -1,9 +1,13 @@
package coffee.liz.abstractionengine.app.screen.game.system;
import coffee.liz.abstractionengine.app.screen.game.FrameState;
-import coffee.liz.abstractionengine.app.screen.game.component.InterpolatedPosition;
+import coffee.liz.abstractionengine.app.screen.game.component.ActorHolder;
+import coffee.liz.abstractionengine.app.screen.game.component.ExternalWorldEntityRef;
+import coffee.liz.abstractionengine.entity.EntityType;
+import coffee.liz.abstractionengine.grid.component.GridPosition;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2f;
+import coffee.liz.ecs.model.Entity;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
@@ -11,36 +15,56 @@ import java.time.Duration;
import java.util.Collection;
import java.util.Set;
+import com.badlogic.gdx.math.Interpolation;
+import com.badlogic.gdx.scenes.scene2d.Actor;
+import com.badlogic.gdx.scenes.scene2d.actions.MoveToAction;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
public class GridInterpolationSystem implements System<FrameState> {
- private static final Duration INTERPOLATION_TIME = Duration.ofMillis(50);
+ private static final Duration INTERPOLATION_TIME = Duration.ofMillis(60);
- private Duration elapsed = Duration.ZERO;
+ @Override
+ public Collection<Class<? extends System<FrameState>>> getDependencies() {
+ return Set.of(GridWorldBridgeSystem.class);
+ }
- @Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
- return Set.of(GameWorldManagementSystem.class);
- }
+ @Override
+ public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
+ final GridWorldBridgeSystem bridgeSystem = world.getSystem(GridWorldBridgeSystem.class);
- @Override
- public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
- final GameWorldManagementSystem gameWorldSystem = world.getSystem(GameWorldManagementSystem.class);
+ world.query(Set.of(ExternalWorldEntityRef.class, ActorHolder.class)).forEach(entity -> {
+ final Actor actor = entity.get(ActorHolder.class).getActor();
+ final boolean isAlreadyInterpolating = !actor.getActions().isEmpty();
+ if (isAlreadyInterpolating) {
+ return;
+ }
- if (gameWorldSystem.isStepped()) {
- elapsed = Duration.ZERO;
- }
+ final Entity ref = entity.get(ExternalWorldEntityRef.class).getEntity();
+ if (!ref.has(GridPosition.class)) {
+ return;
+ }
- elapsed = elapsed.plus(dt);
- final float t = Math.min(1.0f, (float) elapsed.toMillis() / INTERPOLATION_TIME.toMillis());
+ final Vec2<Float> position = Vec2f.builder().x(actor.getX()).y(actor.getY()).build();
+ final GridPosition gridPosition = ref.get(GridPosition.class);
+ final Vec2<Float> target = gridPosition.getPosition().floatValue().scale(bridgeSystem.getGridToWorld());
+ final boolean isAtTarget = target.minus(position).length() < 0.05;
+ if (isAtTarget) {
+ return;
+ }
- world.query(Set.of(InterpolatedPosition.class)).forEach(entity -> {
- final InterpolatedPosition pos = entity.get(InterpolatedPosition.class);
- final Vec2<Float> interpolated = lerp(pos.getFrom(), pos.getTo(), t);
- entity.add(new InterpolatedPosition(pos.getFrom(), pos.getTo(), interpolated));
- });
- }
+ final MoveToAction momentumAction = new MoveToAction();
+ momentumAction.setInterpolation(interpolationType(ref.get(EntityType.class)));
+ momentumAction.setPosition(target.getX(), target.getY());
+ momentumAction.setDuration(INTERPOLATION_TIME.toMillis() / 1000f);
+ actor.addAction(momentumAction);
+ });
+ }
- private static Vec2<Float> lerp(final Vec2<Float> from, final Vec2<Float> to, final float t) {
- return Vec2f.builder().x(from.getX() + (to.getX() - from.getX()) * t)
- .y(from.getY() + (to.getY() - from.getY()) * t).build();
- }
+ private Interpolation interpolationType(final EntityType type) {
+ return switch(type) {
+ case PLAYER -> Interpolation.pow3;
+ default -> new Interpolation.Swing(1.15f);
+ };
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java
new file mode 100644
index 0000000..52a21a6
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java
@@ -0,0 +1,119 @@
+package coffee.liz.abstractionengine.app.screen.game.system;
+
+import coffee.liz.abstractionengine.AbstractionEngineGridWorld;
+import coffee.liz.abstractionengine.app.AbstractionEngineGame;
+import coffee.liz.abstractionengine.app.actor.Abstraction;
+import coffee.liz.abstractionengine.app.actor.Penguin;
+import coffee.liz.abstractionengine.app.actor.Player;
+import coffee.liz.abstractionengine.app.actor.Wall;
+import coffee.liz.abstractionengine.app.screen.game.FrameState;
+import coffee.liz.abstractionengine.app.screen.game.component.ActorHolder;
+import coffee.liz.abstractionengine.app.screen.game.component.ExternalWorldEntityRef;
+import coffee.liz.abstractionengine.app.utils.FunctionUtils;
+import coffee.liz.abstractionengine.entity.EntityFactory;
+import coffee.liz.abstractionengine.entity.EntityType;
+import coffee.liz.abstractionengine.grid.component.GridInputState;
+import coffee.liz.abstractionengine.grid.component.GridPosition;
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.System;
+import coffee.liz.ecs.model.World;
+import lombok.Getter;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.badlogic.gdx.scenes.scene2d.Actor;
+import com.badlogic.gdx.scenes.scene2d.Stage;
+
+public class GridWorldBridgeSystem implements System<FrameState> {
+ private final Map<Integer, Entity> outerIdToInnerEntity = new HashMap<>();
+ private final AbstractionEngineGridWorld outerWorld;
+ private final Vec2<Integer> gridSize;
+
+ @Getter
+ private final Vec2<Float> gridToWorld;
+ @Getter
+ private final Vec2<Float> worldToGrid;
+
+ public GridWorldBridgeSystem(final Vec2<Integer> gridSize) {
+ this.gridSize = gridSize;
+ this.outerWorld = new AbstractionEngineGridWorld(gridSize);
+
+ this.gridToWorld = AbstractionEngineGame.WORLD_SIZE.scale(gridSize.floatValue().transform(x -> 1f / x, y -> 1f / y));
+ this.worldToGrid = gridSize.floatValue().scale(AbstractionEngineGame.WORLD_SIZE.floatValue().transform(x -> 1f/x, y -> 1f/y));
+ }
+
+ public void initLevel() {
+ EntityFactory.populateRect(gridSize, outerWorld, EntityFactory.Wall::addToWorld);
+ EntityFactory.Player.addToWorld(outerWorld, Vec2i.builder().y(10).x(10).build());
+ EntityFactory.Abstraction.addToWorld(outerWorld, Vec2i.builder().y(10).x(12).build());
+ EntityFactory.Abstraction.addToWorld(outerWorld, Vec2i.builder().y(10).x(13).build());
+ outerWorld.update(GridInputState.builder().movement(Vec2i.ZERO).build());
+ }
+
+ @Override
+ public Collection<Class<? extends System<FrameState>>> getDependencies() {
+ return Set.of(InputSystem.class);
+ }
+
+ @Override
+ public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
+ final InputSystem inputSystem = world.getSystem(InputSystem.class);
+ final GridInputState gridInputState = inputSystem.getGridInputState();
+ outerWorld.update(gridInputState);
+ syncEntities(world);
+ }
+
+ private void syncEntities(final World<FrameState> world) {
+ final Set<Entity> gridEntities = outerWorld.query(Set.of(GridPosition.class, EntityType.class));
+ final Set<Integer> seenGridIds = new HashSet<>();
+
+ for (final Entity gridEntity : gridEntities) {
+ seenGridIds.add(gridEntity.getId());
+
+ final boolean isNewEntity = !outerIdToInnerEntity.containsKey(gridEntity.getId());
+ if (!isNewEntity) {
+ continue;
+ }
+
+ final Entity outer = world.createEntity();
+ outer.add(new ActorHolder(
+ createActor(gridEntity.get(EntityType.class), world.getSystem(RenderSystem.class).getStage())));
+ outer.add(new ExternalWorldEntityRef(gridEntity));
+ outer.add(gridEntity.get(EntityType.class));
+ outerIdToInnerEntity.put(gridEntity.getId(), outer);
+ }
+
+ final Set<Integer> outerRemoved = gridEntities.stream().map(Entity::getId)
+ .filter(id -> !seenGridIds.contains(id)).collect(Collectors.toSet());
+
+ for (final int removedId : outerRemoved) {
+ world.removeEntity(outerIdToInnerEntity.get(removedId));
+ outerIdToInnerEntity.remove(removedId);
+ }
+ }
+
+ @Override
+ public void close() {
+ FunctionUtils.wrapCheckedException(outerWorld::close);
+ }
+
+ private Actor createActor(final EntityType type, final Stage stage) {
+ final Actor actor = switch (type) {
+ case PLAYER -> new Penguin();
+ case ABSTRACTION -> new Abstraction();
+ case WALL -> new Wall();
+ default -> throw new UnsupportedOperationException();
+ };
+ actor.setBounds(0, 0, getGridToWorld().getX(), getGridToWorld().getX());
+ stage.addActor(actor);
+ return actor;
+ }
+}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/InputSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/InputSystem.java
index b311221..b8e3782 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/InputSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/InputSystem.java
@@ -2,73 +2,75 @@ package coffee.liz.abstractionengine.app.screen.game.system;
import coffee.liz.abstractionengine.app.config.KeyBinds;
import coffee.liz.abstractionengine.app.screen.game.FrameState;
+import coffee.liz.abstractionengine.grid.component.GridInputState;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2i;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
-import lombok.Getter;
import java.time.Duration;
import java.util.Collection;
import java.util.Set;
public class InputSystem implements System<FrameState> {
- private static final Duration INITIAL_DELAY = Duration.ofMillis(200);
- private static final Duration REPEAT_INTERVAL = Duration.ofMillis(80);
+ private static final Duration INITIAL_DELAY = Duration.ofMillis(200);
+ private static final Duration REPEAT_INTERVAL = Duration.ofMillis(80);
- private KeyBinds.Action heldAction = null;
- private Duration heldTime = Duration.ZERO;
- private boolean pastInitialDelay = false;
+ private KeyBinds.Action heldAction = null;
+ private Duration heldTime = Duration.ZERO;
+ private boolean pastInitialDelay = false;
+ private Vec2<Integer> stepMovement = Vec2i.ZERO;
- @Getter
- private Vec2<Integer> stepMovement = Vec2i.ZERO;
+ public GridInputState getGridInputState() {
+ return GridInputState.builder().movement(stepMovement).build();
+ }
- @Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
- return Set.of();
- }
+ @Override
+ public Collection<Class<? extends System<FrameState>>> getDependencies() {
+ return Set.of();
+ }
- @Override
- public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
- final Set<KeyBinds.Action> currentlyActive = state.getSettings().getKeyBinds()
- .filterActiveActions(state.getIsKeyPressed());
+ @Override
+ public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
+ final Set<KeyBinds.Action> currentlyActive = state.getSettings().getKeyBinds()
+ .filterActiveActions(state.getIsKeyPressed());
- if (currentlyActive.isEmpty()) {
- heldAction = null;
- stepMovement = Vec2i.ZERO;
- return;
- }
+ if (currentlyActive.isEmpty()) {
+ heldAction = null;
+ stepMovement = Vec2i.ZERO;
+ return;
+ }
- final KeyBinds.Action active = currentlyActive.contains(heldAction)
- ? heldAction
- : currentlyActive.iterator().next();
+ final KeyBinds.Action active = currentlyActive.contains(heldAction)
+ ? heldAction
+ : currentlyActive.iterator().next();
- if (!active.equals(heldAction)) {
- heldAction = active;
- heldTime = Duration.ZERO;
- pastInitialDelay = false;
- stepMovement = actionToMovement(active);
- } else {
- heldTime = heldTime.plus(dt);
- if (!pastInitialDelay && heldTime.compareTo(INITIAL_DELAY) >= 0) {
- pastInitialDelay = true;
- heldTime = heldTime.minus(INITIAL_DELAY);
- stepMovement = actionToMovement(active);
- } else if (pastInitialDelay && heldTime.compareTo(REPEAT_INTERVAL) >= 0) {
- heldTime = heldTime.minus(REPEAT_INTERVAL);
- stepMovement = actionToMovement(active);
- } else {
- stepMovement = Vec2i.ZERO;
- }
- }
- }
+ if (!active.equals(heldAction)) {
+ heldAction = active;
+ heldTime = Duration.ZERO;
+ pastInitialDelay = false;
+ stepMovement = actionToMovement(active);
+ } else {
+ heldTime = heldTime.plus(dt);
+ if (!pastInitialDelay && heldTime.compareTo(INITIAL_DELAY) >= 0) {
+ pastInitialDelay = true;
+ heldTime = heldTime.minus(INITIAL_DELAY);
+ stepMovement = actionToMovement(active);
+ } else if (pastInitialDelay && heldTime.compareTo(REPEAT_INTERVAL) >= 0) {
+ heldTime = heldTime.minus(REPEAT_INTERVAL);
+ stepMovement = actionToMovement(active);
+ } else {
+ stepMovement = Vec2i.ZERO;
+ }
+ }
+ }
- private static Vec2<Integer> actionToMovement(final KeyBinds.Action action) {
- return switch (action) {
- case MOVE_UP -> Vec2i.NORTH;
- case MOVE_DOWN -> Vec2i.SOUTH;
- case MOVE_LEFT -> Vec2i.WEST;
- case MOVE_RIGHT -> Vec2i.EAST;
- };
- }
+ private static Vec2<Integer> actionToMovement(final KeyBinds.Action action) {
+ return switch (action) {
+ case MOVE_UP -> Vec2i.NORTH;
+ case MOVE_DOWN -> Vec2i.SOUTH;
+ case MOVE_LEFT -> Vec2i.WEST;
+ case MOVE_RIGHT -> Vec2i.EAST;
+ };
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java
index 9a839d8..0bb4f54 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java
@@ -1,16 +1,15 @@
package coffee.liz.abstractionengine.app.screen.game.system;
import coffee.liz.abstractionengine.app.Theme;
-import coffee.liz.abstractionengine.app.actor.GridBoardActor;
import coffee.liz.abstractionengine.app.config.Settings;
import coffee.liz.abstractionengine.app.screen.game.FrameState;
-import coffee.liz.abstractionengine.app.screen.game.component.InterpolatedPosition;
import coffee.liz.abstractionengine.app.ui.editor.LambdaEditor;
-import coffee.liz.abstractionengine.entity.EntityType;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
+import lombok.Getter;
+
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
@@ -22,83 +21,82 @@ import com.kotcrab.vis.ui.VisUI;
import java.time.Duration;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
public class RenderSystem implements System<FrameState> {
- private final FitViewport viewport;
- private final Vec2<Integer> gridSize;
- private final ShapeRenderer shapeRenderer;
- private final Stage stage;
- private final Stage uiStage;
- private final GridBoardActor boardActor;
- private final InputMultiplexer inputMultiplexer;
+ private final FitViewport viewport;
+ private final Vec2<Integer> gridSize;
+ private final ShapeRenderer shapeRenderer;
+ @Getter
+ private final Stage stage;
+ private final Stage uiStage;
+ private final InputMultiplexer inputMultiplexer;
- public RenderSystem(final FitViewport viewport, final Vec2<Integer> gridSize, final Settings settings) {
- this.viewport = viewport;
- this.gridSize = gridSize;
- this.shapeRenderer = new ShapeRenderer();
- this.stage = new Stage(viewport);
- this.boardActor = new GridBoardActor(shapeRenderer, gridSize);
+ public RenderSystem(final FitViewport viewport, final Vec2<Integer> gridSize, final Settings settings) {
+ this.viewport = viewport;
+ this.gridSize = gridSize;
+ this.shapeRenderer = new ShapeRenderer();
+ this.stage = new Stage(viewport);
- stage.addActor(boardActor);
+ // stage.addActor(boardActor);
- VisUI.load();
- this.uiStage = new Stage(new ScreenViewport());
- uiStage.addActor(new LambdaEditor(settings.isVimMode()));
+ VisUI.load();
+ this.uiStage = new Stage(new ScreenViewport());
+ uiStage.addActor(new LambdaEditor(settings.isVimMode()));
- // TODO: Move this to an input system
- this.inputMultiplexer = new InputMultiplexer(uiStage, stage);
- }
+ // TODO: Move this to an input system
+ this.inputMultiplexer = new InputMultiplexer(uiStage, stage);
+ }
- public InputProcessor getInputProcessor() {
- return inputMultiplexer;
- }
+ public InputProcessor getInputProcessor() {
+ return inputMultiplexer;
+ }
- public void resize(final int width, final int height) {
- uiStage.getViewport().update(width, height, true);
- }
+ public void resize(final int width, final int height) {
+ uiStage.getViewport().update(width, height, true);
+ }
- @Override
- public Collection<Class<? extends System<FrameState>>> getDependencies() {
- return Set.of(GridInterpolationSystem.class);
- }
+ @Override
+ public Collection<Class<? extends System<FrameState>>> getDependencies() {
+ return Set.of(GridInterpolationSystem.class);
+ }
- @Override
- public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
- ScreenUtils.clear(Theme.BG);
+ @Override
+ public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
+ ScreenUtils.clear(Theme.BG);
- final Vec2<Float> cellSize = computeCellSize();
- final List<GridBoardActor.RenderableEntity> renderables = world
- .query(Set.of(InterpolatedPosition.class, EntityType.class)).stream().map(entity -> {
- final InterpolatedPosition pos = entity.get(InterpolatedPosition.class);
- final EntityType type = entity.get(EntityType.class);
- final Vec2<Float> drawPos = pos.getCurrent().scale(cellSize);
- return new GridBoardActor.RenderableEntity(type, drawPos, cellSize);
- }).toList();
+ final Vec2<Float> cellSize = computeCellSize();
+ // final List<GridBoardActor.RenderableEntity> renderables = world
+ // .query(Set.of(InterpolatedPosition.class,
+ // EntityType.class)).stream().map(entity -> {
+ // final InterpolatedPosition pos = entity.get(InterpolatedPosition.class);
+ // final EntityType type = entity.get(EntityType.class);
+ // final Vec2<Float> drawPos = pos.getCurrent().scale(cellSize);
+ // return new GridBoardActor.RenderableEntity(type, drawPos, cellSize);
+ // }).toList();
- boardActor.setCellSize(cellSize);
- boardActor.setEntities(renderables);
+ // boardActor.setCellSize(cellSize);
+ // boardActor.setEntities(renderables);
- final float deltaSeconds = dt.toMillis() / 1000f;
- stage.act(deltaSeconds);
- stage.draw();
+ final float deltaSeconds = dt.toMillis() / 1000f;
+ stage.act(deltaSeconds);
+ stage.draw();
- uiStage.getViewport().apply();
- uiStage.act(deltaSeconds);
- uiStage.draw();
- }
+ uiStage.getViewport().apply();
+ uiStage.act(deltaSeconds);
+ uiStage.draw();
+ }
- @Override
- public void close() {
- uiStage.dispose();
- stage.dispose();
- shapeRenderer.dispose();
- VisUI.dispose();
- }
+ @Override
+ public void close() {
+ uiStage.dispose();
+ stage.dispose();
+ shapeRenderer.dispose();
+ VisUI.dispose();
+ }
- private Vec2<Float> computeCellSize() {
- return Vec2f.builder().x(viewport.getWorldWidth() / gridSize.getX())
- .y(viewport.getWorldHeight() / gridSize.getY()).build();
- }
+ private Vec2<Float> computeCellSize() {
+ return Vec2f.builder().x(viewport.getWorldWidth() / gridSize.getX())
+ .y(viewport.getWorldHeight() / gridSize.getY()).build();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/CursorStyle.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/CursorStyle.java
index c8b82af..f4c75b3 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/CursorStyle.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/CursorStyle.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor;
public enum CursorStyle {
- CARET, BLOCK, CARET_AND_BLOCK, HIDDEN
+ CARET, BLOCK, CARET_AND_BLOCK, HIDDEN
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorModifier.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorModifier.java
index fa9dd00..b8f6802 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorModifier.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorModifier.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor;
public enum EditorModifier {
- CTRL, ALT, SHIFT, META
+ CTRL, ALT, SHIFT, META
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorTextArea.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorTextArea.java
index e2570b4..144141f 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorTextArea.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/EditorTextArea.java
@@ -21,254 +21,254 @@ import java.util.EnumSet;
import java.util.Set;
public class EditorTextArea extends EditorHighlightTextAreaBridge {
- private static final Color CURRENT_LINE_COLOR = new Color(Theme.SURFACE_ALT.r, Theme.SURFACE_ALT.g,
- Theme.SURFACE_ALT.b, 0.5f);
- private static final Color BLOCK_CURSOR_COLOR = new Color(Theme.FG.r, Theme.FG.g, Theme.FG.b, 0.7f);
- private static final Set<EditorModifier> EMPTY_MODIFIERS = Set.of();
- private static final Drawable INVISIBLE_CURSOR = new BaseDrawable() {
- };
+ private static final Color CURRENT_LINE_COLOR = new Color(Theme.SURFACE_ALT.r, Theme.SURFACE_ALT.g,
+ Theme.SURFACE_ALT.b, 0.5f);
+ private static final Color BLOCK_CURSOR_COLOR = new Color(Theme.FG.r, Theme.FG.g, Theme.FG.b, 0.7f);
+ private static final Set<EditorModifier> EMPTY_MODIFIERS = Set.of();
+ private static final Drawable INVISIBLE_CURSOR = new BaseDrawable() {
+ };
- private final float gutterWidth;
- private final float charWidth;
- private final ShapeRenderer shapeRenderer;
- @Setter
- private InputStrategy inputStrategy;
+ private final float gutterWidth;
+ private final float charWidth;
+ private final ShapeRenderer shapeRenderer;
+ @Setter
+ private InputStrategy inputStrategy;
- public EditorTextArea(final String text, final VisTextFieldStyle style, final float gutterWidth) {
- super(text, padStyle(style, gutterWidth));
- this.gutterWidth = gutterWidth;
- this.charWidth = style.font.getData().spaceXadvance;
- this.shapeRenderer = new ShapeRenderer();
- }
+ public EditorTextArea(final String text, final VisTextFieldStyle style, final float gutterWidth) {
+ super(text, padStyle(style, gutterWidth));
+ this.gutterWidth = gutterWidth;
+ this.charWidth = style.font.getData().spaceXadvance;
+ this.shapeRenderer = new ShapeRenderer();
+ }
- public void syncCursorState() {
- editorSyncCursorState();
- scrollCursorIntoView();
- }
+ public void syncCursorState() {
+ editorSyncCursorState();
+ scrollCursorIntoView();
+ }
- public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
- editorSetSelectionEndpoints(selectionStart, cursorPosition);
- scrollCursorIntoView();
- }
+ public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
+ editorSetSelectionEndpoints(selectionStart, cursorPosition);
+ scrollCursorIntoView();
+ }
- public void setCursorKeepingSelection(final int cursorPosition) {
- editorSetCursorKeepingSelection(cursorPosition);
- scrollCursorIntoView();
- }
+ public void setCursorKeepingSelection(final int cursorPosition) {
+ editorSetCursorKeepingSelection(cursorPosition);
+ scrollCursorIntoView();
+ }
- @Override
- protected InputListener createInputListener() {
- return new TextAreaListener() {
- @Override
- public boolean keyDown(final InputEvent event, final int keycode) {
- if (inputStrategy != null) {
- final KeyEvent keyEvent = new KeyEvent(keycode, currentModifiers());
- if (inputStrategy.onKeyDown(keyEvent)) {
- return true;
- }
- }
- return super.keyDown(event, keycode);
- }
+ @Override
+ protected InputListener createInputListener() {
+ return new TextAreaListener() {
+ @Override
+ public boolean keyDown(final InputEvent event, final int keycode) {
+ if (inputStrategy != null) {
+ final KeyEvent keyEvent = new KeyEvent(keycode, currentModifiers());
+ if (inputStrategy.onKeyDown(keyEvent)) {
+ return true;
+ }
+ }
+ return super.keyDown(event, keycode);
+ }
- @Override
- public boolean keyTyped(final InputEvent event, final char character) {
- if (inputStrategy != null && inputStrategy.onKeyTyped(character)) {
- return true;
- }
- return super.keyTyped(event, character);
- }
+ @Override
+ public boolean keyTyped(final InputEvent event, final char character) {
+ if (inputStrategy != null && inputStrategy.onKeyTyped(character)) {
+ return true;
+ }
+ return super.keyTyped(event, character);
+ }
- @Override
- public void clicked(final InputEvent event, final float x, final float y) {
- final int count = getTapCount() % 4;
- if (count == 0) {
- clearSelection();
- }
- if (count == 2) {
- final Drawable bg = getStyle().background;
- final float adjustedX = bg != null ? Math.max(0, x - bg.getLeftWidth()) : x;
- final int[] word = wordUnderCursor(letterUnderCursor(adjustedX));
- setSelection(word[0], word[1]);
- }
- }
- };
- }
+ @Override
+ public void clicked(final InputEvent event, final float x, final float y) {
+ final int count = getTapCount() % 4;
+ if (count == 0) {
+ clearSelection();
+ }
+ if (count == 2) {
+ final Drawable bg = getStyle().background;
+ final float adjustedX = bg != null ? Math.max(0, x - bg.getLeftWidth()) : x;
+ final int[] word = wordUnderCursor(letterUnderCursor(adjustedX));
+ setSelection(word[0], word[1]);
+ }
+ }
+ };
+ }
- @Override
- protected void drawCursor(final Drawable cursorPatch, final Batch batch, final BitmapFont font, final float x,
- final float y) {
- if (shouldRenderBlockCursor()) {
- if (shouldRenderCaret()) {
- super.drawCursor(cursorPatch, batch, font, x, y);
- } else {
- super.drawCursor(INVISIBLE_CURSOR, batch, font, x, y);
- }
- return;
- }
+ @Override
+ protected void drawCursor(final Drawable cursorPatch, final Batch batch, final BitmapFont font, final float x,
+ final float y) {
+ if (shouldRenderBlockCursor()) {
+ if (shouldRenderCaret()) {
+ super.drawCursor(cursorPatch, batch, font, x, y);
+ } else {
+ super.drawCursor(INVISIBLE_CURSOR, batch, font, x, y);
+ }
+ return;
+ }
- if (shouldRenderCaret()) {
- super.drawCursor(cursorPatch, batch, font, x, y);
- }
- }
+ if (shouldRenderCaret()) {
+ super.drawCursor(cursorPatch, batch, font, x, y);
+ }
+ }
- @Override
- protected void drawText(final Batch batch, final BitmapFont font, final float x, final float y) {
- final float parentAlpha = font.getColor().a;
- final int first = getFirstLineShowing();
- final int count = getLinesShowing();
- final int total = getLineNumberCount();
- final int cursorLine = getCursorLine();
- final float lineHeight = font.getLineHeight();
+ @Override
+ protected void drawText(final Batch batch, final BitmapFont font, final float x, final float y) {
+ final float parentAlpha = font.getColor().a;
+ final int first = getFirstLineShowing();
+ final int count = getLinesShowing();
+ final int total = getLineNumberCount();
+ final int cursorLine = getCursorLine();
+ final float lineHeight = font.getLineHeight();
- batch.end();
- Gdx.gl.glEnable(GL20.GL_BLEND);
- shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
- shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
- shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
- if (cursorLine >= first && cursorLine < first + count) {
- final float highlightY = y - font.getCapHeight() + font.getDescent() - (cursorLine - first) * lineHeight;
- shapeRenderer.setColor(CURRENT_LINE_COLOR.r, CURRENT_LINE_COLOR.g, CURRENT_LINE_COLOR.b,
- CURRENT_LINE_COLOR.a * parentAlpha);
- shapeRenderer.rect(x - gutterWidth, highlightY, getWidth(), lineHeight);
- }
+ batch.end();
+ Gdx.gl.glEnable(GL20.GL_BLEND);
+ shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
+ shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
+ shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
+ if (cursorLine >= first && cursorLine < first + count) {
+ final float highlightY = y - font.getCapHeight() + font.getDescent() - (cursorLine - first) * lineHeight;
+ shapeRenderer.setColor(CURRENT_LINE_COLOR.r, CURRENT_LINE_COLOR.g, CURRENT_LINE_COLOR.b,
+ CURRENT_LINE_COLOR.a * parentAlpha);
+ shapeRenderer.rect(x - gutterWidth, highlightY, getWidth(), lineHeight);
+ }
- if (shouldRenderBlockCursor() && isFocused()) {
- // Keep VisTextArea cursor metrics current even when caret is hidden.
- super.drawCursor(INVISIBLE_CURSOR, batch, font, x, y);
- drawBlockCursor(font, x, y, first, cursorLine, lineHeight, parentAlpha);
- }
- shapeRenderer.end();
- Gdx.gl.glDisable(GL20.GL_BLEND);
- batch.begin();
+ if (shouldRenderBlockCursor() && isFocused()) {
+ // Keep VisTextArea cursor metrics current even when caret is hidden.
+ super.drawCursor(INVISIBLE_CURSOR, batch, font, x, y);
+ drawBlockCursor(font, x, y, first, cursorLine, lineHeight, parentAlpha);
+ }
+ shapeRenderer.end();
+ Gdx.gl.glDisable(GL20.GL_BLEND);
+ batch.begin();
- drawLineNumbers(batch, font, x, y, first, count, total, cursorLine, lineHeight, parentAlpha);
+ drawLineNumbers(batch, font, x, y, first, count, total, cursorLine, lineHeight, parentAlpha);
- font.setColor(1, 1, 1, parentAlpha);
- super.drawText(batch, font, x, y);
- }
+ font.setColor(1, 1, 1, parentAlpha);
+ super.drawText(batch, font, x, y);
+ }
- private static VisTextFieldStyle padStyle(final VisTextFieldStyle original, final float gutterWidth) {
- final VisTextFieldStyle style = new VisTextFieldStyle(original);
- style.background = wrapIfPresent(style.background, gutterWidth);
- style.backgroundOver = wrapIfPresent(style.backgroundOver, gutterWidth);
- style.focusedBackground = wrapIfPresent(style.focusedBackground, gutterWidth);
- style.disabledBackground = wrapIfPresent(style.disabledBackground, gutterWidth);
- return style;
- }
+ private static VisTextFieldStyle padStyle(final VisTextFieldStyle original, final float gutterWidth) {
+ final VisTextFieldStyle style = new VisTextFieldStyle(original);
+ style.background = wrapIfPresent(style.background, gutterWidth);
+ style.backgroundOver = wrapIfPresent(style.backgroundOver, gutterWidth);
+ style.focusedBackground = wrapIfPresent(style.focusedBackground, gutterWidth);
+ style.disabledBackground = wrapIfPresent(style.disabledBackground, gutterWidth);
+ return style;
+ }
- private static Drawable wrapIfPresent(final Drawable drawable, final float gutterWidth) {
- return drawable != null ? new GutterPaddedDrawable(drawable, gutterWidth) : null;
- }
+ private static Drawable wrapIfPresent(final Drawable drawable, final float gutterWidth) {
+ return drawable != null ? new GutterPaddedDrawable(drawable, gutterWidth) : null;
+ }
- private void drawLineNumbers(final Batch batch, final BitmapFont font, final float x, final float y,
- final int firstLine, final int visibleLineCount, final int totalLines, final int cursorLine,
- final float lineHeight, final float parentAlpha) {
- final LineNumberMode mode = resolveRenderState().lineNumberMode();
- if (mode == LineNumberMode.OFF) {
- return;
- }
+ private void drawLineNumbers(final Batch batch, final BitmapFont font, final float x, final float y,
+ final int firstLine, final int visibleLineCount, final int totalLines, final int cursorLine,
+ final float lineHeight, final float parentAlpha) {
+ final LineNumberMode mode = resolveRenderState().lineNumberMode();
+ if (mode == LineNumberMode.OFF) {
+ return;
+ }
- float offsetY = 0f;
- for (int line = firstLine; line < firstLine + visibleLineCount && line < totalLines; line++) {
- final Color color = line == cursorLine ? Theme.FG : Theme.BORDER_LIGHT;
- font.setColor(color.r, color.g, color.b, color.a * parentAlpha);
- final String lineNum = formatLineNumber(mode, line, cursorLine);
- font.draw(batch, lineNum, x - gutterWidth, y + offsetY);
- offsetY -= lineHeight;
- }
- }
+ float offsetY = 0f;
+ for (int line = firstLine; line < firstLine + visibleLineCount && line < totalLines; line++) {
+ final Color color = line == cursorLine ? Theme.FG : Theme.BORDER_LIGHT;
+ font.setColor(color.r, color.g, color.b, color.a * parentAlpha);
+ final String lineNum = formatLineNumber(mode, line, cursorLine);
+ font.draw(batch, lineNum, x - gutterWidth, y + offsetY);
+ offsetY -= lineHeight;
+ }
+ }
- private int getLineNumberCount() {
- final int totalLines = getLines();
- if (totalLines > 1 && getText().endsWith("\n")) {
- return totalLines - 1;
- }
- return totalLines;
- }
+ private int getLineNumberCount() {
+ final int totalLines = getLines();
+ if (totalLines > 1 && getText().endsWith("\n")) {
+ return totalLines - 1;
+ }
+ return totalLines;
+ }
- private String formatLineNumber(final LineNumberMode mode, final int line, final int cursorLine) {
- if (mode == LineNumberMode.RELATIVE && line != cursorLine) {
- return String.valueOf(Math.abs(line - cursorLine));
- }
- return String.valueOf(line + 1);
- }
+ private String formatLineNumber(final LineNumberMode mode, final int line, final int cursorLine) {
+ if (mode == LineNumberMode.RELATIVE && line != cursorLine) {
+ return String.valueOf(Math.abs(line - cursorLine));
+ }
+ return String.valueOf(line + 1);
+ }
- private void drawBlockCursor(final BitmapFont font, final float x, final float y, final int firstLine,
- final int cursorLine, final float lineHeight, final float parentAlpha) {
- final float cursorX = x + getCursorX();
- final float cursorY = y - font.getCapHeight() + font.getDescent() - (cursorLine - firstLine) * lineHeight;
- shapeRenderer.setColor(BLOCK_CURSOR_COLOR.r, BLOCK_CURSOR_COLOR.g, BLOCK_CURSOR_COLOR.b,
- BLOCK_CURSOR_COLOR.a * parentAlpha);
- shapeRenderer.rect(cursorX, cursorY, Math.max(1f, charWidth), lineHeight);
- }
+ private void drawBlockCursor(final BitmapFont font, final float x, final float y, final int firstLine,
+ final int cursorLine, final float lineHeight, final float parentAlpha) {
+ final float cursorX = x + getCursorX();
+ final float cursorY = y - font.getCapHeight() + font.getDescent() - (cursorLine - firstLine) * lineHeight;
+ shapeRenderer.setColor(BLOCK_CURSOR_COLOR.r, BLOCK_CURSOR_COLOR.g, BLOCK_CURSOR_COLOR.b,
+ BLOCK_CURSOR_COLOR.a * parentAlpha);
+ shapeRenderer.rect(cursorX, cursorY, Math.max(1f, charWidth), lineHeight);
+ }
- private boolean shouldRenderCaret() {
- final CursorStyle cursorStyle = resolveRenderState().cursorStyle();
- return cursorStyle == CursorStyle.CARET || cursorStyle == CursorStyle.CARET_AND_BLOCK;
- }
+ private boolean shouldRenderCaret() {
+ final CursorStyle cursorStyle = resolveRenderState().cursorStyle();
+ return cursorStyle == CursorStyle.CARET || cursorStyle == CursorStyle.CARET_AND_BLOCK;
+ }
- private boolean shouldRenderBlockCursor() {
- final CursorStyle cursorStyle = resolveRenderState().cursorStyle();
- return cursorStyle == CursorStyle.BLOCK || cursorStyle == CursorStyle.CARET_AND_BLOCK;
- }
+ private boolean shouldRenderBlockCursor() {
+ final CursorStyle cursorStyle = resolveRenderState().cursorStyle();
+ return cursorStyle == CursorStyle.BLOCK || cursorStyle == CursorStyle.CARET_AND_BLOCK;
+ }
- private RenderState resolveRenderState() {
- if (inputStrategy == null) {
- return RenderState.DEFAULT;
- }
- final RenderState renderState = inputStrategy.getRenderState();
- return renderState != null ? renderState : RenderState.DEFAULT;
- }
+ private RenderState resolveRenderState() {
+ if (inputStrategy == null) {
+ return RenderState.DEFAULT;
+ }
+ final RenderState renderState = inputStrategy.getRenderState();
+ return renderState != null ? renderState : RenderState.DEFAULT;
+ }
- private boolean isFocused() {
- final Stage stage = getStage();
- return stage != null && stage.getKeyboardFocus() == this && !isDisabled();
- }
+ private boolean isFocused() {
+ final Stage stage = getStage();
+ return stage != null && stage.getKeyboardFocus() == this && !isDisabled();
+ }
- private void scrollCursorIntoView() {
- if (!(getParent() instanceof ScrollPane scrollPane)) {
- return;
- }
+ private void scrollCursorIntoView() {
+ if (!(getParent() instanceof ScrollPane scrollPane)) {
+ return;
+ }
- final float lineHeight = getStyle().font.getLineHeight();
- final float cursorX = getCursorX();
- final float cursorY = getHeight() - getCursorY() + lineHeight;
- scrollPane.scrollTo(cursorX, cursorY, Math.max(1f, charWidth), lineHeight, false, false);
- }
+ final float lineHeight = getStyle().font.getLineHeight();
+ final float cursorX = getCursorX();
+ final float cursorY = getHeight() - getCursorY() + lineHeight;
+ scrollPane.scrollTo(cursorX, cursorY, Math.max(1f, charWidth), lineHeight, false, false);
+ }
- private Set<EditorModifier> currentModifiers() {
- if (Gdx.input == null) {
- return EMPTY_MODIFIERS;
- }
+ private Set<EditorModifier> currentModifiers() {
+ if (Gdx.input == null) {
+ return EMPTY_MODIFIERS;
+ }
- final EnumSet<EditorModifier> modifiers = EnumSet.noneOf(EditorModifier.class);
- if (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)) {
- modifiers.add(EditorModifier.CTRL);
- }
- if (Gdx.input.isKeyPressed(Input.Keys.ALT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.ALT_RIGHT)) {
- modifiers.add(EditorModifier.ALT);
- }
- if (Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT)) {
- modifiers.add(EditorModifier.SHIFT);
- }
- if (Gdx.input.isKeyPressed(Input.Keys.SYM)) {
- modifiers.add(EditorModifier.META);
- }
- return modifiers.isEmpty() ? EMPTY_MODIFIERS : modifiers;
- }
+ final EnumSet<EditorModifier> modifiers = EnumSet.noneOf(EditorModifier.class);
+ if (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)) {
+ modifiers.add(EditorModifier.CTRL);
+ }
+ if (Gdx.input.isKeyPressed(Input.Keys.ALT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.ALT_RIGHT)) {
+ modifiers.add(EditorModifier.ALT);
+ }
+ if (Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT)) {
+ modifiers.add(EditorModifier.SHIFT);
+ }
+ if (Gdx.input.isKeyPressed(Input.Keys.SYM)) {
+ modifiers.add(EditorModifier.META);
+ }
+ return modifiers.isEmpty() ? EMPTY_MODIFIERS : modifiers;
+ }
- private static final class GutterPaddedDrawable extends BaseDrawable {
- private final Drawable wrapped;
+ private static final class GutterPaddedDrawable extends BaseDrawable {
+ private final Drawable wrapped;
- GutterPaddedDrawable(final Drawable wrapped, final float gutterWidth) {
- super(wrapped);
- this.wrapped = wrapped;
- setLeftWidth(wrapped.getLeftWidth() + gutterWidth);
- }
+ GutterPaddedDrawable(final Drawable wrapped, final float gutterWidth) {
+ super(wrapped);
+ this.wrapped = wrapped;
+ setLeftWidth(wrapped.getLeftWidth() + gutterWidth);
+ }
- @Override
- public void draw(final Batch batch, final float x, final float y, final float width, final float height) {
- wrapped.draw(batch, x, y, width, height);
- }
- }
+ @Override
+ public void draw(final Batch batch, final float x, final float y, final float width, final float height) {
+ wrapped.draw(batch, x, y, width, height);
+ }
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/InputStrategy.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/InputStrategy.java
index 49816d3..ba55466 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/InputStrategy.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/InputStrategy.java
@@ -1,11 +1,11 @@
package coffee.liz.abstractionengine.app.ui.editor;
public interface InputStrategy {
- boolean onKeyDown(KeyEvent event);
+ boolean onKeyDown(KeyEvent event);
- boolean onKeyTyped(char character);
+ boolean onKeyTyped(char character);
- default RenderState getRenderState() {
- return RenderState.DEFAULT;
- }
+ default RenderState getRenderState() {
+ return RenderState.DEFAULT;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/KeyEvent.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/KeyEvent.java
index 4da2f60..c4bade5 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/KeyEvent.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/KeyEvent.java
@@ -3,7 +3,7 @@ package coffee.liz.abstractionengine.app.ui.editor;
import java.util.Set;
public record KeyEvent(int keycode, Set<EditorModifier> modifiers) {
- public boolean hasModifier(final EditorModifier modifier) {
- return modifiers.contains(modifier);
- }
+ public boolean hasModifier(final EditorModifier modifier) {
+ return modifiers.contains(modifier);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LambdaEditor.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LambdaEditor.java
index 46fcb22..11a4b0e 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LambdaEditor.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LambdaEditor.java
@@ -15,66 +15,66 @@ import com.kotcrab.vis.ui.widget.VisTextField.VisTextFieldStyle;
import com.kotcrab.vis.ui.widget.VisWindow;
public class LambdaEditor extends VisWindow {
- private static final int FONT_SIZE = 15;
- private static final float WINDOW_ALPHA = 0.92f;
+ private static final int FONT_SIZE = 15;
+ private static final float WINDOW_ALPHA = 0.92f;
- private static final String DEFAULT_TEXT = "-- Church numerals\n" + "let zero = λf.λx.x;\n"
- + "let one = λf.λx.f x;\n" + "let succ = λn.λf.λx.f (n f x);\n" + "let add = λm.λn.λf.λx.m f (n f x);\n"
- + "\n" + "succ (add one zero)\n";
+ private static final String DEFAULT_TEXT = "-- Church numerals\n" + "let zero = λf.λx.x;\n"
+ + "let one = λf.λx.f x;\n" + "let succ = λn.λf.λx.f (n f x);\n" + "let add = λm.λn.λf.λx.m f (n f x);\n"
+ + "\n" + "succ (add one zero)\n";
- private final BitmapFont font;
+ private final BitmapFont font;
- public LambdaEditor(final boolean vimMode) {
- super("λ-editor");
+ public LambdaEditor(final boolean vimMode) {
+ super("λ-editor");
- TableUtils.setSpacingDefaults(this);
- columnDefaults(0).left();
+ TableUtils.setSpacingDefaults(this);
+ columnDefaults(0).left();
- this.font = FontHelper.initFont(FONT_SIZE, FontHelper.MONO, 1f);
+ this.font = FontHelper.initFont(FONT_SIZE, FontHelper.MONO, 1f);
- setResizable(true);
- addCloseButton();
- addEditor(vimMode);
+ setResizable(true);
+ addCloseButton();
+ addEditor(vimMode);
- setSize(400, 300);
- setColor(1, 1, 1, WINDOW_ALPHA);
- centerWindow();
- }
+ setSize(400, 300);
+ setColor(1, 1, 1, WINDOW_ALPHA);
+ centerWindow();
+ }
- private void addEditor(final boolean vimMode) {
- final VisTextFieldStyle style = new VisTextFieldStyle(VisUI.getSkin().get("textArea", VisTextFieldStyle.class));
- style.font = font;
+ private void addEditor(final boolean vimMode) {
+ final VisTextFieldStyle style = new VisTextFieldStyle(VisUI.getSkin().get("textArea", VisTextFieldStyle.class));
+ style.font = font;
- final GlyphLayout layout = new GlyphLayout(font, "000 ");
- final float gutterWidth = layout.width;
+ final GlyphLayout layout = new GlyphLayout(font, "000 ");
+ final float gutterWidth = layout.width;
- final EditorTextArea textArea = new EditorTextArea(DEFAULT_TEXT, style, gutterWidth);
- textArea.setHighlighter(createHighlighter());
+ final EditorTextArea textArea = new EditorTextArea(DEFAULT_TEXT, style, gutterWidth);
+ textArea.setHighlighter(createHighlighter());
- final ScrollPane scrollPane = textArea.createCompatibleScrollPane();
- scrollPane.setFadeScrollBars(false);
+ final ScrollPane scrollPane = textArea.createCompatibleScrollPane();
+ scrollPane.setFadeScrollBars(false);
- final VisLabel statusLabel = new VisLabel(vimMode ? "-- NORMAL --" : "-- INSERT --");
- statusLabel.setAlignment(Align.left);
+ final VisLabel statusLabel = new VisLabel(vimMode ? "-- NORMAL --" : "-- INSERT --");
+ statusLabel.setAlignment(Align.left);
- if (vimMode) {
- final VimEngine controller = new VimEngine(textArea, statusLabel::setText);
- textArea.setInputStrategy(controller);
- statusLabel.setText(controller.getStatusText());
- }
+ if (vimMode) {
+ final VimEngine controller = new VimEngine(textArea, statusLabel::setText);
+ textArea.setInputStrategy(controller);
+ statusLabel.setText(controller.getStatusText());
+ }
- add(scrollPane).grow().row();
- add(statusLabel).growX().padTop(6f);
- }
+ add(scrollPane).grow().row();
+ add(statusLabel).growX().padTop(6f);
+ }
- private static Highlighter createHighlighter() {
- final Highlighter highlighter = new Highlighter();
- highlighter.regex(Theme.MUTED, "--[^\\n]*");
- highlighter.regex(Theme.PRIMARY, "\\blet\\b");
- highlighter.regex(Theme.SECONDARY, "[λ\\\\]");
- highlighter.regex(Theme.SECONDARY, "\\.");
- highlighter.regex(Theme.BORDER_LIGHT, "[=;]");
- highlighter.regex(Theme.BORDER_LIGHT, "[()]");
- return highlighter;
- }
+ private static Highlighter createHighlighter() {
+ final Highlighter highlighter = new Highlighter();
+ highlighter.regex(Theme.MUTED, "--[^\\n]*");
+ highlighter.regex(Theme.PRIMARY, "\\blet\\b");
+ highlighter.regex(Theme.SECONDARY, "[λ\\\\]");
+ highlighter.regex(Theme.SECONDARY, "\\.");
+ highlighter.regex(Theme.BORDER_LIGHT, "[=;]");
+ highlighter.regex(Theme.BORDER_LIGHT, "[()]");
+ return highlighter;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LineNumberMode.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LineNumberMode.java
index 3ec768d..0ab0f20 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LineNumberMode.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/LineNumberMode.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor;
public enum LineNumberMode {
- OFF, ABSOLUTE, RELATIVE
+ OFF, ABSOLUTE, RELATIVE
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/RenderState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/RenderState.java
index a04c988..8961cfa 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/RenderState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/RenderState.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor;
public record RenderState(CursorStyle cursorStyle, LineNumberMode lineNumberMode) {
- public static final RenderState DEFAULT = new RenderState(CursorStyle.CARET, LineNumberMode.ABSOLUTE);
+ public static final RenderState DEFAULT = new RenderState(CursorStyle.CARET, LineNumberMode.ABSOLUTE);
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/EditorBuffer.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/EditorBuffer.java
index eadc8e8..0ccde34 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/EditorBuffer.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/EditorBuffer.java
@@ -1,21 +1,21 @@
package coffee.liz.abstractionengine.app.ui.editor.vim;
public interface EditorBuffer {
- String getText();
+ String getText();
- void setText(String text);
+ void setText(String text);
- int getCursorPosition();
+ int getCursorPosition();
- void setCursorPosition(int cursorPosition);
+ void setCursorPosition(int cursorPosition);
- int getCursorLine();
+ int getCursorLine();
- int getLines();
+ int getLines();
- void moveCursorLine(int line);
+ void moveCursorLine(int line);
- void setSelectionEndpoints(int selectionStart, int cursorPosition);
+ void setSelectionEndpoints(int selectionStart, int cursorPosition);
- void clearSelection();
+ void clearSelection();
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/Mode.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/Mode.java
index e470f91..97e1d62 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/Mode.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/Mode.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim;
public enum Mode {
- NORMAL, INSERT, VISUAL, VISUAL_LINE, SEARCH
+ NORMAL, INSERT, VISUAL, VISUAL_LINE, SEARCH
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimConfig.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimConfig.java
index 050790c..5b62f61 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimConfig.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimConfig.java
@@ -1,34 +1,34 @@
package coffee.liz.abstractionengine.app.ui.editor.vim;
public record VimConfig(int maxUndoStates, char ctrlRedoCharacter, String normalStatusLabel, String insertStatusLabel,
- String visualStatusLabel, String visualLineStatusLabel, boolean wrapSearch) {
- private static final int DEFAULT_MAX_UNDO_STATES = 200;
- private static final char DEFAULT_CTRL_REDO_CHARACTER = 18;
- private static final String DEFAULT_NORMAL_STATUS_LABEL = "-- NORMAL --";
- private static final String DEFAULT_INSERT_STATUS_LABEL = "-- INSERT --";
- private static final String DEFAULT_VISUAL_STATUS_LABEL = "-- VISUAL --";
- private static final String DEFAULT_VISUAL_LINE_STATUS_LABEL = "-- VISUAL LINE --";
+ String visualStatusLabel, String visualLineStatusLabel, boolean wrapSearch) {
+ private static final int DEFAULT_MAX_UNDO_STATES = 200;
+ private static final char DEFAULT_CTRL_REDO_CHARACTER = 18;
+ private static final String DEFAULT_NORMAL_STATUS_LABEL = "-- NORMAL --";
+ private static final String DEFAULT_INSERT_STATUS_LABEL = "-- INSERT --";
+ private static final String DEFAULT_VISUAL_STATUS_LABEL = "-- VISUAL --";
+ private static final String DEFAULT_VISUAL_LINE_STATUS_LABEL = "-- VISUAL LINE --";
- public VimConfig {
- if (maxUndoStates <= 0) {
- throw new IllegalArgumentException("maxUndoStates must be positive");
- }
- if (normalStatusLabel == null || normalStatusLabel.isEmpty()) {
- throw new IllegalArgumentException("normalStatusLabel must not be empty");
- }
- if (insertStatusLabel == null || insertStatusLabel.isEmpty()) {
- throw new IllegalArgumentException("insertStatusLabel must not be empty");
- }
- if (visualStatusLabel == null || visualStatusLabel.isEmpty()) {
- throw new IllegalArgumentException("visualStatusLabel must not be empty");
- }
- if (visualLineStatusLabel == null || visualLineStatusLabel.isEmpty()) {
- throw new IllegalArgumentException("visualLineStatusLabel must not be empty");
- }
- }
+ public VimConfig {
+ if (maxUndoStates <= 0) {
+ throw new IllegalArgumentException("maxUndoStates must be positive");
+ }
+ if (normalStatusLabel == null || normalStatusLabel.isEmpty()) {
+ throw new IllegalArgumentException("normalStatusLabel must not be empty");
+ }
+ if (insertStatusLabel == null || insertStatusLabel.isEmpty()) {
+ throw new IllegalArgumentException("insertStatusLabel must not be empty");
+ }
+ if (visualStatusLabel == null || visualStatusLabel.isEmpty()) {
+ throw new IllegalArgumentException("visualStatusLabel must not be empty");
+ }
+ if (visualLineStatusLabel == null || visualLineStatusLabel.isEmpty()) {
+ throw new IllegalArgumentException("visualLineStatusLabel must not be empty");
+ }
+ }
- public static VimConfig defaults() {
- return new VimConfig(DEFAULT_MAX_UNDO_STATES, DEFAULT_CTRL_REDO_CHARACTER, DEFAULT_NORMAL_STATUS_LABEL,
- DEFAULT_INSERT_STATUS_LABEL, DEFAULT_VISUAL_STATUS_LABEL, DEFAULT_VISUAL_LINE_STATUS_LABEL, true);
- }
+ public static VimConfig defaults() {
+ return new VimConfig(DEFAULT_MAX_UNDO_STATES, DEFAULT_CTRL_REDO_CHARACTER, DEFAULT_NORMAL_STATUS_LABEL,
+ DEFAULT_INSERT_STATUS_LABEL, DEFAULT_VISUAL_STATUS_LABEL, DEFAULT_VISUAL_LINE_STATUS_LABEL, true);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimEngine.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimEngine.java
index dd577fb..ab5f203 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimEngine.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/VimEngine.java
@@ -31,175 +31,175 @@ import java.util.Set;
import java.util.function.Consumer;
public class VimEngine implements InputStrategy {
- private final VimConfig config;
- private final KeyContext context;
- private final StatusFormatter statusFormatter;
- private final ModeHandler<NormalState> normalModeHandler;
- private final ModeHandler<InsertState> insertModeHandler;
- private final ModeHandler<VisualState> visualModeHandler;
- private final ModeHandler<VisualLineState> visualLineModeHandler;
- private final ModeHandler<SearchState> searchModeHandler;
+ private final VimConfig config;
+ private final KeyContext context;
+ private final StatusFormatter statusFormatter;
+ private final ModeHandler<NormalState> normalModeHandler;
+ private final ModeHandler<InsertState> insertModeHandler;
+ private final ModeHandler<VisualState> visualModeHandler;
+ private final ModeHandler<VisualLineState> visualLineModeHandler;
+ private final ModeHandler<SearchState> searchModeHandler;
- private ModeState state;
+ private ModeState state;
- public VimEngine(final EditorTextArea textArea, final Consumer<String> statusSink, final VimConfig config) {
- this(new TextAreaBuffer(textArea), statusSink, config);
- }
+ public VimEngine(final EditorTextArea textArea, final Consumer<String> statusSink, final VimConfig config) {
+ this(new TextAreaBuffer(textArea), statusSink, config);
+ }
- public VimEngine(final EditorTextArea textArea, final Consumer<String> statusSink) {
- this(textArea, statusSink, VimConfig.defaults());
- }
+ public VimEngine(final EditorTextArea textArea, final Consumer<String> statusSink) {
+ this(textArea, statusSink, VimConfig.defaults());
+ }
- public VimEngine(final EditorTextArea textArea) {
- this(textArea, null, VimConfig.defaults());
- }
+ public VimEngine(final EditorTextArea textArea) {
+ this(textArea, null, VimConfig.defaults());
+ }
- public VimEngine(final EditorBuffer buffer, final Consumer<String> statusSink, final VimConfig config) {
- this.config = config != null ? config : VimConfig.defaults();
- this.context = new KeyContext(buffer, statusSink, new TextNavigation(),
- new UndoManager(this.config.maxUndoStates()), new Register(), this.config);
- this.statusFormatter = new StatusFormatter();
- this.normalModeHandler = new NormalModeHandler();
- this.insertModeHandler = new InsertModeHandler();
- this.visualModeHandler = new VisualModeHandler();
- this.visualLineModeHandler = new VisualLineModeHandler();
- this.searchModeHandler = new SearchModeHandler();
- this.state = NormalState.DEFAULT;
- context.recordUndoState();
- publishStatus();
- }
+ public VimEngine(final EditorBuffer buffer, final Consumer<String> statusSink, final VimConfig config) {
+ this.config = config != null ? config : VimConfig.defaults();
+ this.context = new KeyContext(buffer, statusSink, new TextNavigation(),
+ new UndoManager(this.config.maxUndoStates()), new Register(), this.config);
+ this.statusFormatter = new StatusFormatter();
+ this.normalModeHandler = new NormalModeHandler();
+ this.insertModeHandler = new InsertModeHandler();
+ this.visualModeHandler = new VisualModeHandler();
+ this.visualLineModeHandler = new VisualLineModeHandler();
+ this.searchModeHandler = new SearchModeHandler();
+ this.state = NormalState.DEFAULT;
+ context.recordUndoState();
+ publishStatus();
+ }
- public VimEngine(final EditorBuffer buffer, final Consumer<String> statusSink) {
- this(buffer, statusSink, VimConfig.defaults());
- }
+ public VimEngine(final EditorBuffer buffer, final Consumer<String> statusSink) {
+ this(buffer, statusSink, VimConfig.defaults());
+ }
- @Override
- public boolean onKeyDown(final KeyEvent event) {
- return handleKeyDown(event);
- }
+ @Override
+ public boolean onKeyDown(final KeyEvent event) {
+ return handleKeyDown(event);
+ }
- @Override
- public boolean onKeyTyped(final char character) {
- return handleKeyTyped(character);
- }
+ @Override
+ public boolean onKeyTyped(final char character) {
+ return handleKeyTyped(character);
+ }
- @Override
- public RenderState getRenderState() {
- if (isBlockCursorMode(state)) {
- return new RenderState(CursorStyle.BLOCK, LineNumberMode.RELATIVE);
- }
- return new RenderState(CursorStyle.CARET, LineNumberMode.ABSOLUTE);
- }
+ @Override
+ public RenderState getRenderState() {
+ if (isBlockCursorMode(state)) {
+ return new RenderState(CursorStyle.BLOCK, LineNumberMode.RELATIVE);
+ }
+ return new RenderState(CursorStyle.CARET, LineNumberMode.ABSOLUTE);
+ }
- public String getStatusText() {
- return context.getStatusText();
- }
+ public String getStatusText() {
+ return context.getStatusText();
+ }
- public boolean handleKeyDown(final int keycode) {
- return handleKeyDown(new KeyEvent(keycode, Set.of()));
- }
+ public boolean handleKeyDown(final int keycode) {
+ return handleKeyDown(new KeyEvent(keycode, Set.of()));
+ }
- public boolean handleKeyDown(final int keycode, final boolean ctrlDown) {
- final Set<EditorModifier> modifiers = ctrlDown ? Set.of(EditorModifier.CTRL) : Set.of();
- return handleKeyDown(new KeyEvent(keycode, modifiers));
- }
+ public boolean handleKeyDown(final int keycode, final boolean ctrlDown) {
+ final Set<EditorModifier> modifiers = ctrlDown ? Set.of(EditorModifier.CTRL) : Set.of();
+ return handleKeyDown(new KeyEvent(keycode, modifiers));
+ }
- public boolean handleKeyDown(final KeyEvent event) {
- context.setCurrentKeyEvent(event);
- if (isInsertState(state)) {
- final boolean consumed = applyHandleResult(insertModeHandler.onKeyDown((InsertState) state, context));
- return consumed;
- }
+ public boolean handleKeyDown(final KeyEvent event) {
+ context.setCurrentKeyEvent(event);
+ if (isInsertState(state)) {
+ final boolean consumed = applyHandleResult(insertModeHandler.onKeyDown((InsertState) state, context));
+ return consumed;
+ }
- if (isRedoKeyDown(event)) {
- state = context.redoToNormalState();
- context.suppressNextRedoTyped();
- publishStatus();
- return true;
- }
+ if (isRedoKeyDown(event)) {
+ state = context.redoToNormalState();
+ context.suppressNextRedoTyped();
+ publishStatus();
+ return true;
+ }
- final HandleResult result = dispatchKeyDown(state);
- if (applyHandleResult(result)) {
- return true;
- }
+ final HandleResult result = dispatchKeyDown(state);
+ if (applyHandleResult(result)) {
+ return true;
+ }
- return !isInsertState(state);
- }
+ return !isInsertState(state);
+ }
- public boolean handleKeyTyped(final char character) {
- if (character == config.ctrlRedoCharacter()) {
- if (context.consumeRedoTypedSuppression()) {
- return true;
- }
- state = context.redoToNormalState();
- publishStatus();
- return true;
- }
+ public boolean handleKeyTyped(final char character) {
+ if (character == config.ctrlRedoCharacter()) {
+ if (context.consumeRedoTypedSuppression()) {
+ return true;
+ }
+ state = context.redoToNormalState();
+ publishStatus();
+ return true;
+ }
- if (context.consumeSuppressedTypedCommand()) {
- return true;
- }
- context.clearRedoTypedSuppression();
+ if (context.consumeSuppressedTypedCommand()) {
+ return true;
+ }
+ context.clearRedoTypedSuppression();
- if (isInsertState(state)) {
- return false;
- }
+ if (isInsertState(state)) {
+ return false;
+ }
- final HandleResult result = dispatchKeyTyped(state, character);
- if (applyHandleResult(result)) {
- return true;
- }
+ final HandleResult result = dispatchKeyTyped(state, character);
+ if (applyHandleResult(result)) {
+ return true;
+ }
- return !isInsertState(state);
- }
+ return !isInsertState(state);
+ }
- private HandleResult dispatchKeyDown(final ModeState modeState) {
- return switch (modeState) {
- case NormalState normalState -> normalModeHandler.onKeyDown(normalState, context);
- case InsertState insertState -> insertModeHandler.onKeyDown(insertState, context);
- case VisualState visualState -> visualModeHandler.onKeyDown(visualState, context);
- case VisualLineState visualLineState -> visualLineModeHandler.onKeyDown(visualLineState, context);
- case SearchState searchState -> searchModeHandler.onKeyDown(searchState, context);
- };
- }
+ private HandleResult dispatchKeyDown(final ModeState modeState) {
+ return switch (modeState) {
+ case NormalState normalState -> normalModeHandler.onKeyDown(normalState, context);
+ case InsertState insertState -> insertModeHandler.onKeyDown(insertState, context);
+ case VisualState visualState -> visualModeHandler.onKeyDown(visualState, context);
+ case VisualLineState visualLineState -> visualLineModeHandler.onKeyDown(visualLineState, context);
+ case SearchState searchState -> searchModeHandler.onKeyDown(searchState, context);
+ };
+ }
- private HandleResult dispatchKeyTyped(final ModeState modeState, final char character) {
- return switch (modeState) {
- case NormalState normalState -> normalModeHandler.onKeyTyped(normalState, character, context);
- case InsertState insertState -> insertModeHandler.onKeyTyped(insertState, character, context);
- case VisualState visualState -> visualModeHandler.onKeyTyped(visualState, character, context);
- case VisualLineState visualLineState ->
- visualLineModeHandler.onKeyTyped(visualLineState, character, context);
- case SearchState searchState -> searchModeHandler.onKeyTyped(searchState, character, context);
- };
- }
+ private HandleResult dispatchKeyTyped(final ModeState modeState, final char character) {
+ return switch (modeState) {
+ case NormalState normalState -> normalModeHandler.onKeyTyped(normalState, character, context);
+ case InsertState insertState -> insertModeHandler.onKeyTyped(insertState, character, context);
+ case VisualState visualState -> visualModeHandler.onKeyTyped(visualState, character, context);
+ case VisualLineState visualLineState ->
+ visualLineModeHandler.onKeyTyped(visualLineState, character, context);
+ case SearchState searchState -> searchModeHandler.onKeyTyped(searchState, character, context);
+ };
+ }
- private boolean applyHandleResult(final HandleResult result) {
- if (result.suppressTyped()) {
- context.incrementSuppressedTypedCommands();
- }
- if (result.nextState() != null) {
- state = result.nextState();
- }
- publishStatus();
- return result.consumed();
- }
+ private boolean applyHandleResult(final HandleResult result) {
+ if (result.suppressTyped()) {
+ context.incrementSuppressedTypedCommands();
+ }
+ if (result.nextState() != null) {
+ state = result.nextState();
+ }
+ publishStatus();
+ return result.consumed();
+ }
- private boolean isRedoKeyDown(final KeyEvent event) {
- final boolean ctrlDown = event.hasModifier(EditorModifier.CTRL) || event.hasModifier(EditorModifier.META);
- return ctrlDown && event.keycode() == Input.Keys.R;
- }
+ private boolean isRedoKeyDown(final KeyEvent event) {
+ final boolean ctrlDown = event.hasModifier(EditorModifier.CTRL) || event.hasModifier(EditorModifier.META);
+ return ctrlDown && event.keycode() == Input.Keys.R;
+ }
- private boolean isInsertState(final ModeState modeState) {
- return modeState instanceof InsertState;
- }
+ private boolean isInsertState(final ModeState modeState) {
+ return modeState instanceof InsertState;
+ }
- private boolean isBlockCursorMode(final ModeState modeState) {
- return modeState instanceof NormalState || modeState instanceof VisualState
- || modeState instanceof VisualLineState;
- }
+ private boolean isBlockCursorMode(final ModeState modeState) {
+ return modeState instanceof NormalState || modeState instanceof VisualState
+ || modeState instanceof VisualLineState;
+ }
- private void publishStatus() {
- context.publishStatus(statusFormatter.format(state, config));
- }
+ private void publishStatus() {
+ context.publishStatus(statusFormatter.format(state, config));
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/buffer/TextAreaBuffer.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/buffer/TextAreaBuffer.java
index 36fe9d3..428976e 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/buffer/TextAreaBuffer.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/buffer/TextAreaBuffer.java
@@ -6,59 +6,59 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class TextAreaBuffer implements EditorBuffer {
- private final EditorTextArea textArea;
+ private final EditorTextArea textArea;
- @Override
- public String getText() {
- return textArea.getText();
- }
+ @Override
+ public String getText() {
+ return textArea.getText();
+ }
- @Override
- public void setText(final String text) {
- if (text.equals(textArea.getText())) {
- return;
- }
- textArea.setText(text);
- textArea.syncCursorState();
- }
+ @Override
+ public void setText(final String text) {
+ if (text.equals(textArea.getText())) {
+ return;
+ }
+ textArea.setText(text);
+ textArea.syncCursorState();
+ }
- @Override
- public int getCursorPosition() {
- return textArea.getCursorPosition();
- }
+ @Override
+ public int getCursorPosition() {
+ return textArea.getCursorPosition();
+ }
- @Override
- public void setCursorPosition(final int cursorPosition) {
- final int clampedCursor = Math.max(0, Math.min(cursorPosition, textArea.getText().length()));
- if (clampedCursor == textArea.getCursorPosition()) {
- return;
- }
- textArea.setCursorPosition(clampedCursor);
- textArea.syncCursorState();
- }
+ @Override
+ public void setCursorPosition(final int cursorPosition) {
+ final int clampedCursor = Math.max(0, Math.min(cursorPosition, textArea.getText().length()));
+ if (clampedCursor == textArea.getCursorPosition()) {
+ return;
+ }
+ textArea.setCursorPosition(clampedCursor);
+ textArea.syncCursorState();
+ }
- @Override
- public int getCursorLine() {
- return textArea.getCursorLine();
- }
+ @Override
+ public int getCursorLine() {
+ return textArea.getCursorLine();
+ }
- @Override
- public int getLines() {
- return textArea.getLines();
- }
+ @Override
+ public int getLines() {
+ return textArea.getLines();
+ }
- @Override
- public void moveCursorLine(final int line) {
- textArea.moveCursorLine(line);
- }
+ @Override
+ public void moveCursorLine(final int line) {
+ textArea.moveCursorLine(line);
+ }
- @Override
- public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
- textArea.setSelectionEndpoints(selectionStart, cursorPosition);
- }
+ @Override
+ public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
+ textArea.setSelectionEndpoints(selectionStart, cursorPosition);
+ }
- @Override
- public void clearSelection() {
- textArea.clearSelection();
- }
+ @Override
+ public void clearSelection() {
+ textArea.clearSelection();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java
index a15232d..63ebff9 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java
@@ -24,683 +24,683 @@ import java.util.Set;
import java.util.function.Consumer;
public class KeyContext {
- private final EditorBuffer editorBuffer;
- private final Consumer<String> statusUpdater;
- private final TextNavigation navigation;
- private final UndoManager undoManager;
- private final Register register;
- private final VimConfig config;
+ private final EditorBuffer editorBuffer;
+ private final Consumer<String> statusUpdater;
+ private final TextNavigation navigation;
+ private final UndoManager undoManager;
+ private final Register register;
+ private final VimConfig config;
- private String statusText;
- private String lastSearchQuery;
- private SearchDirection lastSearchDirection;
- private SearchIterator searchIterator;
- private String searchIteratorQuery;
- private String searchIteratorText;
- private int suppressedTypedCommands;
- private boolean suppressNextRedoTyped;
- private KeyEvent currentKeyEvent;
+ private String statusText;
+ private String lastSearchQuery;
+ private SearchDirection lastSearchDirection;
+ private SearchIterator searchIterator;
+ private String searchIteratorQuery;
+ private String searchIteratorText;
+ private int suppressedTypedCommands;
+ private boolean suppressNextRedoTyped;
+ private KeyEvent currentKeyEvent;
- public KeyContext(final EditorBuffer editorBuffer, final Consumer<String> statusUpdater,
- final TextNavigation navigation, final UndoManager undoManager, final Register register,
- final VimConfig config) {
- this.editorBuffer = editorBuffer;
- this.statusUpdater = statusUpdater;
- this.navigation = navigation;
- this.undoManager = undoManager;
- this.register = register;
- this.config = config;
- this.statusText = "";
- this.lastSearchQuery = "";
- this.lastSearchDirection = SearchDirection.FORWARD;
- this.searchIterator = null;
- this.searchIteratorQuery = "";
- this.searchIteratorText = "";
- this.suppressedTypedCommands = 0;
- this.suppressNextRedoTyped = false;
- this.currentKeyEvent = new KeyEvent(Input.Keys.UNKNOWN, Set.of());
- }
+ public KeyContext(final EditorBuffer editorBuffer, final Consumer<String> statusUpdater,
+ final TextNavigation navigation, final UndoManager undoManager, final Register register,
+ final VimConfig config) {
+ this.editorBuffer = editorBuffer;
+ this.statusUpdater = statusUpdater;
+ this.navigation = navigation;
+ this.undoManager = undoManager;
+ this.register = register;
+ this.config = config;
+ this.statusText = "";
+ this.lastSearchQuery = "";
+ this.lastSearchDirection = SearchDirection.FORWARD;
+ this.searchIterator = null;
+ this.searchIteratorQuery = "";
+ this.searchIteratorText = "";
+ this.suppressedTypedCommands = 0;
+ this.suppressNextRedoTyped = false;
+ this.currentKeyEvent = new KeyEvent(Input.Keys.UNKNOWN, Set.of());
+ }
- public EditorBuffer editorBuffer() {
- return editorBuffer;
- }
+ public EditorBuffer editorBuffer() {
+ return editorBuffer;
+ }
- public TextNavigation navigation() {
- return navigation;
- }
+ public TextNavigation navigation() {
+ return navigation;
+ }
- public VimConfig config() {
- return config;
- }
+ public VimConfig config() {
+ return config;
+ }
- public void setCurrentKeyEvent(final KeyEvent currentKeyEvent) {
- this.currentKeyEvent = currentKeyEvent;
- }
+ public void setCurrentKeyEvent(final KeyEvent currentKeyEvent) {
+ this.currentKeyEvent = currentKeyEvent;
+ }
- public KeyEvent currentKeyEvent() {
- return currentKeyEvent;
- }
+ public KeyEvent currentKeyEvent() {
+ return currentKeyEvent;
+ }
- public String getStatusText() {
- return statusText;
- }
+ public String getStatusText() {
+ return statusText;
+ }
- public void publishStatus(final String status) {
- if (!status.equals(statusText)) {
- statusText = status;
- if (statusUpdater != null) {
- statusUpdater.accept(statusText);
- }
- }
- }
+ public void publishStatus(final String status) {
+ if (!status.equals(statusText)) {
+ statusText = status;
+ if (statusUpdater != null) {
+ statusUpdater.accept(statusText);
+ }
+ }
+ }
- public String getLastSearchQuery() {
- return lastSearchQuery;
- }
+ public String getLastSearchQuery() {
+ return lastSearchQuery;
+ }
- public void setLastSearchQuery(final String lastSearchQuery) {
- this.lastSearchQuery = lastSearchQuery == null ? "" : lastSearchQuery;
- }
+ public void setLastSearchQuery(final String lastSearchQuery) {
+ this.lastSearchQuery = lastSearchQuery == null ? "" : lastSearchQuery;
+ }
- public void incrementSuppressedTypedCommands() {
- suppressedTypedCommands++;
- }
+ public void incrementSuppressedTypedCommands() {
+ suppressedTypedCommands++;
+ }
- public boolean consumeSuppressedTypedCommand() {
- if (suppressedTypedCommands <= 0) {
- return false;
- }
- suppressedTypedCommands--;
- return true;
- }
+ public boolean consumeSuppressedTypedCommand() {
+ if (suppressedTypedCommands <= 0) {
+ return false;
+ }
+ suppressedTypedCommands--;
+ return true;
+ }
- public void suppressNextRedoTyped() {
- suppressNextRedoTyped = true;
- }
+ public void suppressNextRedoTyped() {
+ suppressNextRedoTyped = true;
+ }
- public boolean consumeRedoTypedSuppression() {
- if (!suppressNextRedoTyped) {
- return false;
- }
- suppressNextRedoTyped = false;
- return true;
- }
+ public boolean consumeRedoTypedSuppression() {
+ if (!suppressNextRedoTyped) {
+ return false;
+ }
+ suppressNextRedoTyped = false;
+ return true;
+ }
- public void clearRedoTypedSuppression() {
- suppressNextRedoTyped = false;
- }
+ public void clearRedoTypedSuppression() {
+ suppressNextRedoTyped = false;
+ }
- public Character toCommandCharacter() {
- final int keycode = currentKeyEvent.keycode();
- final boolean shiftDown = currentKeyEvent.hasModifier(EditorModifier.SHIFT);
+ public Character toCommandCharacter() {
+ final int keycode = currentKeyEvent.keycode();
+ final boolean shiftDown = currentKeyEvent.hasModifier(EditorModifier.SHIFT);
- if (keycode == Input.Keys.SLASH) {
- return shiftDown ? '?' : '/';
- }
+ if (keycode == Input.Keys.SLASH) {
+ return shiftDown ? '?' : '/';
+ }
- if (keycode == Input.Keys.NUM_4 && shiftDown) {
- return '$';
- }
+ if (keycode == Input.Keys.NUM_4 && shiftDown) {
+ return '$';
+ }
- final String keyName = Input.Keys.toString(keycode);
- if (keyName == null || keyName.length() != 1) {
- return null;
- }
+ final String keyName = Input.Keys.toString(keycode);
+ if (keyName == null || keyName.length() != 1) {
+ return null;
+ }
- final char key = keyName.charAt(0);
- if (Character.isLetter(key)) {
- return shiftDown ? Character.toUpperCase(key) : Character.toLowerCase(key);
- }
+ final char key = keyName.charAt(0);
+ if (Character.isLetter(key)) {
+ return shiftDown ? Character.toUpperCase(key) : Character.toLowerCase(key);
+ }
- if (Character.isDigit(key) && !shiftDown) {
- return key;
- }
+ if (Character.isDigit(key) && !shiftDown) {
+ return key;
+ }
- return null;
- }
+ return null;
+ }
- public int readCount(final int count) {
- return count > 0 ? count : 1;
- }
+ public int readCount(final int count) {
+ return count > 0 ? count : 1;
+ }
- public int resetPreferredColumn(final char character, final int preferredColumn) {
- if (character == 'j' || character == 'k') {
- return preferredColumn;
- }
- return -1;
- }
+ public int resetPreferredColumn(final char character, final int preferredColumn) {
+ if (character == 'j' || character == 'k') {
+ return preferredColumn;
+ }
+ return -1;
+ }
- public void moveLeft() {
- final int cursor = editorBuffer.getCursorPosition();
- final int lineStart = navigation.findLineStart(editorBuffer.getText(), cursor);
- if (cursor > lineStart) {
- editorBuffer.setCursorPosition(cursor - 1);
- }
- }
+ public void moveLeft() {
+ final int cursor = editorBuffer.getCursorPosition();
+ final int lineStart = navigation.findLineStart(editorBuffer.getText(), cursor);
+ if (cursor > lineStart) {
+ editorBuffer.setCursorPosition(cursor - 1);
+ }
+ }
- public void moveRightNormal() {
- final String text = editorBuffer.getText();
- final int cursor = editorBuffer.getCursorPosition();
- final int lineEnd = navigation.findLineEnd(text, cursor);
- if (cursor < lineEnd) {
- editorBuffer.setCursorPosition(cursor + 1);
- }
- }
+ public void moveRightNormal() {
+ final String text = editorBuffer.getText();
+ final int cursor = editorBuffer.getCursorPosition();
+ final int lineEnd = navigation.findLineEnd(text, cursor);
+ if (cursor < lineEnd) {
+ editorBuffer.setCursorPosition(cursor + 1);
+ }
+ }
- public void moveRightForAppend() {
- final String text = editorBuffer.getText();
- final int cursor = editorBuffer.getCursorPosition();
- if (cursor < text.length() && text.charAt(cursor) != '\n') {
- editorBuffer.setCursorPosition(cursor + 1);
- }
- }
+ public void moveRightForAppend() {
+ final String text = editorBuffer.getText();
+ final int cursor = editorBuffer.getCursorPosition();
+ if (cursor < text.length() && text.charAt(cursor) != '\n') {
+ editorBuffer.setCursorPosition(cursor + 1);
+ }
+ }
- public int moveVertical(final int delta, final int repeats, final int preferredColumn,
- final boolean clampInNormalMode) {
- int preferred = preferredColumn;
- for (int i = 0; i < repeats; i++) {
- preferred = moveVerticalOnce(delta, preferred, clampInNormalMode);
- }
- return preferred;
- }
+ public int moveVertical(final int delta, final int repeats, final int preferredColumn,
+ final boolean clampInNormalMode) {
+ int preferred = preferredColumn;
+ for (int i = 0; i < repeats; i++) {
+ preferred = moveVerticalOnce(delta, preferred, clampInNormalMode);
+ }
+ return preferred;
+ }
- private int moveVerticalOnce(final int delta, final int preferredColumn, final boolean clampInNormalMode) {
- if (delta == 0) {
- return preferredColumn;
- }
+ private int moveVerticalOnce(final int delta, final int preferredColumn, final boolean clampInNormalMode) {
+ if (delta == 0) {
+ return preferredColumn;
+ }
- final String text = editorBuffer.getText();
- if (text.isEmpty()) {
- return preferredColumn;
- }
+ final String text = editorBuffer.getText();
+ if (text.isEmpty()) {
+ return preferredColumn;
+ }
- final int cursor = editorBuffer.getCursorPosition();
- final int currentLineStart = navigation.findLineStart(text, cursor);
- final int resolvedPreferred = preferredColumn < 0 ? Math.max(0, cursor - currentLineStart) : preferredColumn;
+ final int cursor = editorBuffer.getCursorPosition();
+ final int currentLineStart = navigation.findLineStart(text, cursor);
+ final int resolvedPreferred = preferredColumn < 0 ? Math.max(0, cursor - currentLineStart) : preferredColumn;
- int targetStart = currentLineStart;
- if (delta > 0) {
- targetStart = navigation.findNextLineStart(text, targetStart);
- if (targetStart < 0 || targetStart > text.length()) {
- return resolvedPreferred;
- }
- } else {
- targetStart = navigation.findPreviousLineStart(text, targetStart);
- if (targetStart < 0) {
- return resolvedPreferred;
- }
- }
+ int targetStart = currentLineStart;
+ if (delta > 0) {
+ targetStart = navigation.findNextLineStart(text, targetStart);
+ if (targetStart < 0 || targetStart > text.length()) {
+ return resolvedPreferred;
+ }
+ } else {
+ targetStart = navigation.findPreviousLineStart(text, targetStart);
+ if (targetStart < 0) {
+ return resolvedPreferred;
+ }
+ }
- final int targetEndExclusive = navigation.findLineEndExclusiveByStart(text, targetStart);
- final int targetLineLength = Math.max(0, targetEndExclusive - targetStart);
- final int maxColumn = targetLineLength > 0 ? targetLineLength - 1 : 0;
- final int targetColumn = Math.min(resolvedPreferred, maxColumn);
- editorBuffer.setCursorPosition(targetStart + targetColumn);
- if (clampInNormalMode) {
- clampCursorInNormalMode();
- }
- return resolvedPreferred;
- }
+ final int targetEndExclusive = navigation.findLineEndExclusiveByStart(text, targetStart);
+ final int targetLineLength = Math.max(0, targetEndExclusive - targetStart);
+ final int maxColumn = targetLineLength > 0 ? targetLineLength - 1 : 0;
+ final int targetColumn = Math.min(resolvedPreferred, maxColumn);
+ editorBuffer.setCursorPosition(targetStart + targetColumn);
+ if (clampInNormalMode) {
+ clampCursorInNormalMode();
+ }
+ return resolvedPreferred;
+ }
- public void moveWordForward() {
- final String text = editorBuffer.getText();
- int cursor = editorBuffer.getCursorPosition();
- final int length = text.length();
+ public void moveWordForward() {
+ final String text = editorBuffer.getText();
+ int cursor = editorBuffer.getCursorPosition();
+ final int length = text.length();
- if (cursor >= length) {
- return;
- }
+ if (cursor >= length) {
+ return;
+ }
- final int originalCursor = cursor;
- final char current = text.charAt(cursor);
+ final int originalCursor = cursor;
+ final char current = text.charAt(cursor);
- if (navigation.isWordCharacter(current)) {
- while (cursor < length && navigation.isWordCharacter(text.charAt(cursor))) {
- cursor++;
- }
- while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
- cursor++;
- }
- } else if (navigation.isPunctuationWord(current)) {
- while (cursor < length && navigation.isPunctuationWord(text.charAt(cursor))) {
- cursor++;
- }
- while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
- cursor++;
- }
- if (cursor >= length) {
- cursor = originalCursor;
- }
- } else if (navigation.isInlineWhitespace(current)) {
- while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
- cursor++;
- }
- } else if (current == '\n' || current == '\r') {
- if (cursor < length) {
- cursor++;
- }
- while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
- cursor++;
- }
- }
+ if (navigation.isWordCharacter(current)) {
+ while (cursor < length && navigation.isWordCharacter(text.charAt(cursor))) {
+ cursor++;
+ }
+ while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
+ cursor++;
+ }
+ } else if (navigation.isPunctuationWord(current)) {
+ while (cursor < length && navigation.isPunctuationWord(text.charAt(cursor))) {
+ cursor++;
+ }
+ while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
+ cursor++;
+ }
+ if (cursor >= length) {
+ cursor = originalCursor;
+ }
+ } else if (navigation.isInlineWhitespace(current)) {
+ while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
+ cursor++;
+ }
+ } else if (current == '\n' || current == '\r') {
+ if (cursor < length) {
+ cursor++;
+ }
+ while (cursor < length && navigation.isInlineWhitespace(text.charAt(cursor))) {
+ cursor++;
+ }
+ }
- editorBuffer.setCursorPosition(Math.min(cursor, length));
- }
+ editorBuffer.setCursorPosition(Math.min(cursor, length));
+ }
- public void moveWordBackward() {
- final String text = editorBuffer.getText();
- int cursor = editorBuffer.getCursorPosition();
+ public void moveWordBackward() {
+ final String text = editorBuffer.getText();
+ int cursor = editorBuffer.getCursorPosition();
- if (cursor <= 0) {
- return;
- }
+ if (cursor <= 0) {
+ return;
+ }
- cursor--;
- while (cursor > 0 && Character.isWhitespace(text.charAt(cursor))) {
- cursor--;
- }
+ cursor--;
+ while (cursor > 0 && Character.isWhitespace(text.charAt(cursor))) {
+ cursor--;
+ }
- final char current = text.charAt(cursor);
- if (navigation.isWordCharacter(current)) {
- while (cursor > 0 && navigation.isWordCharacter(text.charAt(cursor - 1))) {
- cursor--;
- }
- } else {
- while (cursor > 0) {
- final char previous = text.charAt(cursor - 1);
- if (Character.isWhitespace(previous) || navigation.isWordCharacter(previous)) {
- break;
- }
- cursor--;
- }
- }
+ final char current = text.charAt(cursor);
+ if (navigation.isWordCharacter(current)) {
+ while (cursor > 0 && navigation.isWordCharacter(text.charAt(cursor - 1))) {
+ cursor--;
+ }
+ } else {
+ while (cursor > 0) {
+ final char previous = text.charAt(cursor - 1);
+ if (Character.isWhitespace(previous) || navigation.isWordCharacter(previous)) {
+ break;
+ }
+ cursor--;
+ }
+ }
- editorBuffer.setCursorPosition(cursor);
- }
+ editorBuffer.setCursorPosition(cursor);
+ }
- public void moveLineStart() {
- final int cursor = editorBuffer.getCursorPosition();
- editorBuffer.setCursorPosition(navigation.findLineStart(editorBuffer.getText(), cursor));
- }
+ public void moveLineStart() {
+ final int cursor = editorBuffer.getCursorPosition();
+ editorBuffer.setCursorPosition(navigation.findLineStart(editorBuffer.getText(), cursor));
+ }
- public void moveLineEnd() {
- final int cursor = editorBuffer.getCursorPosition();
- editorBuffer.setCursorPosition(navigation.findLineEnd(editorBuffer.getText(), cursor));
- }
+ public void moveLineEnd() {
+ final int cursor = editorBuffer.getCursorPosition();
+ editorBuffer.setCursorPosition(navigation.findLineEnd(editorBuffer.getText(), cursor));
+ }
- public void moveDocumentEnd() {
- final String text = editorBuffer.getText();
- if (!text.isEmpty()) {
- editorBuffer.setCursorPosition(navigation.lastNavigablePosition(text));
- }
- }
+ public void moveDocumentEnd() {
+ final String text = editorBuffer.getText();
+ if (!text.isEmpty()) {
+ editorBuffer.setCursorPosition(navigation.lastNavigablePosition(text));
+ }
+ }
- public void moveDocumentStart() {
- editorBuffer.setCursorPosition(0);
- clampCursorInNormalMode();
- }
+ public void moveDocumentStart() {
+ editorBuffer.setCursorPosition(0);
+ clampCursorInNormalMode();
+ }
- public void openLineBelow() {
- final String text = editorBuffer.getText();
- final int insertAt = navigation.findBelowLineInsertionIndex(text, editorBuffer.getCursorPosition());
- editorBuffer.setText(text.substring(0, insertAt) + "\n" + text.substring(insertAt));
- editorBuffer.setCursorPosition(Math.min(insertAt, editorBuffer.getText().length()));
- invalidateSearchIterator();
- recordUndoState();
- }
+ public void openLineBelow() {
+ final String text = editorBuffer.getText();
+ final int insertAt = navigation.findBelowLineInsertionIndex(text, editorBuffer.getCursorPosition());
+ editorBuffer.setText(text.substring(0, insertAt) + "\n" + text.substring(insertAt));
+ editorBuffer.setCursorPosition(Math.min(insertAt, editorBuffer.getText().length()));
+ invalidateSearchIterator();
+ recordUndoState();
+ }
- public void openLineAbove() {
- final String text = editorBuffer.getText();
- final int lineStart = navigation.findLineStart(text, editorBuffer.getCursorPosition());
- editorBuffer.setText(text.substring(0, lineStart) + "\n" + text.substring(lineStart));
- editorBuffer.setCursorPosition(lineStart);
- invalidateSearchIterator();
- recordUndoState();
- }
+ public void openLineAbove() {
+ final String text = editorBuffer.getText();
+ final int lineStart = navigation.findLineStart(text, editorBuffer.getCursorPosition());
+ editorBuffer.setText(text.substring(0, lineStart) + "\n" + text.substring(lineStart));
+ editorBuffer.setCursorPosition(lineStart);
+ invalidateSearchIterator();
+ recordUndoState();
+ }
- public void deleteCharUnderCursor() {
- final String text = editorBuffer.getText();
- final int cursor = editorBuffer.getCursorPosition();
- if (cursor >= text.length() || text.charAt(cursor) == '\n') {
- return;
- }
- register.setText(String.valueOf(text.charAt(cursor)));
- register.setType(RegisterType.CHARACTER);
- editorBuffer.setText(text.substring(0, cursor) + text.substring(cursor + 1));
- editorBuffer.setCursorPosition(Math.min(cursor, editorBuffer.getText().length()));
- invalidateSearchIterator();
- }
+ public void deleteCharUnderCursor() {
+ final String text = editorBuffer.getText();
+ final int cursor = editorBuffer.getCursorPosition();
+ if (cursor >= text.length() || text.charAt(cursor) == '\n') {
+ return;
+ }
+ register.setText(String.valueOf(text.charAt(cursor)));
+ register.setType(RegisterType.CHARACTER);
+ editorBuffer.setText(text.substring(0, cursor) + text.substring(cursor + 1));
+ editorBuffer.setCursorPosition(Math.min(cursor, editorBuffer.getText().length()));
+ invalidateSearchIterator();
+ }
- public void deleteLines(final int repeats) {
- final String text = editorBuffer.getText();
- final int start = navigation.findLineStart(text, editorBuffer.getCursorPosition());
- int end = start;
- for (int i = 0; i < repeats; i++) {
- end = navigation.findNextLineStart(text, end);
- if (end == -1) {
- end = text.length();
- break;
- }
- }
- if (start >= end) {
- return;
- }
- register.setText(normalizeLineRegister(text.substring(start, end)));
- register.setType(RegisterType.LINE);
- editorBuffer.setText(text.substring(0, start) + text.substring(end));
- editorBuffer.setCursorPosition(Math.min(start, editorBuffer.getText().length()));
- clampCursorInNormalMode();
- invalidateSearchIterator();
- }
+ public void deleteLines(final int repeats) {
+ final String text = editorBuffer.getText();
+ final int start = navigation.findLineStart(text, editorBuffer.getCursorPosition());
+ int end = start;
+ for (int i = 0; i < repeats; i++) {
+ end = navigation.findNextLineStart(text, end);
+ if (end == -1) {
+ end = text.length();
+ break;
+ }
+ }
+ if (start >= end) {
+ return;
+ }
+ register.setText(normalizeLineRegister(text.substring(start, end)));
+ register.setType(RegisterType.LINE);
+ editorBuffer.setText(text.substring(0, start) + text.substring(end));
+ editorBuffer.setCursorPosition(Math.min(start, editorBuffer.getText().length()));
+ clampCursorInNormalMode();
+ invalidateSearchIterator();
+ }
- public void yankLines(final int repeats) {
- final String text = editorBuffer.getText();
- final int start = navigation.findLineStart(text, editorBuffer.getCursorPosition());
- int end = start;
- for (int i = 0; i < repeats; i++) {
- end = navigation.findNextLineStart(text, end);
- if (end == -1) {
- end = text.length();
- break;
- }
- }
- if (start < end) {
- register.setText(normalizeLineRegister(text.substring(start, end)));
- register.setType(RegisterType.LINE);
- }
- }
+ public void yankLines(final int repeats) {
+ final String text = editorBuffer.getText();
+ final int start = navigation.findLineStart(text, editorBuffer.getCursorPosition());
+ int end = start;
+ for (int i = 0; i < repeats; i++) {
+ end = navigation.findNextLineStart(text, end);
+ if (end == -1) {
+ end = text.length();
+ break;
+ }
+ }
+ if (start < end) {
+ register.setText(normalizeLineRegister(text.substring(start, end)));
+ register.setType(RegisterType.LINE);
+ }
+ }
- public void changeLines(final int repeats) {
- deleteLines(repeats);
- }
+ public void changeLines(final int repeats) {
+ deleteLines(repeats);
+ }
- public void pasteAfter() {
- if (register.getText().isEmpty()) {
- return;
- }
- final String text = editorBuffer.getText();
- final int cursor = editorBuffer.getCursorPosition();
- if (register.getType() == RegisterType.LINE) {
- final int insertAt = navigation.findBelowLineInsertionIndex(text, cursor);
- String inserted = register.getText();
- if (insertAt == text.length() && insertAt > 0 && text.charAt(insertAt - 1) != '\n') {
- inserted = "\n" + inserted;
- }
- editorBuffer.setText(text.substring(0, insertAt) + inserted + text.substring(insertAt));
- editorBuffer.setCursorPosition(Math.min(insertAt, editorBuffer.getText().length()));
- invalidateSearchIterator();
- return;
- }
+ public void pasteAfter() {
+ if (register.getText().isEmpty()) {
+ return;
+ }
+ final String text = editorBuffer.getText();
+ final int cursor = editorBuffer.getCursorPosition();
+ if (register.getType() == RegisterType.LINE) {
+ final int insertAt = navigation.findBelowLineInsertionIndex(text, cursor);
+ String inserted = register.getText();
+ if (insertAt == text.length() && insertAt > 0 && text.charAt(insertAt - 1) != '\n') {
+ inserted = "\n" + inserted;
+ }
+ editorBuffer.setText(text.substring(0, insertAt) + inserted + text.substring(insertAt));
+ editorBuffer.setCursorPosition(Math.min(insertAt, editorBuffer.getText().length()));
+ invalidateSearchIterator();
+ return;
+ }
- final int insertAt = Math.min(cursor + 1, text.length());
- editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
- editorBuffer.setCursorPosition(insertAt + register.getText().length() - 1);
- invalidateSearchIterator();
- }
+ final int insertAt = Math.min(cursor + 1, text.length());
+ editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
+ editorBuffer.setCursorPosition(insertAt + register.getText().length() - 1);
+ invalidateSearchIterator();
+ }
- public void pasteBefore() {
- if (register.getText().isEmpty()) {
- return;
- }
- final String text = editorBuffer.getText();
- final int cursor = editorBuffer.getCursorPosition();
- if (register.getType() == RegisterType.LINE) {
- final int insertAt = navigation.findLineStart(text, cursor);
- editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
- editorBuffer.setCursorPosition(insertAt);
- invalidateSearchIterator();
- return;
- }
+ public void pasteBefore() {
+ if (register.getText().isEmpty()) {
+ return;
+ }
+ final String text = editorBuffer.getText();
+ final int cursor = editorBuffer.getCursorPosition();
+ if (register.getType() == RegisterType.LINE) {
+ final int insertAt = navigation.findLineStart(text, cursor);
+ editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
+ editorBuffer.setCursorPosition(insertAt);
+ invalidateSearchIterator();
+ return;
+ }
- final int insertAt = cursor;
- editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
- editorBuffer.setCursorPosition(insertAt + register.getText().length() - 1);
- invalidateSearchIterator();
- }
+ final int insertAt = cursor;
+ editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
+ editorBuffer.setCursorPosition(insertAt + register.getText().length() - 1);
+ invalidateSearchIterator();
+ }
- public void updateVisualSelection(final int anchor) {
- final int cursor = editorBuffer.getCursorPosition();
- if (cursor != anchor) {
- int selectionStart = anchor;
- if (cursor < anchor && anchor < editorBuffer.getText().length()) {
- selectionStart = anchor + 1;
- }
- editorBuffer.setSelectionEndpoints(selectionStart, cursor);
- } else {
- editorBuffer.clearSelection();
- }
- }
+ public void updateVisualSelection(final int anchor) {
+ final int cursor = editorBuffer.getCursorPosition();
+ if (cursor != anchor) {
+ int selectionStart = anchor;
+ if (cursor < anchor && anchor < editorBuffer.getText().length()) {
+ selectionStart = anchor + 1;
+ }
+ editorBuffer.setSelectionEndpoints(selectionStart, cursor);
+ } else {
+ editorBuffer.clearSelection();
+ }
+ }
- public void updateVisualLineSelection(final int anchorLine, final int cursorLine) {
- final String text = editorBuffer.getText();
- final int startLine = Math.min(anchorLine, cursorLine);
- final int endLine = Math.max(anchorLine, cursorLine);
- final int start = navigation.findLineStartByLine(text, startLine);
- final int end = navigation.findLineSelectionEndByLine(text, endLine);
- if (start < end) {
- final int selectionStart = cursorLine > anchorLine ? start : end;
- final int cursorPosition = cursorLine > anchorLine
- ? resolveVisualLineCursorPosition(text, start, end)
- : start;
- editorBuffer.setSelectionEndpoints(selectionStart, cursorPosition);
- } else {
- editorBuffer.clearSelection();
- }
- }
+ public void updateVisualLineSelection(final int anchorLine, final int cursorLine) {
+ final String text = editorBuffer.getText();
+ final int startLine = Math.min(anchorLine, cursorLine);
+ final int endLine = Math.max(anchorLine, cursorLine);
+ final int start = navigation.findLineStartByLine(text, startLine);
+ final int end = navigation.findLineSelectionEndByLine(text, endLine);
+ if (start < end) {
+ final int selectionStart = cursorLine > anchorLine ? start : end;
+ final int cursorPosition = cursorLine > anchorLine
+ ? resolveVisualLineCursorPosition(text, start, end)
+ : start;
+ editorBuffer.setSelectionEndpoints(selectionStart, cursorPosition);
+ } else {
+ editorBuffer.clearSelection();
+ }
+ }
- public int adjustVisualLineCursor(final int cursorLine, final int delta) {
- final int maxLine = maxSelectableLineIndex();
- return Math.max(0, Math.min(maxLine, cursorLine + delta));
- }
+ public int adjustVisualLineCursor(final int cursorLine, final int delta) {
+ final int maxLine = maxSelectableLineIndex();
+ return Math.max(0, Math.min(maxLine, cursorLine + delta));
+ }
- public int maxSelectableLineIndex() {
- int totalLines = editorBuffer.getLines();
- final String text = editorBuffer.getText();
- if (totalLines > 1 && text.endsWith("\n")) {
- totalLines--;
- }
- return Math.max(0, totalLines - 1);
- }
+ public int maxSelectableLineIndex() {
+ int totalLines = editorBuffer.getLines();
+ final String text = editorBuffer.getText();
+ if (totalLines > 1 && text.endsWith("\n")) {
+ totalLines--;
+ }
+ return Math.max(0, totalLines - 1);
+ }
- private int resolveVisualLineCursorPosition(final String text, final int lineStart, final int selectionEnd) {
- if (!text.isEmpty() && selectionEnd == text.length() && text.charAt(text.length() - 1) == '\n') {
- return Math.max(lineStart, selectionEnd - 1);
- }
- return selectionEnd;
- }
+ private int resolveVisualLineCursorPosition(final String text, final int lineStart, final int selectionEnd) {
+ if (!text.isEmpty() && selectionEnd == text.length() && text.charAt(text.length() - 1) == '\n') {
+ return Math.max(lineStart, selectionEnd - 1);
+ }
+ return selectionEnd;
+ }
- public HandleResult applyVisualOperator(final VisualState state, final PendingOperator operator) {
- final int start = Math.min(state.anchor(), editorBuffer.getCursorPosition());
- final int max = Math.max(state.anchor(), editorBuffer.getCursorPosition());
- final int end = Math.min(editorBuffer.getText().length(), max + 1);
- if (start >= end) {
- editorBuffer.clearSelection();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ public HandleResult applyVisualOperator(final VisualState state, final PendingOperator operator) {
+ final int start = Math.min(state.anchor(), editorBuffer.getCursorPosition());
+ final int max = Math.max(state.anchor(), editorBuffer.getCursorPosition());
+ final int end = Math.min(editorBuffer.getText().length(), max + 1);
+ if (start >= end) {
+ editorBuffer.clearSelection();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- final String text = editorBuffer.getText();
- register.setText(text.substring(start, end));
- register.setType(RegisterType.CHARACTER);
+ final String text = editorBuffer.getText();
+ register.setText(text.substring(start, end));
+ register.setType(RegisterType.CHARACTER);
- if (operator == PendingOperator.YANK) {
- editorBuffer.clearSelection();
- editorBuffer.setCursorPosition(start);
- clampCursorInNormalMode();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ if (operator == PendingOperator.YANK) {
+ editorBuffer.clearSelection();
+ editorBuffer.setCursorPosition(start);
+ clampCursorInNormalMode();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- editorBuffer.setText(text.substring(0, start) + text.substring(end));
- editorBuffer.setCursorPosition(Math.min(start, editorBuffer.getText().length()));
- editorBuffer.clearSelection();
- recordUndoState();
- invalidateSearchIterator();
+ editorBuffer.setText(text.substring(0, start) + text.substring(end));
+ editorBuffer.setCursorPosition(Math.min(start, editorBuffer.getText().length()));
+ editorBuffer.clearSelection();
+ recordUndoState();
+ invalidateSearchIterator();
- if (operator == PendingOperator.CHANGE) {
- return HandleResult.handled(new InsertState(editorBuffer.getText(), editorBuffer.getCursorPosition()));
- }
- clampCursorInNormalMode();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ if (operator == PendingOperator.CHANGE) {
+ return HandleResult.handled(new InsertState(editorBuffer.getText(), editorBuffer.getCursorPosition()));
+ }
+ clampCursorInNormalMode();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- public HandleResult applyVisualLineOperator(final VisualLineState state, final PendingOperator operator) {
- final String text = editorBuffer.getText();
- final int startLine = Math.min(state.anchorLine(), state.cursorLine());
- final int endLine = Math.max(state.anchorLine(), state.cursorLine());
- final int start = navigation.findLineStartByLine(text, startLine);
- final int end = navigation.findLineSelectionEndByLine(text, endLine);
- if (start >= end) {
- editorBuffer.clearSelection();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ public HandleResult applyVisualLineOperator(final VisualLineState state, final PendingOperator operator) {
+ final String text = editorBuffer.getText();
+ final int startLine = Math.min(state.anchorLine(), state.cursorLine());
+ final int endLine = Math.max(state.anchorLine(), state.cursorLine());
+ final int start = navigation.findLineStartByLine(text, startLine);
+ final int end = navigation.findLineSelectionEndByLine(text, endLine);
+ if (start >= end) {
+ editorBuffer.clearSelection();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- register.setText(normalizeLineRegister(text.substring(start, end)));
- register.setType(RegisterType.LINE);
+ register.setText(normalizeLineRegister(text.substring(start, end)));
+ register.setType(RegisterType.LINE);
- if (operator == PendingOperator.YANK) {
- editorBuffer.clearSelection();
- editorBuffer.setCursorPosition(start);
- clampCursorInNormalMode();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ if (operator == PendingOperator.YANK) {
+ editorBuffer.clearSelection();
+ editorBuffer.setCursorPosition(start);
+ clampCursorInNormalMode();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- editorBuffer.setText(text.substring(0, start) + text.substring(end));
- editorBuffer.setCursorPosition(Math.min(start, editorBuffer.getText().length()));
- editorBuffer.clearSelection();
- recordUndoState();
- invalidateSearchIterator();
+ editorBuffer.setText(text.substring(0, start) + text.substring(end));
+ editorBuffer.setCursorPosition(Math.min(start, editorBuffer.getText().length()));
+ editorBuffer.clearSelection();
+ recordUndoState();
+ invalidateSearchIterator();
- if (operator == PendingOperator.CHANGE) {
- return HandleResult.handled(new InsertState(editorBuffer.getText(), editorBuffer.getCursorPosition()));
- }
- clampCursorInNormalMode();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ if (operator == PendingOperator.CHANGE) {
+ return HandleResult.handled(new InsertState(editorBuffer.getText(), editorBuffer.getCursorPosition()));
+ }
+ clampCursorInNormalMode();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- public boolean findNext(final String query, final SearchDirection direction) {
- if (query == null || query.isEmpty()) {
- return false;
- }
- final String text = editorBuffer.getText();
- if (text.isEmpty()) {
- return false;
- }
+ public boolean findNext(final String query, final SearchDirection direction) {
+ if (query == null || query.isEmpty()) {
+ return false;
+ }
+ final String text = editorBuffer.getText();
+ if (text.isEmpty()) {
+ return false;
+ }
- if (searchIterator == null || !query.equals(searchIteratorQuery) || direction != lastSearchDirection
- || !text.equals(searchIteratorText)) {
- searchIterator = new SearchIterator(text, query, editorBuffer.getCursorPosition(), direction,
- config.wrapSearch());
- searchIteratorQuery = query;
- searchIteratorText = text;
- lastSearchDirection = direction;
- }
+ if (searchIterator == null || !query.equals(searchIteratorQuery) || direction != lastSearchDirection
+ || !text.equals(searchIteratorText)) {
+ searchIterator = new SearchIterator(text, query, editorBuffer.getCursorPosition(), direction,
+ config.wrapSearch());
+ searchIteratorQuery = query;
+ searchIteratorText = text;
+ lastSearchDirection = direction;
+ }
- final OptionalInt found = searchIterator.nextMatch();
- if (found.isEmpty()) {
- return false;
- }
+ final OptionalInt found = searchIterator.nextMatch();
+ if (found.isEmpty()) {
+ return false;
+ }
- editorBuffer.setCursorPosition(found.getAsInt());
- clampCursorInNormalMode();
- return true;
- }
+ editorBuffer.setCursorPosition(found.getAsInt());
+ clampCursorInNormalMode();
+ return true;
+ }
- public void invalidateSearchIterator() {
- searchIterator = null;
- searchIteratorQuery = "";
- searchIteratorText = "";
- }
+ public void invalidateSearchIterator() {
+ searchIterator = null;
+ searchIteratorQuery = "";
+ searchIteratorText = "";
+ }
- public void recordUndoState() {
- undoManager.record(editorBuffer.getText(), editorBuffer.getCursorPosition());
- }
+ public void recordUndoState() {
+ undoManager.record(editorBuffer.getText(), editorBuffer.getCursorPosition());
+ }
- public ModeState undoToNormalState() {
- final UndoState previous = undoManager.undo();
- if (previous == null) {
- return NormalState.DEFAULT;
- }
- applyState(previous);
- return NormalState.DEFAULT;
- }
+ public ModeState undoToNormalState() {
+ final UndoState previous = undoManager.undo();
+ if (previous == null) {
+ return NormalState.DEFAULT;
+ }
+ applyState(previous);
+ return NormalState.DEFAULT;
+ }
- public ModeState redoToNormalState() {
- final UndoState target = undoManager.redo();
- if (target == null) {
- return NormalState.DEFAULT;
- }
- applyState(target);
- return NormalState.DEFAULT;
- }
+ public ModeState redoToNormalState() {
+ final UndoState target = undoManager.redo();
+ if (target == null) {
+ return NormalState.DEFAULT;
+ }
+ applyState(target);
+ return NormalState.DEFAULT;
+ }
- public void maybeRecordInsertEdit(final InsertState state) {
- final String currentText = editorBuffer.getText();
- final int currentCursor = editorBuffer.getCursorPosition();
- if (!currentText.equals(state.insertStartText()) || currentCursor != state.insertStartCursor()) {
- recordUndoState();
- }
- }
+ public void maybeRecordInsertEdit(final InsertState state) {
+ final String currentText = editorBuffer.getText();
+ final int currentCursor = editorBuffer.getCursorPosition();
+ if (!currentText.equals(state.insertStartText()) || currentCursor != state.insertStartCursor()) {
+ recordUndoState();
+ }
+ }
- private void applyState(final UndoState state) {
- editorBuffer.setText(state.getText());
- editorBuffer.setCursorPosition(Math.min(state.getCursor(), state.getText().length()));
- editorBuffer.clearSelection();
- clampCursorInNormalMode();
- invalidateSearchIterator();
- }
+ private void applyState(final UndoState state) {
+ editorBuffer.setText(state.getText());
+ editorBuffer.setCursorPosition(Math.min(state.getCursor(), state.getText().length()));
+ editorBuffer.clearSelection();
+ clampCursorInNormalMode();
+ invalidateSearchIterator();
+ }
- public void clampCursorInNormalMode() {
- final String text = editorBuffer.getText();
- if (text.isEmpty()) {
- editorBuffer.setCursorPosition(0);
- return;
- }
- final int maxCursor = navigation.maxCursorPositionInNormalMode(text);
- final int cursor = Math.min(editorBuffer.getCursorPosition(), maxCursor);
- final int lineStart = navigation.findLineStart(text, cursor);
- if (cursor < text.length() && text.charAt(cursor) == '\n' && cursor > lineStart) {
- editorBuffer.setCursorPosition(cursor - 1);
- } else {
- editorBuffer.setCursorPosition(cursor);
- }
- }
+ public void clampCursorInNormalMode() {
+ final String text = editorBuffer.getText();
+ if (text.isEmpty()) {
+ editorBuffer.setCursorPosition(0);
+ return;
+ }
+ final int maxCursor = navigation.maxCursorPositionInNormalMode(text);
+ final int cursor = Math.min(editorBuffer.getCursorPosition(), maxCursor);
+ final int lineStart = navigation.findLineStart(text, cursor);
+ if (cursor < text.length() && text.charAt(cursor) == '\n' && cursor > lineStart) {
+ editorBuffer.setCursorPosition(cursor - 1);
+ } else {
+ editorBuffer.setCursorPosition(cursor);
+ }
+ }
- public int getCursorPhysicalLine() {
- return editorBuffer.getCursorLine();
- }
+ public int getCursorPhysicalLine() {
+ return editorBuffer.getCursorLine();
+ }
- public String text() {
- return editorBuffer.getText();
- }
+ public String text() {
+ return editorBuffer.getText();
+ }
- public int cursor() {
- return editorBuffer.getCursorPosition();
- }
+ public int cursor() {
+ return editorBuffer.getCursorPosition();
+ }
- public void setCursor(final int position) {
- editorBuffer.setCursorPosition(position);
- }
+ public void setCursor(final int position) {
+ editorBuffer.setCursorPosition(position);
+ }
- public void setText(final String text) {
- editorBuffer.setText(text);
- invalidateSearchIterator();
- }
+ public void setText(final String text) {
+ editorBuffer.setText(text);
+ invalidateSearchIterator();
+ }
- public void clearSelection() {
- editorBuffer.clearSelection();
- }
+ public void clearSelection() {
+ editorBuffer.clearSelection();
+ }
- public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
- editorBuffer.setSelectionEndpoints(selectionStart, cursorPosition);
- }
+ public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
+ editorBuffer.setSelectionEndpoints(selectionStart, cursorPosition);
+ }
- public Register register() {
- return register;
- }
+ public Register register() {
+ return register;
+ }
- private String normalizeLineRegister(final String lineText) {
- if (lineText.isEmpty() || lineText.charAt(lineText.length() - 1) == '\n') {
- return lineText;
- }
- return lineText + "\n";
- }
+ private String normalizeLineRegister(final String lineText) {
+ if (lineText.isEmpty() || lineText.charAt(lineText.length() - 1) == '\n') {
+ return lineText;
+ }
+ return lineText + "\n";
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/CommandAction.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/CommandAction.java
index 7a1b85c..9fcf694 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/CommandAction.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/CommandAction.java
@@ -4,5 +4,5 @@ import coffee.liz.abstractionengine.app.ui.editor.vim.context.KeyContext;
import coffee.liz.abstractionengine.app.ui.editor.vim.state.ModeState;
public interface CommandAction<S extends ModeState> {
- HandleResult execute(S state, KeyContext context);
+ HandleResult execute(S state, KeyContext context);
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/HandleResult.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/HandleResult.java
index 9a4e2e4..b58fa77 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/HandleResult.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/HandleResult.java
@@ -3,30 +3,30 @@ package coffee.liz.abstractionengine.app.ui.editor.vim.handler;
import coffee.liz.abstractionengine.app.ui.editor.vim.state.ModeState;
public record HandleResult(boolean consumed, boolean suppressTyped, ModeState nextState) {
- public static HandleResult notHandled() {
- return new HandleResult(false, false, null);
- }
+ public static HandleResult notHandled() {
+ return new HandleResult(false, false, null);
+ }
- public static HandleResult handled() {
- return new HandleResult(true, false, null);
- }
+ public static HandleResult handled() {
+ return new HandleResult(true, false, null);
+ }
- public static HandleResult handled(final ModeState nextState) {
- return new HandleResult(true, false, nextState);
- }
+ public static HandleResult handled(final ModeState nextState) {
+ return new HandleResult(true, false, nextState);
+ }
- public static HandleResult handledAndSuppressTyped() {
- return new HandleResult(true, true, null);
- }
+ public static HandleResult handledAndSuppressTyped() {
+ return new HandleResult(true, true, null);
+ }
- public static HandleResult handledAndSuppressTyped(final ModeState nextState) {
- return new HandleResult(true, true, nextState);
- }
+ public static HandleResult handledAndSuppressTyped(final ModeState nextState) {
+ return new HandleResult(true, true, nextState);
+ }
- public HandleResult withSuppressTyped() {
- if (!consumed) {
- return this;
- }
- return new HandleResult(true, true, nextState);
- }
+ public HandleResult withSuppressTyped() {
+ if (!consumed) {
+ return this;
+ }
+ return new HandleResult(true, true, nextState);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/InsertModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/InsertModeHandler.java
index 176664c..ff9c39f 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/InsertModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/InsertModeHandler.java
@@ -6,19 +6,19 @@ import coffee.liz.abstractionengine.app.ui.editor.vim.context.KeyContext;
import com.badlogic.gdx.Input;
public class InsertModeHandler implements ModeHandler<InsertState> {
- @Override
- public HandleResult onKeyDown(final InsertState state, final KeyContext context) {
- if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
- context.maybeRecordInsertEdit(state);
- context.clampCursorInNormalMode();
- context.clearSelection();
- return HandleResult.handled(NormalState.DEFAULT);
- }
- return HandleResult.notHandled();
- }
+ @Override
+ public HandleResult onKeyDown(final InsertState state, final KeyContext context) {
+ if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
+ context.maybeRecordInsertEdit(state);
+ context.clampCursorInNormalMode();
+ context.clearSelection();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
+ return HandleResult.notHandled();
+ }
- @Override
- public HandleResult onKeyTyped(final InsertState state, final char character, final KeyContext context) {
- return HandleResult.notHandled();
- }
+ @Override
+ public HandleResult onKeyTyped(final InsertState state, final char character, final KeyContext context) {
+ return HandleResult.notHandled();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/ModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/ModeHandler.java
index ed04ce2..430e9c4 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/ModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/ModeHandler.java
@@ -4,7 +4,7 @@ import coffee.liz.abstractionengine.app.ui.editor.vim.context.KeyContext;
import coffee.liz.abstractionengine.app.ui.editor.vim.state.ModeState;
public interface ModeHandler<T extends ModeState> {
- HandleResult onKeyDown(T state, KeyContext context);
+ HandleResult onKeyDown(T state, KeyContext context);
- HandleResult onKeyTyped(T state, char character, KeyContext context);
+ HandleResult onKeyTyped(T state, char character, KeyContext context);
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/MotionAction.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/MotionAction.java
index e6332dd..3e9a0bf 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/MotionAction.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/MotionAction.java
@@ -3,5 +3,5 @@ package coffee.liz.abstractionengine.app.ui.editor.vim.handler;
import coffee.liz.abstractionengine.app.ui.editor.vim.context.KeyContext;
public interface MotionAction {
- int execute(KeyContext context, int repeats, int preferredColumn, boolean clampInNormalMode);
+ int execute(KeyContext context, int repeats, int preferredColumn, boolean clampInNormalMode);
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java
index 65e6f71..e064b0e 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java
@@ -14,313 +14,313 @@ import java.util.HashMap;
import java.util.Map;
public class NormalModeHandler implements ModeHandler<NormalState> {
- private final Map<Character, CommandAction<NormalState>> commandActions = createCommandActions();
- private final Map<Character, MotionAction> motionActions = createMotionActions();
+ private final Map<Character, CommandAction<NormalState>> commandActions = createCommandActions();
+ private final Map<Character, MotionAction> motionActions = createMotionActions();
- @Override
- public HandleResult onKeyDown(final NormalState state, final KeyContext context) {
- if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ @Override
+ public HandleResult onKeyDown(final NormalState state, final KeyContext context) {
+ if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- final Character commandCharacter = context.toCommandCharacter();
- if (commandCharacter != null) {
- return onKeyTyped(state, commandCharacter.charValue(), context).withSuppressTyped();
- }
+ final Character commandCharacter = context.toCommandCharacter();
+ if (commandCharacter != null) {
+ return onKeyTyped(state, commandCharacter.charValue(), context).withSuppressTyped();
+ }
- return HandleResult.handled();
- }
+ return HandleResult.handled();
+ }
- @Override
- public HandleResult onKeyTyped(final NormalState state, final char character, final KeyContext context) {
- if (character >= '1' && character <= '9') {
- return HandleResult.handled(new NormalState(state.count() * 10 + (character - '0'), state.pendingOperator(),
- state.preferredColumn()));
- }
+ @Override
+ public HandleResult onKeyTyped(final NormalState state, final char character, final KeyContext context) {
+ if (character >= '1' && character <= '9') {
+ return HandleResult.handled(new NormalState(state.count() * 10 + (character - '0'), state.pendingOperator(),
+ state.preferredColumn()));
+ }
- if (character == '0' && state.count() > 0) {
- return HandleResult
- .handled(new NormalState(state.count() * 10, state.pendingOperator(), state.preferredColumn()));
- }
+ if (character == '0' && state.count() > 0) {
+ return HandleResult
+ .handled(new NormalState(state.count() * 10, state.pendingOperator(), state.preferredColumn()));
+ }
- if (state.pendingOperator() != PendingOperator.NONE) {
- return handlePendingOperator(state, character, context);
- }
+ if (state.pendingOperator() != PendingOperator.NONE) {
+ return handlePendingOperator(state, character, context);
+ }
- final NormalState normalizedState = new NormalState(state.count(), PendingOperator.NONE,
- context.resetPreferredColumn(character, state.preferredColumn()));
- final CommandAction<NormalState> action = commandActions.get(character);
- if (action == null) {
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, normalizedState.preferredColumn()));
- }
- return action.execute(normalizedState, context);
- }
+ final NormalState normalizedState = new NormalState(state.count(), PendingOperator.NONE,
+ context.resetPreferredColumn(character, state.preferredColumn()));
+ final CommandAction<NormalState> action = commandActions.get(character);
+ if (action == null) {
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, normalizedState.preferredColumn()));
+ }
+ return action.execute(normalizedState, context);
+ }
- private HandleResult handlePendingOperator(final NormalState state, final char character,
- final KeyContext context) {
- if (state.pendingOperator() == PendingOperator.G_PREFIX) {
- if (character == 'g') {
- context.moveDocumentStart();
- }
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ private HandleResult handlePendingOperator(final NormalState state, final char character,
+ final KeyContext context) {
+ if (state.pendingOperator() == PendingOperator.G_PREFIX) {
+ if (character == 'g') {
+ context.moveDocumentStart();
+ }
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- final PendingOperator operator = state.pendingOperator();
- final int repeats = context.readCount(state.count());
- if (character == 'd' && operator == PendingOperator.DELETE) {
- context.deleteLines(repeats);
- context.recordUndoState();
- return HandleResult.handled(NormalState.DEFAULT);
- }
- if (character == 'y' && operator == PendingOperator.YANK) {
- context.yankLines(repeats);
- return HandleResult.handled(NormalState.DEFAULT);
- }
- if (character == 'c' && operator == PendingOperator.CHANGE) {
- context.changeLines(repeats);
- context.recordUndoState();
- return HandleResult.handled(new InsertState(context.text(), context.cursor()));
- }
+ final PendingOperator operator = state.pendingOperator();
+ final int repeats = context.readCount(state.count());
+ if (character == 'd' && operator == PendingOperator.DELETE) {
+ context.deleteLines(repeats);
+ context.recordUndoState();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
+ if (character == 'y' && operator == PendingOperator.YANK) {
+ context.yankLines(repeats);
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
+ if (character == 'c' && operator == PendingOperator.CHANGE) {
+ context.changeLines(repeats);
+ context.recordUndoState();
+ return HandleResult.handled(new InsertState(context.text(), context.cursor()));
+ }
- final int start = context.cursor();
- final int updatedPreferred = applyMotion(character, repeats, state.preferredColumn(), context, true);
- int end = context.cursor();
- if (character == '$') {
- end = Math.min(context.text().length(), end + 1);
- }
+ final int start = context.cursor();
+ final int updatedPreferred = applyMotion(character, repeats, state.preferredColumn(), context, true);
+ int end = context.cursor();
+ if (character == '$') {
+ end = Math.min(context.text().length(), end + 1);
+ }
- final int rangeStart = Math.min(start, end);
- final int rangeEnd = Math.max(start, end);
- if (rangeStart == rangeEnd) {
- if (character == 'l') {
- final String text = context.text();
- if (start < text.length() && text.charAt(start) != '\n') {
- context.register().setText(text.substring(start, start + 1));
- context.register().setType(RegisterType.CHARACTER);
- if (operator == PendingOperator.YANK) {
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
- }
+ final int rangeStart = Math.min(start, end);
+ final int rangeEnd = Math.max(start, end);
+ if (rangeStart == rangeEnd) {
+ if (character == 'l') {
+ final String text = context.text();
+ if (start < text.length() && text.charAt(start) != '\n') {
+ context.register().setText(text.substring(start, start + 1));
+ context.register().setType(RegisterType.CHARACTER);
+ if (operator == PendingOperator.YANK) {
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
+ }
- context.setText(text.substring(0, start) + text.substring(start + 1));
- context.setCursor(Math.min(start, context.text().length()));
- context.clampCursorInNormalMode();
- context.recordUndoState();
- if (operator == PendingOperator.CHANGE) {
- return HandleResult.handled(new InsertState(context.text(), context.cursor()));
- }
- }
- }
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
- }
+ context.setText(text.substring(0, start) + text.substring(start + 1));
+ context.setCursor(Math.min(start, context.text().length()));
+ context.clampCursorInNormalMode();
+ context.recordUndoState();
+ if (operator == PendingOperator.CHANGE) {
+ return HandleResult.handled(new InsertState(context.text(), context.cursor()));
+ }
+ }
+ }
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
+ }
- if (operator == PendingOperator.YANK) {
- context.register().setText(context.text().substring(rangeStart, rangeEnd));
- context.register().setType(RegisterType.CHARACTER);
- context.setCursor(start);
- context.clampCursorInNormalMode();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
- }
+ if (operator == PendingOperator.YANK) {
+ context.register().setText(context.text().substring(rangeStart, rangeEnd));
+ context.register().setType(RegisterType.CHARACTER);
+ context.setCursor(start);
+ context.clampCursorInNormalMode();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
+ }
- final String text = context.text();
- context.register().setText(text.substring(rangeStart, rangeEnd));
- context.register().setType(RegisterType.CHARACTER);
- context.setText(text.substring(0, rangeStart) + text.substring(rangeEnd));
- context.setCursor(Math.min(rangeStart, context.text().length()));
- context.clampCursorInNormalMode();
- context.recordUndoState();
+ final String text = context.text();
+ context.register().setText(text.substring(rangeStart, rangeEnd));
+ context.register().setType(RegisterType.CHARACTER);
+ context.setText(text.substring(0, rangeStart) + text.substring(rangeEnd));
+ context.setCursor(Math.min(rangeStart, context.text().length()));
+ context.clampCursorInNormalMode();
+ context.recordUndoState();
- if (operator == PendingOperator.CHANGE) {
- return HandleResult.handled(new InsertState(context.text(), context.cursor()));
- }
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
- }
+ if (operator == PendingOperator.CHANGE) {
+ return HandleResult.handled(new InsertState(context.text(), context.cursor()));
+ }
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, updatedPreferred));
+ }
- private int applyMotion(final char motion, final int repeats, final int preferredColumn, final KeyContext context,
- final boolean clampInNormalMode) {
- final MotionAction action = motionActions.get(motion);
- if (action == null) {
- return preferredColumn;
- }
- return action.execute(context, repeats, preferredColumn, clampInNormalMode);
- }
+ private int applyMotion(final char motion, final int repeats, final int preferredColumn, final KeyContext context,
+ final boolean clampInNormalMode) {
+ final MotionAction action = motionActions.get(motion);
+ if (action == null) {
+ return preferredColumn;
+ }
+ return action.execute(context, repeats, preferredColumn, clampInNormalMode);
+ }
- private Map<Character, CommandAction<NormalState>> createCommandActions() {
- final Map<Character, CommandAction<NormalState>> map = new HashMap<>();
- map.put('h', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.moveLeft();
- }
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('j', (state, context) -> {
- final int repeats = context.readCount(state.count());
- final int preferred = context.moveVertical(1, repeats, state.preferredColumn(), true);
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, preferred));
- });
- map.put('k', (state, context) -> {
- final int repeats = context.readCount(state.count());
- final int preferred = context.moveVertical(-1, repeats, state.preferredColumn(), true);
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, preferred));
- });
- map.put('l', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.moveRightNormal();
- }
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('w', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.moveWordForward();
- }
- context.clampCursorInNormalMode();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('b', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.moveWordBackward();
- }
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('0', (state, context) -> {
- context.moveLineStart();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('$', (state, context) -> {
- context.moveLineEnd();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('G', (state, context) -> {
- context.moveDocumentEnd();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('g', (state, context) -> HandleResult
- .handled(new NormalState(0, PendingOperator.G_PREFIX, state.preferredColumn())));
- map.put('i', (state, context) -> HandleResult.handled(new InsertState(context.text(), context.cursor())));
- map.put('a', (state, context) -> {
- context.moveRightForAppend();
- return HandleResult.handled(new InsertState(context.text(), context.cursor()));
- });
- map.put('o', (state, context) -> {
- context.openLineBelow();
- return HandleResult.handled(new InsertState(context.text(), context.cursor()));
- });
- map.put('O', (state, context) -> {
- context.openLineAbove();
- return HandleResult.handled(new InsertState(context.text(), context.cursor()));
- });
- map.put('x', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.deleteCharUnderCursor();
- }
- context.clampCursorInNormalMode();
- context.recordUndoState();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('d', (state, context) -> HandleResult
- .handled(new NormalState(0, PendingOperator.DELETE, state.preferredColumn())));
- map.put('y', (state, context) -> HandleResult
- .handled(new NormalState(0, PendingOperator.YANK, state.preferredColumn())));
- map.put('c', (state, context) -> HandleResult
- .handled(new NormalState(0, PendingOperator.CHANGE, state.preferredColumn())));
- map.put('p', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.pasteAfter();
- }
- context.clampCursorInNormalMode();
- context.recordUndoState();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('P', (state, context) -> {
- final int repeats = context.readCount(state.count());
- for (int i = 0; i < repeats; i++) {
- context.pasteBefore();
- }
- context.clampCursorInNormalMode();
- context.recordUndoState();
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('v', (state, context) -> {
- final int anchor = context.cursor();
- context.updateVisualSelection(anchor);
- return HandleResult.handled(new VisualState(anchor, state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('V', (state, context) -> {
- final int anchorLine = context.getCursorPhysicalLine();
- context.updateVisualLineSelection(anchorLine, anchorLine);
- return HandleResult.handled(
- new VisualLineState(anchorLine, anchorLine, state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('/', (state, context) -> HandleResult
- .handled(new SearchState(new StringBuilder(), context.getLastSearchQuery(), SearchDirection.FORWARD)));
- map.put('?', (state, context) -> HandleResult
- .handled(new SearchState(new StringBuilder(), context.getLastSearchQuery(), SearchDirection.BACKWARD)));
- map.put('n', (state, context) -> {
- context.findNext(context.getLastSearchQuery(), SearchDirection.FORWARD);
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('N', (state, context) -> {
- context.findNext(context.getLastSearchQuery(), SearchDirection.BACKWARD);
- return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
- });
- map.put('u', (state, context) -> HandleResult.handled(context.undoToNormalState()));
- return map;
- }
+ private Map<Character, CommandAction<NormalState>> createCommandActions() {
+ final Map<Character, CommandAction<NormalState>> map = new HashMap<>();
+ map.put('h', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.moveLeft();
+ }
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('j', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ final int preferred = context.moveVertical(1, repeats, state.preferredColumn(), true);
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, preferred));
+ });
+ map.put('k', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ final int preferred = context.moveVertical(-1, repeats, state.preferredColumn(), true);
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, preferred));
+ });
+ map.put('l', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.moveRightNormal();
+ }
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('w', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.moveWordForward();
+ }
+ context.clampCursorInNormalMode();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('b', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.moveWordBackward();
+ }
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('0', (state, context) -> {
+ context.moveLineStart();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('$', (state, context) -> {
+ context.moveLineEnd();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('G', (state, context) -> {
+ context.moveDocumentEnd();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('g', (state, context) -> HandleResult
+ .handled(new NormalState(0, PendingOperator.G_PREFIX, state.preferredColumn())));
+ map.put('i', (state, context) -> HandleResult.handled(new InsertState(context.text(), context.cursor())));
+ map.put('a', (state, context) -> {
+ context.moveRightForAppend();
+ return HandleResult.handled(new InsertState(context.text(), context.cursor()));
+ });
+ map.put('o', (state, context) -> {
+ context.openLineBelow();
+ return HandleResult.handled(new InsertState(context.text(), context.cursor()));
+ });
+ map.put('O', (state, context) -> {
+ context.openLineAbove();
+ return HandleResult.handled(new InsertState(context.text(), context.cursor()));
+ });
+ map.put('x', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.deleteCharUnderCursor();
+ }
+ context.clampCursorInNormalMode();
+ context.recordUndoState();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('d', (state, context) -> HandleResult
+ .handled(new NormalState(0, PendingOperator.DELETE, state.preferredColumn())));
+ map.put('y', (state, context) -> HandleResult
+ .handled(new NormalState(0, PendingOperator.YANK, state.preferredColumn())));
+ map.put('c', (state, context) -> HandleResult
+ .handled(new NormalState(0, PendingOperator.CHANGE, state.preferredColumn())));
+ map.put('p', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.pasteAfter();
+ }
+ context.clampCursorInNormalMode();
+ context.recordUndoState();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('P', (state, context) -> {
+ final int repeats = context.readCount(state.count());
+ for (int i = 0; i < repeats; i++) {
+ context.pasteBefore();
+ }
+ context.clampCursorInNormalMode();
+ context.recordUndoState();
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('v', (state, context) -> {
+ final int anchor = context.cursor();
+ context.updateVisualSelection(anchor);
+ return HandleResult.handled(new VisualState(anchor, state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('V', (state, context) -> {
+ final int anchorLine = context.getCursorPhysicalLine();
+ context.updateVisualLineSelection(anchorLine, anchorLine);
+ return HandleResult.handled(
+ new VisualLineState(anchorLine, anchorLine, state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('/', (state, context) -> HandleResult
+ .handled(new SearchState(new StringBuilder(), context.getLastSearchQuery(), SearchDirection.FORWARD)));
+ map.put('?', (state, context) -> HandleResult
+ .handled(new SearchState(new StringBuilder(), context.getLastSearchQuery(), SearchDirection.BACKWARD)));
+ map.put('n', (state, context) -> {
+ context.findNext(context.getLastSearchQuery(), SearchDirection.FORWARD);
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('N', (state, context) -> {
+ context.findNext(context.getLastSearchQuery(), SearchDirection.BACKWARD);
+ return HandleResult.handled(new NormalState(0, PendingOperator.NONE, state.preferredColumn()));
+ });
+ map.put('u', (state, context) -> HandleResult.handled(context.undoToNormalState()));
+ return map;
+ }
- private Map<Character, MotionAction> createMotionActions() {
- final Map<Character, MotionAction> map = new HashMap<>();
- map.put('h', (context, repeats, preferredColumn, clampInNormalMode) -> {
- for (int i = 0; i < repeats; i++) {
- context.moveLeft();
- }
- return preferredColumn;
- });
- map.put('j', (context, repeats, preferredColumn, clampInNormalMode) -> context.moveVertical(1, repeats,
- preferredColumn, clampInNormalMode));
- map.put('k', (context, repeats, preferredColumn, clampInNormalMode) -> context.moveVertical(-1, repeats,
- preferredColumn, clampInNormalMode));
- map.put('l', (context, repeats, preferredColumn, clampInNormalMode) -> {
- for (int i = 0; i < repeats; i++) {
- context.moveRightNormal();
- }
- return preferredColumn;
- });
- map.put('w', (context, repeats, preferredColumn, clampInNormalMode) -> {
- for (int i = 0; i < repeats; i++) {
- context.moveWordForward();
- }
- if (clampInNormalMode) {
- context.clampCursorInNormalMode();
- }
- return preferredColumn;
- });
- map.put('b', (context, repeats, preferredColumn, clampInNormalMode) -> {
- for (int i = 0; i < repeats; i++) {
- context.moveWordBackward();
- }
- return preferredColumn;
- });
- map.put('0', (context, repeats, preferredColumn, clampInNormalMode) -> {
- context.moveLineStart();
- return preferredColumn;
- });
- map.put('$', (context, repeats, preferredColumn, clampInNormalMode) -> {
- context.moveLineEnd();
- return preferredColumn;
- });
- map.put('G', (context, repeats, preferredColumn, clampInNormalMode) -> {
- context.moveDocumentEnd();
- return preferredColumn;
- });
- map.put('g', (context, repeats, preferredColumn, clampInNormalMode) -> {
- context.moveDocumentStart();
- return preferredColumn;
- });
- return map;
- }
+ private Map<Character, MotionAction> createMotionActions() {
+ final Map<Character, MotionAction> map = new HashMap<>();
+ map.put('h', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ for (int i = 0; i < repeats; i++) {
+ context.moveLeft();
+ }
+ return preferredColumn;
+ });
+ map.put('j', (context, repeats, preferredColumn, clampInNormalMode) -> context.moveVertical(1, repeats,
+ preferredColumn, clampInNormalMode));
+ map.put('k', (context, repeats, preferredColumn, clampInNormalMode) -> context.moveVertical(-1, repeats,
+ preferredColumn, clampInNormalMode));
+ map.put('l', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ for (int i = 0; i < repeats; i++) {
+ context.moveRightNormal();
+ }
+ return preferredColumn;
+ });
+ map.put('w', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ for (int i = 0; i < repeats; i++) {
+ context.moveWordForward();
+ }
+ if (clampInNormalMode) {
+ context.clampCursorInNormalMode();
+ }
+ return preferredColumn;
+ });
+ map.put('b', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ for (int i = 0; i < repeats; i++) {
+ context.moveWordBackward();
+ }
+ return preferredColumn;
+ });
+ map.put('0', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ context.moveLineStart();
+ return preferredColumn;
+ });
+ map.put('$', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ context.moveLineEnd();
+ return preferredColumn;
+ });
+ map.put('G', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ context.moveDocumentEnd();
+ return preferredColumn;
+ });
+ map.put('g', (context, repeats, preferredColumn, clampInNormalMode) -> {
+ context.moveDocumentStart();
+ return preferredColumn;
+ });
+ return map;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/SearchModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/SearchModeHandler.java
index c3e20f2..1c0bdd5 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/SearchModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/SearchModeHandler.java
@@ -7,36 +7,36 @@ import coffee.liz.abstractionengine.app.ui.editor.vim.state.SearchState;
import com.badlogic.gdx.Input;
public class SearchModeHandler implements ModeHandler<SearchState> {
- @Override
- public HandleResult onKeyDown(final SearchState state, final KeyContext context) {
- if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
- return HandleResult.handled(NormalState.DEFAULT);
- }
- return HandleResult.handled();
- }
+ @Override
+ public HandleResult onKeyDown(final SearchState state, final KeyContext context) {
+ if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
+ return HandleResult.handled();
+ }
- @Override
- public HandleResult onKeyTyped(final SearchState state, final char character, final KeyContext context) {
- if (character == '\r' || character == '\n') {
- final String query = state.query().toString();
- context.setLastSearchQuery(query);
- context.invalidateSearchIterator();
- context.findNext(query, state.direction());
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ @Override
+ public HandleResult onKeyTyped(final SearchState state, final char character, final KeyContext context) {
+ if (character == '\r' || character == '\n') {
+ final String query = state.query().toString();
+ context.setLastSearchQuery(query);
+ context.invalidateSearchIterator();
+ context.findNext(query, state.direction());
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- if (character == '\b') {
- if (state.query().length() > 0) {
- state.query().setLength(state.query().length() - 1);
- }
- return HandleResult.handled(state);
- }
+ if (character == '\b') {
+ if (state.query().length() > 0) {
+ state.query().setLength(state.query().length() - 1);
+ }
+ return HandleResult.handled(state);
+ }
- if (character < 32 || character == 127) {
- return HandleResult.handled(state);
- }
+ if (character < 32 || character == 127) {
+ return HandleResult.handled(state);
+ }
- state.query().append(character);
- return HandleResult.handled(new SearchState(state.query(), state.lastQuery(), state.direction()));
- }
+ state.query().append(character);
+ return HandleResult.handled(new SearchState(state.query(), state.lastQuery(), state.direction()));
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualLineModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualLineModeHandler.java
index 7056e54..58617bd 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualLineModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualLineModeHandler.java
@@ -9,84 +9,84 @@ import java.util.HashMap;
import java.util.Map;
public class VisualLineModeHandler implements ModeHandler<VisualLineState> {
- private final Map<Character, CommandAction<VisualLineState>> commandActions = createCommandActions();
+ private final Map<Character, CommandAction<VisualLineState>> commandActions = createCommandActions();
- @Override
- public HandleResult onKeyDown(final VisualLineState state, final KeyContext context) {
- if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
- final int startLine = Math.min(state.anchorLine(), state.cursorLine());
- context.setCursor(context.navigation().findLineStartByLine(context.text(), startLine));
- context.clampCursorInNormalMode();
- context.clearSelection();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ @Override
+ public HandleResult onKeyDown(final VisualLineState state, final KeyContext context) {
+ if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
+ final int startLine = Math.min(state.anchorLine(), state.cursorLine());
+ context.setCursor(context.navigation().findLineStartByLine(context.text(), startLine));
+ context.clampCursorInNormalMode();
+ context.clearSelection();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- final Character commandCharacter = context.toCommandCharacter();
- if (commandCharacter != null) {
- return onKeyTyped(state, commandCharacter.charValue(), context).withSuppressTyped();
- }
+ final Character commandCharacter = context.toCommandCharacter();
+ if (commandCharacter != null) {
+ return onKeyTyped(state, commandCharacter.charValue(), context).withSuppressTyped();
+ }
- return HandleResult.handled();
- }
+ return HandleResult.handled();
+ }
- @Override
- public HandleResult onKeyTyped(final VisualLineState state, final char character, final KeyContext context) {
- if (character >= '1' && character <= '9') {
- return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
- state.preferredColumn(), state.pendingOperator(), state.count() * 10 + (character - '0')));
- }
- if (character == '0' && state.count() > 0) {
- return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
- state.preferredColumn(), state.pendingOperator(), state.count() * 10));
- }
+ @Override
+ public HandleResult onKeyTyped(final VisualLineState state, final char character, final KeyContext context) {
+ if (character >= '1' && character <= '9') {
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
+ state.preferredColumn(), state.pendingOperator(), state.count() * 10 + (character - '0')));
+ }
+ if (character == '0' && state.count() > 0) {
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
+ state.preferredColumn(), state.pendingOperator(), state.count() * 10));
+ }
- if (state.pendingOperator() == PendingOperator.G_PREFIX) {
- if (character == 'g') {
- final int cursorLine = 0;
- context.updateVisualLineSelection(state.anchorLine(), cursorLine);
- return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
- PendingOperator.NONE, 0));
- }
- return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
- state.preferredColumn(), PendingOperator.NONE, 0));
- }
+ if (state.pendingOperator() == PendingOperator.G_PREFIX) {
+ if (character == 'g') {
+ final int cursorLine = 0;
+ context.updateVisualLineSelection(state.anchorLine(), cursorLine);
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
+ PendingOperator.NONE, 0));
+ }
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
+ state.preferredColumn(), PendingOperator.NONE, 0));
+ }
- final CommandAction<VisualLineState> action = commandActions.get(character);
- if (action == null) {
- return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
- state.preferredColumn(), PendingOperator.NONE, 0));
- }
- return action.execute(new VisualLineState(state.anchorLine(), state.cursorLine(),
- context.resetPreferredColumn(character, state.preferredColumn()), PendingOperator.NONE, state.count()),
- context);
- }
+ final CommandAction<VisualLineState> action = commandActions.get(character);
+ if (action == null) {
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), state.cursorLine(),
+ state.preferredColumn(), PendingOperator.NONE, 0));
+ }
+ return action.execute(new VisualLineState(state.anchorLine(), state.cursorLine(),
+ context.resetPreferredColumn(character, state.preferredColumn()), PendingOperator.NONE, state.count()),
+ context);
+ }
- private Map<Character, CommandAction<VisualLineState>> createCommandActions() {
- final Map<Character, CommandAction<VisualLineState>> map = new HashMap<>();
- map.put('j', (state, context) -> {
- final int cursorLine = context.adjustVisualLineCursor(state.cursorLine(), context.readCount(state.count()));
- context.updateVisualLineSelection(state.anchorLine(), cursorLine);
- return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
- PendingOperator.NONE, 0));
- });
- map.put('k', (state, context) -> {
- final int cursorLine = context.adjustVisualLineCursor(state.cursorLine(),
- -context.readCount(state.count()));
- context.updateVisualLineSelection(state.anchorLine(), cursorLine);
- return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
- PendingOperator.NONE, 0));
- });
- map.put('G', (state, context) -> {
- final int cursorLine = context.maxSelectableLineIndex();
- context.updateVisualLineSelection(state.anchorLine(), cursorLine);
- return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
- PendingOperator.NONE, 0));
- });
- map.put('g', (state, context) -> HandleResult.handled(new VisualLineState(state.anchorLine(),
- state.cursorLine(), state.preferredColumn(), PendingOperator.G_PREFIX, 0)));
- map.put('d', (state, context) -> context.applyVisualLineOperator(state, PendingOperator.DELETE));
- map.put('y', (state, context) -> context.applyVisualLineOperator(state, PendingOperator.YANK));
- map.put('c', (state, context) -> context.applyVisualLineOperator(state, PendingOperator.CHANGE));
- return map;
- }
+ private Map<Character, CommandAction<VisualLineState>> createCommandActions() {
+ final Map<Character, CommandAction<VisualLineState>> map = new HashMap<>();
+ map.put('j', (state, context) -> {
+ final int cursorLine = context.adjustVisualLineCursor(state.cursorLine(), context.readCount(state.count()));
+ context.updateVisualLineSelection(state.anchorLine(), cursorLine);
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
+ PendingOperator.NONE, 0));
+ });
+ map.put('k', (state, context) -> {
+ final int cursorLine = context.adjustVisualLineCursor(state.cursorLine(),
+ -context.readCount(state.count()));
+ context.updateVisualLineSelection(state.anchorLine(), cursorLine);
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
+ PendingOperator.NONE, 0));
+ });
+ map.put('G', (state, context) -> {
+ final int cursorLine = context.maxSelectableLineIndex();
+ context.updateVisualLineSelection(state.anchorLine(), cursorLine);
+ return HandleResult.handled(new VisualLineState(state.anchorLine(), cursorLine, state.preferredColumn(),
+ PendingOperator.NONE, 0));
+ });
+ map.put('g', (state, context) -> HandleResult.handled(new VisualLineState(state.anchorLine(),
+ state.cursorLine(), state.preferredColumn(), PendingOperator.G_PREFIX, 0)));
+ map.put('d', (state, context) -> context.applyVisualLineOperator(state, PendingOperator.DELETE));
+ map.put('y', (state, context) -> context.applyVisualLineOperator(state, PendingOperator.YANK));
+ map.put('c', (state, context) -> context.applyVisualLineOperator(state, PendingOperator.CHANGE));
+ return map;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualModeHandler.java
index db794d5..7fe7d6a 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/VisualModeHandler.java
@@ -9,124 +9,124 @@ import java.util.HashMap;
import java.util.Map;
public class VisualModeHandler implements ModeHandler<VisualState> {
- private final Map<Character, CommandAction<VisualState>> commandActions = createCommandActions();
+ private final Map<Character, CommandAction<VisualState>> commandActions = createCommandActions();
- @Override
- public HandleResult onKeyDown(final VisualState state, final KeyContext context) {
- if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
- context.setCursor(Math.min(state.anchor(), context.cursor()));
- context.clampCursorInNormalMode();
- context.clearSelection();
- return HandleResult.handled(NormalState.DEFAULT);
- }
+ @Override
+ public HandleResult onKeyDown(final VisualState state, final KeyContext context) {
+ if (context.currentKeyEvent().keycode() == Input.Keys.ESCAPE) {
+ context.setCursor(Math.min(state.anchor(), context.cursor()));
+ context.clampCursorInNormalMode();
+ context.clearSelection();
+ return HandleResult.handled(NormalState.DEFAULT);
+ }
- final Character commandCharacter = context.toCommandCharacter();
- if (commandCharacter != null) {
- return onKeyTyped(state, commandCharacter.charValue(), context).withSuppressTyped();
- }
+ final Character commandCharacter = context.toCommandCharacter();
+ if (commandCharacter != null) {
+ return onKeyTyped(state, commandCharacter.charValue(), context).withSuppressTyped();
+ }
- return HandleResult.handled();
- }
+ return HandleResult.handled();
+ }
- @Override
- public HandleResult onKeyTyped(final VisualState state, final char character, final KeyContext context) {
- if (character >= '1' && character <= '9') {
- return HandleResult.handled(new VisualState(state.anchor(), state.preferredColumn(),
- state.pendingOperator(), state.count() * 10 + (character - '0')));
- }
- if (character == '0' && state.count() > 0) {
- return HandleResult.handled(new VisualState(state.anchor(), state.preferredColumn(),
- state.pendingOperator(), state.count() * 10));
- }
+ @Override
+ public HandleResult onKeyTyped(final VisualState state, final char character, final KeyContext context) {
+ if (character >= '1' && character <= '9') {
+ return HandleResult.handled(new VisualState(state.anchor(), state.preferredColumn(),
+ state.pendingOperator(), state.count() * 10 + (character - '0')));
+ }
+ if (character == '0' && state.count() > 0) {
+ return HandleResult.handled(new VisualState(state.anchor(), state.preferredColumn(),
+ state.pendingOperator(), state.count() * 10));
+ }
- if (state.pendingOperator() == PendingOperator.G_PREFIX) {
- if (character == 'g') {
- context.moveDocumentStart();
- context.updateVisualSelection(state.anchor());
- }
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- }
+ if (state.pendingOperator() == PendingOperator.G_PREFIX) {
+ if (character == 'g') {
+ context.moveDocumentStart();
+ context.updateVisualSelection(state.anchor());
+ }
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ }
- final VisualState normalizedState = new VisualState(state.anchor(),
- context.resetPreferredColumn(character, state.preferredColumn()), PendingOperator.NONE, state.count());
- final CommandAction<VisualState> action = commandActions.get(character);
- if (action == null) {
- return HandleResult.handled(
- new VisualState(state.anchor(), normalizedState.preferredColumn(), PendingOperator.NONE, 0));
- }
- return action.execute(normalizedState, context);
- }
+ final VisualState normalizedState = new VisualState(state.anchor(),
+ context.resetPreferredColumn(character, state.preferredColumn()), PendingOperator.NONE, state.count());
+ final CommandAction<VisualState> action = commandActions.get(character);
+ if (action == null) {
+ return HandleResult.handled(
+ new VisualState(state.anchor(), normalizedState.preferredColumn(), PendingOperator.NONE, 0));
+ }
+ return action.execute(normalizedState, context);
+ }
- private Map<Character, CommandAction<VisualState>> createCommandActions() {
- final Map<Character, CommandAction<VisualState>> map = new HashMap<>();
- map.put('h', (state, context) -> {
- for (int i = 0; i < context.readCount(state.count()); i++) {
- context.moveLeft();
- }
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('j', (state, context) -> {
- final int preferred = context.moveVertical(1, context.readCount(state.count()), state.preferredColumn(),
- false);
- context.updateVisualSelection(state.anchor());
- return HandleResult.handled(new VisualState(state.anchor(), preferred, PendingOperator.NONE, 0));
- });
- map.put('k', (state, context) -> {
- final int preferred = context.moveVertical(-1, context.readCount(state.count()), state.preferredColumn(),
- false);
- context.updateVisualSelection(state.anchor());
- return HandleResult.handled(new VisualState(state.anchor(), preferred, PendingOperator.NONE, 0));
- });
- map.put('l', (state, context) -> {
- for (int i = 0; i < context.readCount(state.count()); i++) {
- context.moveRightNormal();
- }
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('w', (state, context) -> {
- for (int i = 0; i < context.readCount(state.count()); i++) {
- context.moveWordForward();
- }
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('b', (state, context) -> {
- for (int i = 0; i < context.readCount(state.count()); i++) {
- context.moveWordBackward();
- }
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('0', (state, context) -> {
- context.moveLineStart();
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('$', (state, context) -> {
- context.moveLineEnd();
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('G', (state, context) -> {
- context.moveDocumentEnd();
- context.updateVisualSelection(state.anchor());
- return HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
- });
- map.put('g', (state, context) -> HandleResult
- .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.G_PREFIX, 0)));
- map.put('d', (state, context) -> context.applyVisualOperator(state, PendingOperator.DELETE));
- map.put('y', (state, context) -> context.applyVisualOperator(state, PendingOperator.YANK));
- map.put('c', (state, context) -> context.applyVisualOperator(state, PendingOperator.CHANGE));
- return map;
- }
+ private Map<Character, CommandAction<VisualState>> createCommandActions() {
+ final Map<Character, CommandAction<VisualState>> map = new HashMap<>();
+ map.put('h', (state, context) -> {
+ for (int i = 0; i < context.readCount(state.count()); i++) {
+ context.moveLeft();
+ }
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('j', (state, context) -> {
+ final int preferred = context.moveVertical(1, context.readCount(state.count()), state.preferredColumn(),
+ false);
+ context.updateVisualSelection(state.anchor());
+ return HandleResult.handled(new VisualState(state.anchor(), preferred, PendingOperator.NONE, 0));
+ });
+ map.put('k', (state, context) -> {
+ final int preferred = context.moveVertical(-1, context.readCount(state.count()), state.preferredColumn(),
+ false);
+ context.updateVisualSelection(state.anchor());
+ return HandleResult.handled(new VisualState(state.anchor(), preferred, PendingOperator.NONE, 0));
+ });
+ map.put('l', (state, context) -> {
+ for (int i = 0; i < context.readCount(state.count()); i++) {
+ context.moveRightNormal();
+ }
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('w', (state, context) -> {
+ for (int i = 0; i < context.readCount(state.count()); i++) {
+ context.moveWordForward();
+ }
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('b', (state, context) -> {
+ for (int i = 0; i < context.readCount(state.count()); i++) {
+ context.moveWordBackward();
+ }
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('0', (state, context) -> {
+ context.moveLineStart();
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('$', (state, context) -> {
+ context.moveLineEnd();
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('G', (state, context) -> {
+ context.moveDocumentEnd();
+ context.updateVisualSelection(state.anchor());
+ return HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.NONE, 0));
+ });
+ map.put('g', (state, context) -> HandleResult
+ .handled(new VisualState(state.anchor(), state.preferredColumn(), PendingOperator.G_PREFIX, 0)));
+ map.put('d', (state, context) -> context.applyVisualOperator(state, PendingOperator.DELETE));
+ map.put('y', (state, context) -> context.applyVisualOperator(state, PendingOperator.YANK));
+ map.put('c', (state, context) -> context.applyVisualOperator(state, PendingOperator.CHANGE));
+ return map;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/Register.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/Register.java
index 9bacd59..44a3c4c 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/Register.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/Register.java
@@ -6,6 +6,6 @@ import lombok.Setter;
@Getter
@Setter
public class Register {
- private String text = "";
- private RegisterType type = RegisterType.CHARACTER;
+ private String text = "";
+ private RegisterType type = RegisterType.CHARACTER;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/RegisterType.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/RegisterType.java
index 9ecb900..71df9eb 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/RegisterType.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/RegisterType.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.model;
public enum RegisterType {
- CHARACTER, LINE
+ CHARACTER, LINE
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoManager.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoManager.java
index 34b2122..affb1a8 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoManager.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoManager.java
@@ -6,47 +6,47 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class UndoManager {
- private final int maxUndo;
- private final Deque<UndoState> undoStack = new ArrayDeque<>();
- private final Deque<UndoState> redoStack = new ArrayDeque<>();
+ private final int maxUndo;
+ private final Deque<UndoState> undoStack = new ArrayDeque<>();
+ private final Deque<UndoState> redoStack = new ArrayDeque<>();
- public void record(final String text, final int cursor) {
- final UndoState candidate = new UndoState(text, cursor);
- final UndoState top = undoStack.peekLast();
- if (top != null && top.getCursor() == candidate.getCursor() && top.getText().equals(candidate.getText())) {
- return;
- }
+ public void record(final String text, final int cursor) {
+ final UndoState candidate = new UndoState(text, cursor);
+ final UndoState top = undoStack.peekLast();
+ if (top != null && top.getCursor() == candidate.getCursor() && top.getText().equals(candidate.getText())) {
+ return;
+ }
- undoStack.addLast(candidate);
- while (undoStack.size() > maxUndo) {
- undoStack.removeFirst();
- }
- redoStack.clear();
- }
+ undoStack.addLast(candidate);
+ while (undoStack.size() > maxUndo) {
+ undoStack.removeFirst();
+ }
+ redoStack.clear();
+ }
- public UndoState undo() {
- if (undoStack.size() <= 1) {
- return null;
- }
+ public UndoState undo() {
+ if (undoStack.size() <= 1) {
+ return null;
+ }
- final UndoState current = undoStack.removeLast();
- redoStack.addLast(current);
- return undoStack.peekLast();
- }
+ final UndoState current = undoStack.removeLast();
+ redoStack.addLast(current);
+ return undoStack.peekLast();
+ }
- public UndoState redo() {
- if (redoStack.isEmpty()) {
- return null;
- }
+ public UndoState redo() {
+ if (redoStack.isEmpty()) {
+ return null;
+ }
- final UndoState target = redoStack.removeLast();
- final UndoState top = undoStack.peekLast();
- if (top == null || !top.getText().equals(target.getText()) || top.getCursor() != target.getCursor()) {
- undoStack.addLast(target);
- while (undoStack.size() > maxUndo) {
- undoStack.removeFirst();
- }
- }
- return target;
- }
+ final UndoState target = redoStack.removeLast();
+ final UndoState top = undoStack.peekLast();
+ if (top == null || !top.getText().equals(target.getText()) || top.getCursor() != target.getCursor()) {
+ undoStack.addLast(target);
+ while (undoStack.size() > maxUndo) {
+ undoStack.removeFirst();
+ }
+ }
+ return target;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoState.java
index c91ebcd..04375aa 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/model/UndoState.java
@@ -6,6 +6,6 @@ import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class UndoState {
- private final String text;
- private final int cursor;
+ private final String text;
+ private final int cursor;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java
index c9ef857..b74c1df 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java
@@ -1,110 +1,110 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.navigation;
public class TextNavigation {
- public int findLineStart(final String text, final int cursor) {
- int index = Math.max(0, Math.min(cursor, text.length()));
- while (index > 0 && text.charAt(index - 1) != '\n') {
- index--;
- }
- return index;
- }
+ public int findLineStart(final String text, final int cursor) {
+ int index = Math.max(0, Math.min(cursor, text.length()));
+ while (index > 0 && text.charAt(index - 1) != '\n') {
+ index--;
+ }
+ return index;
+ }
- public int findLineEnd(final String text, final int cursor) {
- final int lineStart = findLineStart(text, cursor);
- int index = lineStart;
- while (index < text.length() && text.charAt(index) != '\n') {
- index++;
- }
- if (index == lineStart) {
- return lineStart;
- }
- return index - 1;
- }
+ public int findLineEnd(final String text, final int cursor) {
+ final int lineStart = findLineStart(text, cursor);
+ int index = lineStart;
+ while (index < text.length() && text.charAt(index) != '\n') {
+ index++;
+ }
+ if (index == lineStart) {
+ return lineStart;
+ }
+ return index - 1;
+ }
- public int findLineEndExclusiveByStart(final String text, final int lineStart) {
- int index = lineStart;
- while (index < text.length() && text.charAt(index) != '\n') {
- index++;
- }
- return index;
- }
+ public int findLineEndExclusiveByStart(final String text, final int lineStart) {
+ int index = lineStart;
+ while (index < text.length() && text.charAt(index) != '\n') {
+ index++;
+ }
+ return index;
+ }
- public int findNextLineStart(final String text, final int start) {
- final int newline = text.indexOf('\n', Math.max(0, start));
- if (newline < 0) {
- return -1;
- }
- return newline + 1;
- }
+ public int findNextLineStart(final String text, final int start) {
+ final int newline = text.indexOf('\n', Math.max(0, start));
+ if (newline < 0) {
+ return -1;
+ }
+ return newline + 1;
+ }
- public int findPreviousLineStart(final String text, final int lineStart) {
- final int clampedLineStart = Math.max(0, Math.min(lineStart, text.length()));
- if (clampedLineStart <= 0) {
- return -1;
- }
- final int previousNewline = text.lastIndexOf('\n', clampedLineStart - 2);
- return previousNewline + 1;
- }
+ public int findPreviousLineStart(final String text, final int lineStart) {
+ final int clampedLineStart = Math.max(0, Math.min(lineStart, text.length()));
+ if (clampedLineStart <= 0) {
+ return -1;
+ }
+ final int previousNewline = text.lastIndexOf('\n', clampedLineStart - 2);
+ return previousNewline + 1;
+ }
- public int findBelowLineInsertionIndex(final String text, final int cursor) {
- final int lineStart = findLineStart(text, cursor);
- final int lineEnd = findLineEnd(text, cursor);
- final boolean currentLineIsEmpty = findLineEndExclusiveByStart(text, lineStart) == lineStart;
- int insertAt = Math.min(lineEnd + 1, text.length());
- if (!currentLineIsEmpty && insertAt < text.length() && text.charAt(insertAt) == '\n') {
- insertAt++;
- }
- return insertAt;
- }
+ public int findBelowLineInsertionIndex(final String text, final int cursor) {
+ final int lineStart = findLineStart(text, cursor);
+ final int lineEnd = findLineEnd(text, cursor);
+ final boolean currentLineIsEmpty = findLineEndExclusiveByStart(text, lineStart) == lineStart;
+ int insertAt = Math.min(lineEnd + 1, text.length());
+ if (!currentLineIsEmpty && insertAt < text.length() && text.charAt(insertAt) == '\n') {
+ insertAt++;
+ }
+ return insertAt;
+ }
- public int findLineStartByLine(final String text, final int lineNumber) {
- int line = 0;
- int index = 0;
- while (line < lineNumber && index < text.length()) {
- if (text.charAt(index) == '\n') {
- line++;
- }
- index++;
- }
- return index;
- }
+ public int findLineStartByLine(final String text, final int lineNumber) {
+ int line = 0;
+ int index = 0;
+ while (line < lineNumber && index < text.length()) {
+ if (text.charAt(index) == '\n') {
+ line++;
+ }
+ index++;
+ }
+ return index;
+ }
- public int findLineSelectionEndByLine(final String text, final int lineNumber) {
- int index = findLineStartByLine(text, lineNumber);
- while (index < text.length() && text.charAt(index) != '\n') {
- index++;
- }
- if (index < text.length() && text.charAt(index) == '\n') {
- return index + 1;
- }
- return text.length();
- }
+ public int findLineSelectionEndByLine(final String text, final int lineNumber) {
+ int index = findLineStartByLine(text, lineNumber);
+ while (index < text.length() && text.charAt(index) != '\n') {
+ index++;
+ }
+ if (index < text.length() && text.charAt(index) == '\n') {
+ return index + 1;
+ }
+ return text.length();
+ }
- public int lastNavigablePosition(final String text) {
- if (text.isEmpty()) {
- return 0;
- }
+ public int lastNavigablePosition(final String text) {
+ if (text.isEmpty()) {
+ return 0;
+ }
- return text.length() - 1;
- }
+ return text.length() - 1;
+ }
- public int maxCursorPositionInNormalMode(final String text) {
- if (text.isEmpty()) {
- return 0;
- }
- return text.length() - 1;
- }
+ public int maxCursorPositionInNormalMode(final String text) {
+ if (text.isEmpty()) {
+ return 0;
+ }
+ return text.length() - 1;
+ }
- public boolean isWordCharacter(final char character) {
- return Character.isLetterOrDigit(character) || character == '_';
- }
+ public boolean isWordCharacter(final char character) {
+ return Character.isLetterOrDigit(character) || character == '_';
+ }
- public boolean isInlineWhitespace(final char character) {
- return Character.isWhitespace(character) && character != '\n' && character != '\r';
- }
+ public boolean isInlineWhitespace(final char character) {
+ return Character.isWhitespace(character) && character != '\n' && character != '\r';
+ }
- public boolean isPunctuationWord(final char character) {
- return !isWordCharacter(character) && !Character.isWhitespace(character) && character != '\n'
- && character != '\r';
- }
+ public boolean isPunctuationWord(final char character) {
+ return !isWordCharacter(character) && !Character.isWhitespace(character) && character != '\n'
+ && character != '\r';
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchDirection.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchDirection.java
index ca3d63e..b157d16 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchDirection.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchDirection.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.search;
public enum SearchDirection {
- FORWARD, BACKWARD
+ FORWARD, BACKWARD
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchIterator.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchIterator.java
index 50f0e1c..a5e078b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchIterator.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/search/SearchIterator.java
@@ -3,56 +3,56 @@ package coffee.liz.abstractionengine.app.ui.editor.vim.search;
import java.util.OptionalInt;
public class SearchIterator {
- private final String text;
- private final String query;
- private final SearchDirection direction;
- private final boolean wrap;
- private int nextStart;
- private boolean wrapped;
+ private final String text;
+ private final String query;
+ private final SearchDirection direction;
+ private final boolean wrap;
+ private int nextStart;
+ private boolean wrapped;
- public SearchIterator(final String text, final String query, final int startIndex, final SearchDirection direction,
- final boolean wrap) {
- this.text = text == null ? "" : text;
- this.query = query == null ? "" : query;
- this.direction = direction;
- this.wrap = wrap;
- if (direction == SearchDirection.FORWARD) {
- this.nextStart = Math.min(this.text.length(), Math.max(0, startIndex + 1));
- } else {
- this.nextStart = Math.max(0, startIndex - 1);
- }
- this.wrapped = false;
- }
+ public SearchIterator(final String text, final String query, final int startIndex, final SearchDirection direction,
+ final boolean wrap) {
+ this.text = text == null ? "" : text;
+ this.query = query == null ? "" : query;
+ this.direction = direction;
+ this.wrap = wrap;
+ if (direction == SearchDirection.FORWARD) {
+ this.nextStart = Math.min(this.text.length(), Math.max(0, startIndex + 1));
+ } else {
+ this.nextStart = Math.max(0, startIndex - 1);
+ }
+ this.wrapped = false;
+ }
- public OptionalInt nextMatch() {
- if (query.isEmpty() || text.isEmpty()) {
- return OptionalInt.empty();
- }
+ public OptionalInt nextMatch() {
+ if (query.isEmpty() || text.isEmpty()) {
+ return OptionalInt.empty();
+ }
- if (direction == SearchDirection.FORWARD) {
- final int found = text.indexOf(query, nextStart);
- if (found >= 0) {
- nextStart = Math.min(text.length(), found + 1);
- return OptionalInt.of(found);
- }
- if (wrap && !wrapped) {
- wrapped = true;
- nextStart = 0;
- return nextMatch();
- }
- return OptionalInt.empty();
- }
+ if (direction == SearchDirection.FORWARD) {
+ final int found = text.indexOf(query, nextStart);
+ if (found >= 0) {
+ nextStart = Math.min(text.length(), found + 1);
+ return OptionalInt.of(found);
+ }
+ if (wrap && !wrapped) {
+ wrapped = true;
+ nextStart = 0;
+ return nextMatch();
+ }
+ return OptionalInt.empty();
+ }
- final int found = text.lastIndexOf(query, nextStart);
- if (found >= 0) {
- nextStart = Math.max(0, found - 1);
- return OptionalInt.of(found);
- }
- if (wrap && !wrapped) {
- wrapped = true;
- nextStart = Math.max(0, text.length() - 1);
- return nextMatch();
- }
- return OptionalInt.empty();
- }
+ final int found = text.lastIndexOf(query, nextStart);
+ if (found >= 0) {
+ nextStart = Math.max(0, found - 1);
+ return OptionalInt.of(found);
+ }
+ if (wrap && !wrapped) {
+ wrapped = true;
+ nextStart = Math.max(0, text.length() - 1);
+ return nextMatch();
+ }
+ return OptionalInt.empty();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/ModeState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/ModeState.java
index 78d2fb8..e878dd7 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/ModeState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/ModeState.java
@@ -1,15 +1,15 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.state;
public sealed interface ModeState permits InsertState, NormalState, SearchState, VisualLineState, VisualState {
- default PendingOperator pendingOperator() {
- return PendingOperator.NONE;
- }
+ default PendingOperator pendingOperator() {
+ return PendingOperator.NONE;
+ }
- default int count() {
- return 0;
- }
+ default int count() {
+ return 0;
+ }
- default int preferredColumn() {
- return -1;
- }
+ default int preferredColumn() {
+ return -1;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/NormalState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/NormalState.java
index 42b1d99..d86e842 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/NormalState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/NormalState.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.state;
public record NormalState(int count, PendingOperator pendingOperator, int preferredColumn) implements ModeState {
- public static final NormalState DEFAULT = new NormalState(0, PendingOperator.NONE, -1);
+ public static final NormalState DEFAULT = new NormalState(0, PendingOperator.NONE, -1);
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/PendingOperator.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/PendingOperator.java
index 1fc4425..60f22f0 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/PendingOperator.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/PendingOperator.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.state;
public enum PendingOperator {
- NONE, DELETE, YANK, CHANGE, G_PREFIX
+ NONE, DELETE, YANK, CHANGE, G_PREFIX
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/SearchState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/SearchState.java
index 7de6811..fb2ba40 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/SearchState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/SearchState.java
@@ -3,9 +3,9 @@ package coffee.liz.abstractionengine.app.ui.editor.vim.state;
import coffee.liz.abstractionengine.app.ui.editor.vim.search.SearchDirection;
public record SearchState(StringBuilder query, String lastQuery, SearchDirection direction) implements ModeState {
- public SearchState {
- query = query == null ? new StringBuilder() : query;
- lastQuery = lastQuery == null ? "" : lastQuery;
- direction = direction == null ? SearchDirection.FORWARD : direction;
- }
+ public SearchState {
+ query = query == null ? new StringBuilder() : query;
+ lastQuery = lastQuery == null ? "" : lastQuery;
+ direction = direction == null ? SearchDirection.FORWARD : direction;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualLineState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualLineState.java
index b486223..19c74b7 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualLineState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualLineState.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.state;
public record VisualLineState(int anchorLine, int cursorLine, int preferredColumn, PendingOperator pendingOperator,
- int count) implements ModeState {
+ int count) implements ModeState {
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualState.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualState.java
index 97604c8..373028c 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/state/VisualState.java
@@ -1,5 +1,5 @@
package coffee.liz.abstractionengine.app.ui.editor.vim.state;
public record VisualState(int anchor, int preferredColumn, PendingOperator pendingOperator,
- int count) implements ModeState {
+ int count) implements ModeState {
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/status/StatusFormatter.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/status/StatusFormatter.java
index 4ef8c17..ab5321f 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/status/StatusFormatter.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/status/StatusFormatter.java
@@ -10,47 +10,47 @@ import coffee.liz.abstractionengine.app.ui.editor.vim.state.VisualLineState;
import coffee.liz.abstractionengine.app.ui.editor.vim.state.VisualState;
public class StatusFormatter {
- public String format(final ModeState state, final VimConfig config) {
- return switch (state) {
- case NormalState normalState -> formatNormal(normalState, config);
- case InsertState ignored -> config.insertStatusLabel();
- case VisualState ignored -> config.visualStatusLabel();
- case VisualLineState ignored -> config.visualLineStatusLabel();
- case SearchState searchState -> '/' + searchState.query().toString();
- };
- }
+ public String format(final ModeState state, final VimConfig config) {
+ return switch (state) {
+ case NormalState normalState -> formatNormal(normalState, config);
+ case InsertState ignored -> config.insertStatusLabel();
+ case VisualState ignored -> config.visualStatusLabel();
+ case VisualLineState ignored -> config.visualLineStatusLabel();
+ case SearchState searchState -> '/' + searchState.query().toString();
+ };
+ }
- private String formatNormal(final NormalState state, final VimConfig config) {
- final StringBuilder builder = new StringBuilder(config.normalStatusLabel());
- appendOperator(builder, state.pendingOperator());
- if (state.count() > 0) {
- builder.append(" count=").append(state.count());
- }
- return builder.toString();
- }
+ private String formatNormal(final NormalState state, final VimConfig config) {
+ final StringBuilder builder = new StringBuilder(config.normalStatusLabel());
+ appendOperator(builder, state.pendingOperator());
+ if (state.count() > 0) {
+ builder.append(" count=").append(state.count());
+ }
+ return builder.toString();
+ }
- private void appendOperator(final StringBuilder builder, final PendingOperator pendingOperator) {
- if (pendingOperator == PendingOperator.NONE) {
- return;
- }
+ private void appendOperator(final StringBuilder builder, final PendingOperator pendingOperator) {
+ if (pendingOperator == PendingOperator.NONE) {
+ return;
+ }
- builder.append(" [");
- switch (pendingOperator) {
- case DELETE :
- builder.append('d');
- break;
- case YANK :
- builder.append('y');
- break;
- case CHANGE :
- builder.append('c');
- break;
- case G_PREFIX :
- builder.append('g');
- break;
- default :
- break;
- }
- builder.append(']');
- }
+ builder.append(" [");
+ switch (pendingOperator) {
+ case DELETE :
+ builder.append('d');
+ break;
+ case YANK :
+ builder.append('y');
+ break;
+ case CHANGE :
+ builder.append('c');
+ break;
+ case G_PREFIX :
+ builder.append('g');
+ break;
+ default :
+ break;
+ }
+ builder.append(']');
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/utils/FontHelper.java b/core/src/main/java/coffee/liz/abstractionengine/app/utils/FontHelper.java
index b38f25c..8db56a7 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/utils/FontHelper.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/utils/FontHelper.java
@@ -7,26 +7,26 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
public final class FontHelper {
- private FontHelper() {
- }
+ private FontHelper() {
+ }
- public static final String RENDERABLE_CHARS = "λ" + FreeTypeFontGenerator.DEFAULT_CHARS;
- public static final String MONO = "fonts/JetBrainsMonoNerdFont-Regular.ttf";
+ public static final String RENDERABLE_CHARS = "λ" + FreeTypeFontGenerator.DEFAULT_CHARS;
+ public static final String MONO = "fonts/JetBrainsMonoNerdFont-Regular.ttf";
- public static BitmapFont initFont(final int size, final String path, final float scale) {
- final int scaleForHidpi = 4;
- final FreeTypeFontGenerator gen = new FreeTypeFontGenerator(Gdx.files.internal(path));
- final FreeTypeFontGenerator.FreeTypeFontParameter params = new FreeTypeFontGenerator.FreeTypeFontParameter();
- params.characters = RENDERABLE_CHARS;
- params.size = scaleForHidpi * size;
+ public static BitmapFont initFont(final int size, final String path, final float scale) {
+ final int scaleForHidpi = 4;
+ final FreeTypeFontGenerator gen = new FreeTypeFontGenerator(Gdx.files.internal(path));
+ final FreeTypeFontGenerator.FreeTypeFontParameter params = new FreeTypeFontGenerator.FreeTypeFontParameter();
+ params.characters = RENDERABLE_CHARS;
+ params.size = scaleForHidpi * size;
- final BitmapFont font = gen.generateFont(params);
- font.setFixedWidthGlyphs(RENDERABLE_CHARS);
- font.setUseIntegerPositions(false);
- font.getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
- font.getData().setScale((1f / scaleForHidpi) * scale);
+ final BitmapFont font = gen.generateFont(params);
+ font.setFixedWidthGlyphs(RENDERABLE_CHARS);
+ font.setUseIntegerPositions(false);
+ font.getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
+ font.getData().setScale((1f / scaleForHidpi) * scale);
- gen.dispose();
- return font;
- }
+ gen.dispose();
+ return font;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/utils/FunctionUtils.java b/core/src/main/java/coffee/liz/abstractionengine/app/utils/FunctionUtils.java
index c219df0..c985e48 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/utils/FunctionUtils.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/utils/FunctionUtils.java
@@ -1,28 +1,28 @@
package coffee.liz.abstractionengine.app.utils;
public final class FunctionUtils {
- private FunctionUtils() {
- }
+ private FunctionUtils() {
+ }
- /**
- * Runs the provided action and wraps failures into a {@link RuntimeException}.
- *
- * @param run
- * action to execute
- */
- public static <E extends Throwable> void wrapCheckedException(final ThrowableRunnable<E> run) {
- try {
- run.run();
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
- }
+ /**
+ * Runs the provided action and wraps failures into a {@link RuntimeException}.
+ *
+ * @param run
+ * action to execute
+ */
+ public static <E extends Throwable> void wrapCheckedException(final ThrowableRunnable<E> run) {
+ try {
+ run.run();
+ } catch (final Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
- @FunctionalInterface
- public interface ThrowableRunnable<E extends Throwable> {
- /**
- * Run.
- */
- void run() throws E;
- }
+ @FunctionalInterface
+ public interface ThrowableRunnable<E extends Throwable> {
+ /**
+ * Run.
+ */
+ void run() throws E;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/utils/TimerUtils.java b/core/src/main/java/coffee/liz/abstractionengine/app/utils/TimerUtils.java
index dea7bd2..77f074b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/utils/TimerUtils.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/utils/TimerUtils.java
@@ -3,22 +3,22 @@ package coffee.liz.abstractionengine.app.utils;
import com.badlogic.gdx.utils.Timer;
public final class TimerUtils {
- private TimerUtils() {
- }
+ private TimerUtils() {
+ }
- /**
- * Creates a {@link Timer.Task} from a runnable.
- *
- * @param r
- * action to run
- * @return timer task that runs the action
- */
- public static Timer.Task sideEffectTask(final Runnable r) {
- return new Timer.Task() {
- @Override
- public void run() {
- r.run();
- }
- };
- }
+ /**
+ * Creates a {@link Timer.Task} from a runnable.
+ *
+ * @param r
+ * action to run
+ * @return timer task that runs the action
+ */
+ public static Timer.Task sideEffectTask(final Runnable r) {
+ return new Timer.Task() {
+ @Override
+ public void run() {
+ r.run();
+ }
+ };
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java
index 99a6eb7..d8299aa 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java
@@ -11,70 +11,70 @@ import java.util.List;
import java.util.function.BiFunction;
public final class EntityFactory {
- private EntityFactory() {
- }
+ private EntityFactory() {
+ }
- /**
- * {@link EntityType#PLAYER} factory.
- */
- public final class Player {
- private Player() {
- }
+ /**
+ * {@link EntityType#PLAYER} factory.
+ */
+ public final class Player {
+ private Player() {
+ }
- public static Entity addToWorld(final World<?> world, final Vec2<Integer> position) {
- return world.createEntity().add(new GridPosition(position)).add(new GridControllable())
- .add(EntityType.PLAYER).add(new EntityTypeGridCollidable());
- }
- }
+ public static Entity addToWorld(final World<?> world, final Vec2<Integer> position) {
+ return world.createEntity().add(new GridPosition(position)).add(new GridControllable())
+ .add(EntityType.PLAYER).add(new EntityTypeGridCollidable());
+ }
+ }
- /**
- * {@link EntityType#WALL} factory.
- */
- public final class Wall {
- private Wall() {
- }
+ /**
+ * {@link EntityType#WALL} factory.
+ */
+ public final class Wall {
+ private Wall() {
+ }
- public static Entity addToWorld(final World<?> world, final Vec2<Integer> position) {
- return world.createEntity().add(new GridPosition(position)).add(EntityType.WALL)
- .add(new EntityTypeGridCollidable());
- }
- }
+ public static Entity addToWorld(final World<?> world, final Vec2<Integer> position) {
+ return world.createEntity().add(new GridPosition(position)).add(EntityType.WALL)
+ .add(new EntityTypeGridCollidable());
+ }
+ }
- /**
- * {@link EntityType#ABSTRACTION} factory.
- */
- public final class Abstraction {
- private Abstraction() {
- }
+ /**
+ * {@link EntityType#ABSTRACTION} factory.
+ */
+ public final class Abstraction {
+ private Abstraction() {
+ }
- public static Entity addToWorld(final World<?> world, final Vec2<Integer> position) {
- return world.createEntity().add(new GridPosition(position)).add(EntityType.ABSTRACTION)
- .add(new EntityTypeGridCollidable());
- }
- }
+ public static Entity addToWorld(final World<?> world, final Vec2<Integer> position) {
+ return world.createEntity().add(new GridPosition(position)).add(EntityType.ABSTRACTION)
+ .add(new EntityTypeGridCollidable());
+ }
+ }
- /**
- * Populates entities on the border of a rectangle of defined dimensions.
- *
- * @param dimensions
- * are the world dimensions.
- * @param world
- * is the world to populate
- * @param factory
- * accepts the world and position in the world and creates the
- * entity.
- * @return 2d matrix of entities at each position in the world of populated
- * entities.
- */
- public static List<List<Entity>> populateRect(final Vec2<Integer> dimensions, final World<?> world,
- final BiFunction<World<?>, Vec2<Integer>, Entity> factory) {
- return Mat2.init(dimensions, pos -> {
- final boolean isXBorder = pos.getX() == 0 || pos.getX() == dimensions.getX() - 1;
- final boolean isYBorder = pos.getY() == 0 || pos.getY() == dimensions.getY() - 1;
- if (isXBorder || isYBorder) {
- return factory.apply(world, pos);
- }
- return null;
- });
- }
+ /**
+ * Populates entities on the border of a rectangle of defined dimensions.
+ *
+ * @param dimensions
+ * are the world dimensions.
+ * @param world
+ * is the world to populate
+ * @param factory
+ * accepts the world and position in the world and creates the
+ * entity.
+ * @return 2d matrix of entities at each position in the world of populated
+ * entities.
+ */
+ public static List<List<Entity>> populateRect(final Vec2<Integer> dimensions, final World<?> world,
+ final BiFunction<World<?>, Vec2<Integer>, Entity> factory) {
+ return Mat2.init(dimensions, pos -> {
+ final boolean isXBorder = pos.getX() == 0 || pos.getX() == dimensions.getX() - 1;
+ final boolean isYBorder = pos.getY() == 0 || pos.getY() == dimensions.getY() - 1;
+ if (isXBorder || isYBorder) {
+ return factory.apply(world, pos);
+ }
+ return null;
+ });
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityType.java b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityType.java
index e0bf243..93fa160 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityType.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityType.java
@@ -9,44 +9,44 @@ import coffee.liz.ecs.model.Component;
* {@link coffee.liz.abstractionengine.AbstractionEngineGridWorld}
*/
public enum EntityType implements Component {
- /** Player entity */
- PLAYER,
- /** Wall entity. Nothing goes through this */
- WALL,
- /** Lambda term producer */
- PRODUCER,
- /** Lambda abstraction */
- ABSTRACTION,
- /** Lambda application */
- APPLICATION,
- /** Lava */
- LAVA,
- /** Bridge */
- BRIDGE;
+ /** Player entity */
+ PLAYER,
+ /** Wall entity. Nothing goes through this */
+ WALL,
+ /** Lambda term producer */
+ PRODUCER,
+ /** Lambda abstraction */
+ ABSTRACTION,
+ /** Lambda application */
+ APPLICATION,
+ /** Lava */
+ LAVA,
+ /** Bridge */
+ BRIDGE;
- /**
- * Gets the collision behavior to apply based on the colliding types.
- *
- * @param that
- * is the {@link EntityType} colliding.
- * @return collision behavior to resolve.
- */
- public CollisionBehavior collideWith(final EntityType that) {
- if (that.equals(WALL)) {
- return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.WALL).priority(0).build();
- }
- if (this.equals(ABSTRACTION) && that.equals(APPLICATION)) {
- return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(0).build();
- }
+ /**
+ * Gets the collision behavior to apply based on the colliding types.
+ *
+ * @param that
+ * is the {@link EntityType} colliding.
+ * @return collision behavior to resolve.
+ */
+ public CollisionBehavior collideWith(final EntityType that) {
+ if (that.equals(WALL)) {
+ return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.WALL).priority(0).build();
+ }
+ if (this.equals(ABSTRACTION) && that.equals(APPLICATION)) {
+ return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(0).build();
+ }
- if (that.equals(LAVA)) {
- return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(1).build();
- }
- if (that.equals(BRIDGE)) { // BRIDGE takes precedence over LAVA, so stuff can walk on a bridge over
- // LAVA
- return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(0).build();
- }
+ if (that.equals(LAVA)) {
+ return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(1).build();
+ }
+ if (that.equals(BRIDGE)) { // BRIDGE takes precedence over LAVA, so stuff can walk on a bridge over
+ // LAVA
+ return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(0).build();
+ }
- return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.PROPAGATE).priority(0).build();
- }
+ return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.PROPAGATE).priority(0).build();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityTypeGridCollidable.java b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityTypeGridCollidable.java
index c75b717..e7def51 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityTypeGridCollidable.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityTypeGridCollidable.java
@@ -7,8 +7,8 @@ import lombok.Data;
@Data
public class EntityTypeGridCollidable implements GridCollidable {
- @Override
- public CollisionBehavior getCollisionBehaviorBetween(final Entity me, final Entity them) {
- return me.get(EntityType.class).collideWith(them.get(EntityType.class));
- }
+ @Override
+ public CollisionBehavior getCollisionBehaviorBetween(final Entity me, final Entity them) {
+ return me.get(EntityType.class).collideWith(them.get(EntityType.class));
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridCollidable.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridCollidable.java
index e72d4e8..44b36f2 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridCollidable.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridCollidable.java
@@ -10,56 +10,56 @@ import lombok.RequiredArgsConstructor;
/** {@link Component} for grid collision handling. */
public interface GridCollidable extends Component {
- @RequiredArgsConstructor
- @Data
- @Builder
- class CollisionBehavior implements Comparable<CollisionBehavior> {
- private final CollisionBehaviorType collisionBehaviorType;
- private final int priority;
+ @RequiredArgsConstructor
+ @Data
+ @Builder
+ class CollisionBehavior implements Comparable<CollisionBehavior> {
+ private final CollisionBehaviorType collisionBehaviorType;
+ private final int priority;
- public int compareTo(final CollisionBehavior other) {
- return Integer.compare(getPriority(), other.getPriority());
- }
+ public int compareTo(final CollisionBehavior other) {
+ return Integer.compare(getPriority(), other.getPriority());
+ }
- public enum CollisionBehaviorType {
- /** Propagate collision to next entity. */
- PROPAGATE,
- /** Block collision like a wall. */
- WALL,
- /** Swallow the colliding entity. */
- SWALLOW;
- }
- }
+ public enum CollisionBehaviorType {
+ /** Propagate collision to next entity. */
+ PROPAGATE,
+ /** Block collision like a wall. */
+ WALL,
+ /** Swallow the colliding entity. */
+ SWALLOW;
+ }
+ }
- /**
- * Get collision behavior for colliding entity.
- *
- * @param me
- * the staring colliding {@link Entity}
- * @param them
- * the colliding {@link Entity}
- * @return the {@link CollisionBehavior}
- */
- CollisionBehavior getCollisionBehaviorBetween(final Entity me, final Entity them);
+ /**
+ * Get collision behavior for colliding entity.
+ *
+ * @param me
+ * the staring colliding {@link Entity}
+ * @param them
+ * the colliding {@link Entity}
+ * @return the {@link CollisionBehavior}
+ */
+ CollisionBehavior getCollisionBehaviorBetween(final Entity me, final Entity them);
- /**
- * Handle swallowing an entity.
- *
- * @param them
- * the {@link Entity} being swallowed
- * @param world
- * the {@link World} to modify
- */
- default <T> void onSwallow(final Entity them, final World<T> world) {
- throw new UnsupportedOperationException("Does not swallow"); // ...could not be me~ (つ﹏⊂)
- }
+ /**
+ * Handle swallowing an entity.
+ *
+ * @param them
+ * the {@link Entity} being swallowed
+ * @param world
+ * the {@link World} to modify
+ */
+ default <T> void onSwallow(final Entity them, final World<T> world) {
+ throw new UnsupportedOperationException("Does not swallow"); // ...could not be me~ (つ﹏⊂)
+ }
- /**
- * Anything that implements GridCollidable should be keyed by GridCollidable.
- *
- * @return Key type
- */
- default Class<? extends Component> getKey() {
- return GridCollidable.class;
- }
+ /**
+ * Anything that implements GridCollidable should be keyed by GridCollidable.
+ *
+ * @return Key type
+ */
+ default Class<? extends Component> getKey() {
+ return GridCollidable.class;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java
index 8fadb09..6ab0d2b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java
@@ -16,22 +16,22 @@ import jakarta.annotation.Nullable;
@AllArgsConstructor
@Builder
public class GridInputState {
- /** Movement {@link Vec2} direction. */
- @Nullable
- private final Vec2<Integer> movement;
+ /** Movement {@link Vec2} direction. */
+ @Nullable
+ private final Vec2<Integer> movement;
- /** Lambda term update to apply. */
- @Nullable
- private final UpdateLambdaTerm updateLambdaTerm;
+ /** Lambda term update to apply. */
+ @Nullable
+ private final UpdateLambdaTerm updateLambdaTerm;
- /** Update lambda term with target entity. */
- @Getter
- @RequiredArgsConstructor
- public static class UpdateLambdaTerm {
- /** {@link Entity} to update. */
- private final Entity toUpdate;
+ /** Update lambda term with target entity. */
+ @Getter
+ @RequiredArgsConstructor
+ public static class UpdateLambdaTerm {
+ /** {@link Entity} to update. */
+ private final Entity toUpdate;
- /** {@link LambdaProgram} to apply. */
- private final LambdaProgram lambdaProgram;
- }
+ /** {@link LambdaProgram} to apply. */
+ private final LambdaProgram lambdaProgram;
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridMomentum.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridMomentum.java
index aec26b1..0281924 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridMomentum.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridMomentum.java
@@ -1,8 +1,10 @@
package coffee.liz.abstractionengine.grid.component;
import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.math.Vec2i;
import coffee.liz.ecs.model.Component;
+import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -12,6 +14,6 @@ import lombok.RequiredArgsConstructor;
@Data
@Getter
public class GridMomentum implements Component {
- /** Velocity {@link Vec2}. */
- private final Vec2<Integer> velocity;
+ /** Current velocity {@link Vec2}. */
+ private final Vec2<Integer> velocity;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridPosition.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridPosition.java
index 4ec0557..7b1769e 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridPosition.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridPosition.java
@@ -12,5 +12,5 @@ import lombok.RequiredArgsConstructor;
@Data
@Getter
public class GridPosition implements Component {
- private final Vec2<Integer> position;
+ private final Vec2<Integer> position;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java
index 4af8be0..ee77256 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java
@@ -20,36 +20,36 @@ import java.util.Set;
@RequiredArgsConstructor
@Getter
public abstract class BaseGridIndexSystem<T> implements System<T> {
- protected final Vec2<Integer> dimensions;
- protected final List<List<Set<Entity>>> rows;
+ protected final Vec2<Integer> dimensions;
+ protected final List<List<Set<Entity>>> rows;
- public BaseGridIndexSystem(final Vec2<Integer> dimensions) {
- this.dimensions = dimensions;
- this.rows = Mat2.init(dimensions, _ -> new HashSet<>());
- }
+ public BaseGridIndexSystem(final Vec2<Integer> dimensions) {
+ this.dimensions = dimensions;
+ this.rows = Mat2.init(dimensions, _ -> new HashSet<>());
+ }
- @Override
- public Collection<Class<? extends System<T>>> getDependencies() {
- return Set.of();
- }
+ @Override
+ public Collection<Class<? extends System<T>>> getDependencies() {
+ return Set.of();
+ }
- @Override
- public void update(final World<T> world, final T state, final Duration dt) {
- rows.forEach(row -> row.forEach(Set::clear));
- world.query(Set.of(GridPosition.class)).forEach(entity -> {
- final GridPosition position = entity.get(GridPosition.class);
- rows.get(position.getPosition().getY()).get(position.getPosition().getX()).add(entity);
- });
- }
+ @Override
+ public void update(final World<T> world, final T state, final Duration dt) {
+ rows.forEach(row -> row.forEach(Set::clear));
+ world.query(Set.of(GridPosition.class)).forEach(entity -> {
+ final GridPosition position = entity.get(GridPosition.class);
+ rows.get(position.getPosition().getY()).get(position.getPosition().getX()).add(entity);
+ });
+ }
- public Collection<Entity> entitiesAt(final Vec2<Integer> pos) {
- if (!inBounds(pos)) {
- return Collections.emptySet();
- }
- return Set.copyOf(rows.get(pos.getY()).get(pos.getX()));
- }
+ public Collection<Entity> entitiesAt(final Vec2<Integer> pos) {
+ if (!inBounds(pos)) {
+ return Collections.emptySet();
+ }
+ return Set.copyOf(rows.get(pos.getY()).get(pos.getX()));
+ }
- public boolean inBounds(final Vec2<Integer> pos) {
- return pos.getX() >= 0 && pos.getX() < dimensions.getX() && pos.getY() >= 0 && pos.getY() < dimensions.getY();
- }
+ public boolean inBounds(final Vec2<Integer> pos) {
+ return pos.getX() >= 0 && pos.getX() < dimensions.getX() && pos.getY() >= 0 && pos.getY() < dimensions.getY();
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java
index 33c86c8..23a821d 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java
@@ -24,85 +24,85 @@ import java.util.Set;
* System which resolves collisions between cells in the Grid.
*/
public class GridCollisionPropagatationSystem implements System<GridInputState> {
- @Override
- public Collection<Class<? extends System<GridInputState>>> getDependencies() {
- return Set.of(GridMovementSystem.class, GridIndexSystem.class);
- }
+ @Override
+ public Collection<Class<? extends System<GridInputState>>> getDependencies() {
+ return Set.of(GridMovementSystem.class, GridIndexSystem.class);
+ }
- @Override
- public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
- world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)).forEach(pusher -> {
- final Vec2<Integer> velocity = pusher.get(GridMomentum.class).getVelocity();
- if (velocity.equals(Vec2i.ZERO)) {
- return;
- }
+ @Override
+ public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
+ world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)).forEach(pusher -> {
+ final Vec2<Integer> velocity = pusher.get(GridMomentum.class).getVelocity();
+ if (velocity.equals(Vec2i.ZERO)) {
+ return;
+ }
- final Vec2<Integer> position = pusher.get(GridPosition.class).getPosition();
- final CollisionRayResult result = resolveCollisionRay(world, pusher, position, velocity);
+ final Vec2<Integer> position = pusher.get(GridPosition.class).getPosition();
+ final CollisionRayResult result = resolveCollisionRay(world, pusher, position, velocity);
- pusher.add(new GridMomentum(Vec2i.ZERO));
- if (result instanceof CollisionRayResult.Blocked) {
- return;
- }
+ pusher.add(new GridMomentum(Vec2i.ZERO));
+ if (result instanceof CollisionRayResult.Blocked) {
+ return;
+ }
- final CollisionRayResult.Propagated propagated = (CollisionRayResult.Propagated) result;
- propagated.ray().forEach(e -> e.add(new GridMomentum(propagated.direction())));
- propagated.swallows()
- .forEach(entry -> entry.getKey().get(GridCollidable.class).onSwallow(entry.getValue(), world));
- });
- }
+ final CollisionRayResult.Propagated propagated = (CollisionRayResult.Propagated) result;
+ propagated.ray().forEach(e -> e.add(new GridMomentum(propagated.direction())));
+ propagated.swallows()
+ .forEach(entry -> entry.getKey().get(GridCollidable.class).onSwallow(entry.getValue(), world));
+ });
+ }
- private CollisionRayResult resolveCollisionRay(World<GridInputState> world, Entity pusher, Vec2<Integer> start,
- Vec2<Integer> direction) {
- final GridIndexSystem gridIndex = world.getSystem(GridIndexSystem.class);
+ private CollisionRayResult resolveCollisionRay(World<GridInputState> world, Entity pusher, Vec2<Integer> start,
+ Vec2<Integer> direction) {
+ final GridIndexSystem gridIndex = world.getSystem(GridIndexSystem.class);
- final List<List<Entity>> ray = new ArrayList<>();
- ray.add(List.of(pusher));
- final Set<Map.Entry<Entity, Entity>> swallows = new HashSet<>();
+ final List<List<Entity>> ray = new ArrayList<>();
+ ray.add(List.of(pusher));
+ final Set<Map.Entry<Entity, Entity>> swallows = new HashSet<>();
- Vec2<Integer> gridPosition = start.plus(direction);
- while (!ray.getLast().isEmpty()) {
- if (!gridIndex.inBounds(gridPosition)) {
- return new CollisionRayResult.Blocked();
- }
+ Vec2<Integer> gridPosition = start.plus(direction);
+ while (!ray.getLast().isEmpty()) {
+ if (!gridIndex.inBounds(gridPosition)) {
+ return new CollisionRayResult.Blocked();
+ }
- final List<Entity> collidables = gridIndex.entitiesAt(gridPosition).stream()
- .filter(e -> e.has(GridCollidable.class)).toList();
- if (collidables.isEmpty()) {
- break;
- }
+ final List<Entity> collidables = gridIndex.entitiesAt(gridPosition).stream()
+ .filter(e -> e.has(GridCollidable.class)).toList();
+ if (collidables.isEmpty()) {
+ break;
+ }
- final List<Entity> nextRay = new ArrayList<>();
+ final List<Entity> nextRay = new ArrayList<>();
- for (final Entity push : ray.getLast()) {
- final Map.Entry<Entity, CollisionBehavior> behavior = collidables.stream()
- .map(c -> Map.entry(c, c.get(GridCollidable.class).getCollisionBehaviorBetween(push, c)))
- .min(Comparator.comparing(e -> e.getValue().getPriority())).orElseThrow();
+ for (final Entity push : ray.getLast()) {
+ final Map.Entry<Entity, CollisionBehavior> behavior = collidables.stream()
+ .map(c -> Map.entry(c, c.get(GridCollidable.class).getCollisionBehaviorBetween(push, c)))
+ .min(Comparator.comparing(e -> e.getValue().getPriority())).orElseThrow();
- switch (behavior.getValue().getCollisionBehaviorType()) {
- case PROPAGATE -> nextRay.add(behavior.getKey());
- case SWALLOW -> swallows.add(Map.entry(behavior.getKey(), push));
- case WALL -> {
- return new CollisionRayResult.Blocked();
- }
- }
- }
+ switch (behavior.getValue().getCollisionBehaviorType()) {
+ case PROPAGATE -> nextRay.add(behavior.getKey());
+ case SWALLOW -> swallows.add(Map.entry(behavior.getKey(), push));
+ case WALL -> {
+ return new CollisionRayResult.Blocked();
+ }
+ }
+ }
- ray.add(nextRay);
- gridPosition = gridPosition.plus(direction);
- }
+ ray.add(nextRay);
+ gridPosition = gridPosition.plus(direction);
+ }
- final Collection<Entity> rayEntities = ray.stream().flatMap(Collection::stream).toList();
- return new CollisionRayResult.Propagated(rayEntities, swallows, direction);
- }
+ final Collection<Entity> rayEntities = ray.stream().flatMap(Collection::stream).toList();
+ return new CollisionRayResult.Propagated(rayEntities, swallows, direction);
+ }
- private sealed interface CollisionRayResult permits CollisionRayResult.Propagated, CollisionRayResult.Blocked {
+ private sealed interface CollisionRayResult permits CollisionRayResult.Propagated, CollisionRayResult.Blocked {
- record Propagated(Collection<Entity> ray, Set<Map.Entry<Entity, Entity>> swallows,
- Vec2<Integer> direction) implements CollisionRayResult {
- }
+ record Propagated(Collection<Entity> ray, Set<Map.Entry<Entity, Entity>> swallows,
+ Vec2<Integer> direction) implements CollisionRayResult {
+ }
- record Blocked() implements CollisionRayResult {
- }
- }
+ record Blocked() implements CollisionRayResult {
+ }
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridIndexSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridIndexSystem.java
index ca2279f..aea669b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridIndexSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridIndexSystem.java
@@ -4,7 +4,7 @@ import coffee.liz.abstractionengine.grid.component.GridInputState;
import coffee.liz.ecs.math.Vec2;
public class GridIndexSystem extends BaseGridIndexSystem<GridInputState> {
- public GridIndexSystem(final Vec2<Integer> dimensions) {
- super(dimensions);
- }
+ public GridIndexSystem(final Vec2<Integer> dimensions) {
+ super(dimensions);
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java
index f5f1089..02f012b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java
@@ -18,14 +18,14 @@ import java.util.Set;
@RequiredArgsConstructor
@Getter
public class GridMovementSystem implements System<GridInputState> {
- @Override
- public Collection<Class<? extends System<GridInputState>>> getDependencies() {
- return Set.of();
- }
+ @Override
+ public Collection<Class<? extends System<GridInputState>>> getDependencies() {
+ return Set.of();
+ }
- @Override
- public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
- world.query(Set.of(GridControllable.class, GridPosition.class))
- .forEach(entity -> entity.add(new GridMomentum(state.getMovement())));
- }
+ @Override
+ public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
+ world.query(Set.of(GridControllable.class, GridPosition.class))
+ .forEach(entity -> entity.add(new GridMomentum(state.getMovement())));
+ }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java
index 88f8d57..5e0e632 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java
@@ -13,19 +13,19 @@ import java.util.Set;
/** System applying physics/position updates from momentum. */
public class GridPhysicsSystem implements System<GridInputState> {
- @Override
- public Collection<Class<? extends System<GridInputState>>> getDependencies() {
- return Set.of(GridCollisionPropagatationSystem.class);
- }
+ @Override
+ public Collection<Class<? extends System<GridInputState>>> getDependencies() {
+ return Set.of(GridCollisionPropagatationSystem.class);
+ }
- @Override
- public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
- world.query(Set.of(GridMomentum.class, GridPosition.class)).forEach(entity -> {
- final GridMomentum momentum = entity.get(GridMomentum.class);
- final GridPosition position = entity.get(GridPosition.class);
+ @Override
+ public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
+ world.query(Set.of(GridMomentum.class, GridPosition.class)).forEach(entity -> {
+ final GridMomentum momentum = entity.get(GridMomentum.class);
+ final GridPosition position = entity.get(GridPosition.class);
- entity.add(new GridPosition(position.getPosition().plus(momentum.getVelocity())));
- entity.add(new GridMomentum(Vec2i.ZERO));
- });
- }
+ entity.add(new GridPosition(position.getPosition().plus(momentum.getVelocity())));
+ entity.add(new GridMomentum(Vec2i.ZERO));
+ });
+ }
}
diff --git a/core/src/main/java/coffee/liz/ecs/DAGWorld.java b/core/src/main/java/coffee/liz/ecs/DAGWorld.java
index b5b54c2..24d5adc 100644
--- a/core/src/main/java/coffee/liz/ecs/DAGWorld.java
+++ b/core/src/main/java/coffee/liz/ecs/DAGWorld.java
@@ -26,140 +26,140 @@ import java.util.stream.Collectors;
@Log4j2
@RequiredArgsConstructor
public class DAGWorld<T> implements World<T> {
- /** All entities in the world. */
- protected final Set<Entity> entities = Collections.synchronizedSet(new HashSet<>());
+ /** All entities in the world. */
+ protected final Set<Entity> entities = Collections.synchronizedSet(new HashSet<>());
- /** Cache mapping component types to entities having that component. */
- private final Map<Class<? extends Component>, Set<Entity>> componentCache = Collections
- .synchronizedMap(new HashMap<>());
+ /** Cache mapping component types to entities having that component. */
+ private final Map<Class<? extends Component>, Set<Entity>> componentCache = Collections
+ .synchronizedMap(new HashMap<>());
- /** Deterministic ID's for spawned entities. */
- private final AtomicInteger nextEntityId = new AtomicInteger(0);
+ /** Deterministic ID's for spawned entities. */
+ private final AtomicInteger nextEntityId = new AtomicInteger(0);
- /** All registered systems. */
- protected final Map<Class<? extends System<T>>, System<T>> systems;
+ /** All registered systems. */
+ protected final Map<Class<? extends System<T>>, System<T>> systems;
- /** Ordered list of systems for execution. */
- private final List<System<T>> systemExecutionOrder;
+ /** Ordered list of systems for execution. */
+ private final List<System<T>> systemExecutionOrder;
- public DAGWorld(final Map<Class<? extends System<T>>, System<T>> systems) {
- this.systems = systems;
- this.systemExecutionOrder = buildExecutionOrder(systems.values().stream().toList());
- log.debug("Executing in order: {}", systemExecutionOrder);
- }
+ public DAGWorld(final Map<Class<? extends System<T>>, System<T>> systems) {
+ this.systems = systems;
+ this.systemExecutionOrder = buildExecutionOrder(systems.values().stream().toList());
+ log.debug("Executing in order: {}", systemExecutionOrder);
+ }
- @Override
- public Entity createEntity() {
- final Entity entity = Entity.builder().id(nextEntityId.incrementAndGet()).build();
- entities.add(entity);
- return entity;
- }
+ @Override
+ public Entity createEntity() {
+ final Entity entity = Entity.builder().id(nextEntityId.incrementAndGet()).build();
+ entities.add(entity);
+ return entity;
+ }
- @Override
- public void removeEntity(final Entity entity) {
- entity.getComponentMap().keySet().forEach(componentType -> {
- final Set<Entity> cachedEntities = componentCache.get(componentType);
- if (cachedEntities != null) {
- cachedEntities.remove(entity);
- }
- });
- entities.remove(entity);
- }
+ @Override
+ public void removeEntity(final Entity entity) {
+ entity.getComponentMap().keySet().forEach(componentType -> {
+ final Set<Entity> cachedEntities = componentCache.get(componentType);
+ if (cachedEntities != null) {
+ cachedEntities.remove(entity);
+ }
+ });
+ entities.remove(entity);
+ }
- @Override
- public Set<Entity> query(final Collection<Class<? extends Component>> components) {
- if (components.isEmpty()) {
- return Set.copyOf(entities);
- }
+ @Override
+ public Set<Entity> query(final Collection<Class<? extends Component>> components) {
+ if (components.isEmpty()) {
+ return Set.copyOf(entities);
+ }
- final Class<? extends Component> firstType = components.iterator().next();
- final Set<Entity> candidates = componentCache.get(firstType);
- if (candidates == null) {
- return Collections.emptySet();
- }
+ final Class<? extends Component> firstType = components.iterator().next();
+ final Set<Entity> candidates = componentCache.get(firstType);
+ if (candidates == null) {
+ return Collections.emptySet();
+ }
- return candidates.stream().filter(entity -> components.stream().allMatch(entity::has))
- .collect(Collectors.toSet());
- }
+ return candidates.stream().filter(entity -> components.stream().allMatch(entity::has))
+ .collect(Collectors.toSet());
+ }
- @Override
- public void update(final T state, final Duration duration) {
- systemExecutionOrder.forEach(system -> {
- refreshComponentCache();
- system.update(this, state, duration);
- });
- refreshComponentCache();
- }
+ @Override
+ public void update(final T state, final Duration duration) {
+ systemExecutionOrder.forEach(system -> {
+ refreshComponentCache();
+ system.update(this, state, duration);
+ });
+ refreshComponentCache();
+ }
- @SuppressWarnings("unchecked")
- @Override
- public <S extends System<T>> S getSystem(final Class<S> system) {
- return (S) systems.get(system);
- }
+ @SuppressWarnings("unchecked")
+ @Override
+ public <S extends System<T>> S getSystem(final Class<S> system) {
+ return (S) systems.get(system);
+ }
- private void refreshComponentCache() {
- componentCache.clear();
- entities.forEach(entity -> entity.getComponentMap().keySet().forEach(
- componentType -> componentCache.computeIfAbsent(componentType, _ -> new HashSet<>()).add(entity)));
- }
+ private void refreshComponentCache() {
+ componentCache.clear();
+ entities.forEach(entity -> entity.getComponentMap().keySet().forEach(
+ componentType -> componentCache.computeIfAbsent(componentType, _ -> new HashSet<>()).add(entity)));
+ }
- private List<System<T>> buildExecutionOrder(final Collection<System<T>> systems) {
- if (systems.isEmpty()) {
- return Collections.emptyList();
- }
+ private List<System<T>> buildExecutionOrder(final Collection<System<T>> systems) {
+ if (systems.isEmpty()) {
+ return Collections.emptyList();
+ }
- final Map<Class<?>, System<T>> systemMap = systems.stream()
- .collect(Collectors.toMap(System::getClass, system -> system));
- final Map<Class<?>, Integer> inDegree = new HashMap<>();
- final Map<Class<?>, Set<Class<?>>> adjacencyList = new HashMap<>();
+ final Map<Class<?>, System<T>> systemMap = systems.stream()
+ .collect(Collectors.toMap(System::getClass, system -> system));
+ final Map<Class<?>, Integer> inDegree = new HashMap<>();
+ final Map<Class<?>, Set<Class<?>>> adjacencyList = new HashMap<>();
- systems.forEach(system -> {
- final Class<?> systemClass = system.getClass();
- inDegree.put(systemClass, 0);
- adjacencyList.put(systemClass, new HashSet<>());
- });
+ systems.forEach(system -> {
+ final Class<?> systemClass = system.getClass();
+ inDegree.put(systemClass, 0);
+ adjacencyList.put(systemClass, new HashSet<>());
+ });
- systems.forEach(system -> {
- system.getDependencies().forEach(dependency -> {
- if (systemMap.containsKey(dependency)) {
- adjacencyList.get(dependency).add(system.getClass());
- inDegree.merge(system.getClass(), 1, Integer::sum);
- }
- });
- });
+ systems.forEach(system -> {
+ system.getDependencies().forEach(dependency -> {
+ if (systemMap.containsKey(dependency)) {
+ adjacencyList.get(dependency).add(system.getClass());
+ inDegree.merge(system.getClass(), 1, Integer::sum);
+ }
+ });
+ });
- // Kahn's algorithm
- final List<System<T>> result = new ArrayList<>();
+ // Kahn's algorithm
+ final List<System<T>> result = new ArrayList<>();
- final Queue<Class<?>> queue = new LinkedList<>(
- inDegree.entrySet().stream().filter(entry -> entry.getValue() == 0).map(Map.Entry::getKey).toList());
+ final Queue<Class<?>> queue = new LinkedList<>(
+ inDegree.entrySet().stream().filter(entry -> entry.getValue() == 0).map(Map.Entry::getKey).toList());
- while (!queue.isEmpty()) {
- final Class<?> currentClass = queue.poll();
- result.add(systemMap.get(currentClass));
+ while (!queue.isEmpty()) {
+ final Class<?> currentClass = queue.poll();
+ result.add(systemMap.get(currentClass));
- adjacencyList.getOrDefault(currentClass, Collections.emptySet()).forEach(dependent -> {
- final int newInDegree = inDegree.get(dependent) - 1;
- inDegree.put(dependent, newInDegree);
- if (newInDegree == 0) {
- queue.add(dependent);
- }
- });
- }
+ adjacencyList.getOrDefault(currentClass, Collections.emptySet()).forEach(dependent -> {
+ final int newInDegree = inDegree.get(dependent) - 1;
+ inDegree.put(dependent, newInDegree);
+ if (newInDegree == 0) {
+ queue.add(dependent);
+ }
+ });
+ }
- if (result.size() != systems.size()) {
- throw new IllegalStateException("Circular dependency detected in systems");
- }
+ if (result.size() != systems.size()) {
+ throw new IllegalStateException("Circular dependency detected in systems");
+ }
- return Collections.unmodifiableList(result);
- }
+ return Collections.unmodifiableList(result);
+ }
- @Override
- public void close() throws Exception {
- for (final System<T> system : systemExecutionOrder) {
- system.close();
- }
- componentCache.clear();
- entities.clear();
- }
+ @Override
+ public void close() throws Exception {
+ for (final System<T> system : systemExecutionOrder) {
+ system.close();
+ }
+ componentCache.clear();
+ entities.clear();
+ }
}
diff --git a/core/src/main/java/coffee/liz/ecs/math/Mat2.java b/core/src/main/java/coffee/liz/ecs/math/Mat2.java
index 9975227..ed9493c 100644
--- a/core/src/main/java/coffee/liz/ecs/math/Mat2.java
+++ b/core/src/main/java/coffee/liz/ecs/math/Mat2.java
@@ -7,82 +7,82 @@ import java.util.function.Function;
import java.util.function.Supplier;
public final class Mat2 {
- private Mat2() {
- }
+ private Mat2() {
+ }
- /**
- * Initializes a mutable 2d matrix of given type.
- *
- * @param dimensions
- * the dimensions
- * @param constructor
- * the constructor
- * @return row-indexed 2d matrix of {@param dimensions}
- */
- public static <T> List<List<T>> init(final Vec2<Integer> dimensions, final Function<Vec2<Integer>, T> constructor) {
- final List<List<T>> rows = new ArrayList<>();
- for (int y = 0; y < dimensions.getY(); y++) {
- final List<T> row = new ArrayList<>(dimensions.getX());
- for (int x = 0; x < dimensions.getX(); x++)
- row.add(constructor.apply(Vec2i.builder().y(y).x(x).build()));
- rows.add(row);
- }
- return rows;
- }
+ /**
+ * Initializes a mutable 2d matrix of given type.
+ *
+ * @param dimensions
+ * the dimensions
+ * @param constructor
+ * the constructor
+ * @return row-indexed 2d matrix of {@param dimensions}
+ */
+ public static <T> List<List<T>> init(final Vec2<Integer> dimensions, final Function<Vec2<Integer>, T> constructor) {
+ final List<List<T>> rows = new ArrayList<>();
+ for (int y = 0; y < dimensions.getY(); y++) {
+ final List<T> row = new ArrayList<>(dimensions.getX());
+ for (int x = 0; x < dimensions.getX(); x++)
+ row.add(constructor.apply(Vec2i.builder().y(y).x(x).build()));
+ rows.add(row);
+ }
+ return rows;
+ }
- /**
- * Convolves a {@link Convolver} across a matrix reaching neighbors around the
- * grid like a torus.
- *
- * @param mat
- * is the row-indexed 2d matrix to convolve.
- * @param axes
- * are the x/y major/minor axes.
- * @param init
- * is the initial value of the convolution.
- * @param convolver
- * is the {@link Convolver}.
- * @param finalReduction
- * to apply after {@param convolver}.
- * @return result of {@param convolver} applied along axes at each cell.
- * @param <T>
- * is the type of the matrix to convolve.
- * @param <R>
- * is the type of the resulting type of each convolution.
- */
- public static <T, R, U> List<List<U>> convolveTorus(final List<List<T>> mat, final Vec2<Integer> axes,
- final Supplier<R> init, final Convolver<T, R> convolver, final BiFunction<T, R, U> finalReduction) {
- final List<List<R>> rows = new ArrayList<>();
- for (int y = 0; y < mat.size(); y++) {
- final List<R> row = new ArrayList<>(mat.get(y).size());
- for (int x = 0; x < mat.get(y).size(); x++) {
- final T center = mat.get(y).get(x);
- R result = init.get();
- for (int dy = -axes.getY(); dy <= axes.getY(); dy++) {
- final int ry = Math.floorMod(y + dy, mat.size());
- for (int dx = -axes.getX(); dx <= axes.getX(); dx++) {
- final int rx = Math.floorMod(x + dx, mat.get(ry).size());
- result = convolver.convolve(mat.get(ry).get(rx), Vec2i.builder().x(dx).y(dy).build(), result);
- }
- }
- row.add(result);
- }
- rows.add(row);
- }
+ /**
+ * Convolves a {@link Convolver} across a matrix reaching neighbors around the
+ * grid like a torus.
+ *
+ * @param mat
+ * is the row-indexed 2d matrix to convolve.
+ * @param axes
+ * are the x/y major/minor axes.
+ * @param init
+ * is the initial value of the convolution.
+ * @param convolver
+ * is the {@link Convolver}.
+ * @param finalReduction
+ * to apply after {@param convolver}.
+ * @return result of {@param convolver} applied along axes at each cell.
+ * @param <T>
+ * is the type of the matrix to convolve.
+ * @param <R>
+ * is the type of the resulting type of each convolution.
+ */
+ public static <T, R, U> List<List<U>> convolveTorus(final List<List<T>> mat, final Vec2<Integer> axes,
+ final Supplier<R> init, final Convolver<T, R> convolver, final BiFunction<T, R, U> finalReduction) {
+ final List<List<R>> rows = new ArrayList<>();
+ for (int y = 0; y < mat.size(); y++) {
+ final List<R> row = new ArrayList<>(mat.get(y).size());
+ for (int x = 0; x < mat.get(y).size(); x++) {
+ final T center = mat.get(y).get(x);
+ R result = init.get();
+ for (int dy = -axes.getY(); dy <= axes.getY(); dy++) {
+ final int ry = Math.floorMod(y + dy, mat.size());
+ for (int dx = -axes.getX(); dx <= axes.getX(); dx++) {
+ final int rx = Math.floorMod(x + dx, mat.get(ry).size());
+ result = convolver.convolve(mat.get(ry).get(rx), Vec2i.builder().x(dx).y(dy).build(), result);
+ }
+ }
+ row.add(result);
+ }
+ rows.add(row);
+ }
- final List<List<U>> reductions = new ArrayList<>();
- for (int y = 0; y < mat.size(); y++) {
- final List<U> reduction = new ArrayList<>(mat.get(y).size());
- for (int x = 0; x < mat.get(y).size(); x++) {
- reduction.add(finalReduction.apply(mat.get(y).get(x), rows.get(y).get(x)));
- }
- reductions.add(reduction);
- }
- return reductions;
- }
+ final List<List<U>> reductions = new ArrayList<>();
+ for (int y = 0; y < mat.size(); y++) {
+ final List<U> reduction = new ArrayList<>(mat.get(y).size());
+ for (int x = 0; x < mat.get(y).size(); x++) {
+ reduction.add(finalReduction.apply(mat.get(y).get(x), rows.get(y).get(x)));
+ }
+ reductions.add(reduction);
+ }
+ return reductions;
+ }
- @FunctionalInterface
- public interface Convolver<T, R> {
- R convolve(final T center, final Vec2<Integer> rel, final R reduction);
- }
+ @FunctionalInterface
+ public interface Convolver<T, R> {
+ R convolve(final T center, final Vec2<Integer> rel, final R reduction);
+ }
}
diff --git a/core/src/main/java/coffee/liz/ecs/math/Vec2.java b/core/src/main/java/coffee/liz/ecs/math/Vec2.java
index 7620395..dde6e51 100644
--- a/core/src/main/java/coffee/liz/ecs/math/Vec2.java
+++ b/core/src/main/java/coffee/liz/ecs/math/Vec2.java
@@ -9,80 +9,80 @@ import java.util.function.Function;
* the numeric type of vector components
*/
public interface Vec2<T> {
- /**
- * @return the x coordinate
- */
- T getX();
+ /**
+ * @return the x coordinate
+ */
+ T getX();
- /**
- * @return the y coordinate
- */
- T getY();
+ /**
+ * @return the y coordinate
+ */
+ T getY();
- /**
- * Adds another vector to this vector.
- *
- * @param other
- * the vector to add
- * @return a new vector with the result
- */
- Vec2<T> plus(final Vec2<T> other);
+ /**
+ * Adds another vector to this vector.
+ *
+ * @param other
+ * the vector to add
+ * @return a new vector with the result
+ */
+ Vec2<T> plus(final Vec2<T> other);
- /**
- * Subtracts another vector from this vector.
- *
- * @param other
- * the vector to subtract
- * @return a new vector with the result
- */
- Vec2<T> minus(final Vec2<T> other);
+ /**
+ * Subtracts another vector from this vector.
+ *
+ * @param other
+ * the vector to subtract
+ * @return a new vector with the result
+ */
+ Vec2<T> minus(final Vec2<T> other);
- /**
- * Scales this vector by the given factors.
- *
- * @param scaleX
- * the x scale factor
- * @param scaleY
- * the y scale factor
- * @return a new scaled vector
- */
- Vec2<T> scale(final T scaleX, final T scaleY);
+ /**
+ * Scales this vector by the given factors.
+ *
+ * @param scaleX
+ * the x scale factor
+ * @param scaleY
+ * the y scale factor
+ * @return a new scaled vector
+ */
+ Vec2<T> scale(final T scaleX, final T scaleY);
- /**
- * Scales this vector by the given vector.
- *
- * @param scale
- * scale vec.
- * @return a new scaled vector
- */
- default Vec2<T> scale(final Vec2<T> scale) {
- return scale(scale.getX(), scale.getY());
- }
+ /**
+ * Scales this vector by the given vector.
+ *
+ * @param scale
+ * scale vec.
+ * @return a new scaled vector
+ */
+ default Vec2<T> scale(final Vec2<T> scale) {
+ return scale(scale.getX(), scale.getY());
+ }
- /**
- * Length of the vector.
- *
- * @return length.
- */
- float length();
+ /**
+ * Length of the vector.
+ *
+ * @return length.
+ */
+ float length();
- /**
- * @return Vec2<Integer> components of {@link Vec2<T>}
- */
- Vec2<Integer> intValue();
+ /**
+ * @return Vec2<Integer> components of {@link Vec2<T>}
+ */
+ Vec2<Integer> intValue();
- /**
- * @return Vec2<Float> components of {@link Vec2<T>}
- */
- Vec2<Float> floatValue();
+ /**
+ * @return Vec2<Float> components of {@link Vec2<T>}
+ */
+ Vec2<Float> floatValue();
- /**
- * @param xTransform
- * transform of x component.
- * @param yTransform
- * transform of y component.
- * @return transformed vec applying {@param xTransform} to x component,
- * {@param yTransform} to y component.
- */
- Vec2<T> transform(final Function<T, T> xTransform, final Function<T, T> yTransform);
+ /**
+ * @param xTransform
+ * transform of x component.
+ * @param yTransform
+ * transform of y component.
+ * @return transformed vec applying {@param xTransform} to x component,
+ * {@param yTransform} to y component.
+ */
+ Vec2<T> transform(final Function<T, T> xTransform, final Function<T, T> yTransform);
}
diff --git a/core/src/main/java/coffee/liz/ecs/math/Vec2f.java b/core/src/main/java/coffee/liz/ecs/math/Vec2f.java
index 5b91a2d..42b73e7 100644
--- a/core/src/main/java/coffee/liz/ecs/math/Vec2f.java
+++ b/core/src/main/java/coffee/liz/ecs/math/Vec2f.java
@@ -15,47 +15,47 @@ import java.util.function.Function;
@Data
@Builder
public final class Vec2f implements Vec2<Float> {
- /** X coordinate. */
- private final Float x;
+ /** X coordinate. */
+ private final Float x;
- /** Y coordinate. */
- private final Float y;
+ /** Y coordinate. */
+ private final Float y;
- @Override
- public Vec2<Float> plus(final Vec2<Float> other) {
- return new Vec2f(x + other.getX(), y + other.getY());
- }
+ @Override
+ public Vec2<Float> plus(final Vec2<Float> other) {
+ return new Vec2f(x + other.getX(), y + other.getY());
+ }
- @Override
- public Vec2<Float> minus(final Vec2<Float> other) {
- return new Vec2f(x - other.getX(), y - other.getY());
- }
+ @Override
+ public Vec2<Float> minus(final Vec2<Float> other) {
+ return new Vec2f(x - other.getX(), y - other.getY());
+ }
- @Override
- public Vec2<Float> scale(final Float scaleX, final Float scaleY) {
- return new Vec2f(x * scaleX, y * scaleY);
- }
+ @Override
+ public Vec2<Float> scale(final Float scaleX, final Float scaleY) {
+ return new Vec2f(x * scaleX, y * scaleY);
+ }
- @Override
- public float length() {
- return (float) sqrt(x * x + y * y);
- }
+ @Override
+ public float length() {
+ return (float) sqrt(x * x + y * y);
+ }
- @Override
- public Vec2<Float> floatValue() {
- return this;
- }
+ @Override
+ public Vec2<Float> floatValue() {
+ return this;
+ }
- @Override
- public Vec2<Float> transform(final Function<Float, Float> xTransform, final Function<Float, Float> yTransform) {
- return new Vec2f(xTransform.apply(getX()), yTransform.apply(getY()));
- }
+ @Override
+ public Vec2<Float> transform(final Function<Float, Float> xTransform, final Function<Float, Float> yTransform) {
+ return new Vec2f(xTransform.apply(getX()), yTransform.apply(getY()));
+ }
- @Override
- public Vec2<Integer> intValue() {
- return Vec2i.builder().x(this.x.intValue()).y(this.y.intValue()).build();
- }
+ @Override
+ public Vec2<Integer> intValue() {
+ return Vec2i.builder().x(this.x.intValue()).y(this.y.intValue()).build();
+ }
- /** Zero float vec */
- public static Vec2<Float> ZERO = Vec2f.builder().x(0f).y(0f).build();
+ /** Zero float vec */
+ public static Vec2<Float> ZERO = Vec2f.builder().x(0f).y(0f).build();
}
diff --git a/core/src/main/java/coffee/liz/ecs/math/Vec2i.java b/core/src/main/java/coffee/liz/ecs/math/Vec2i.java
index b07e481..326a5df 100644
--- a/core/src/main/java/coffee/liz/ecs/math/Vec2i.java
+++ b/core/src/main/java/coffee/liz/ecs/math/Vec2i.java
@@ -15,51 +15,51 @@ import java.util.function.Function;
@Builder
@Data
public final class Vec2i implements Vec2<Integer> {
- /** X coordinate. */
- private final Integer x;
+ /** X coordinate. */
+ private final Integer x;
- /** Y coordinate. */
- private final Integer y;
+ /** Y coordinate. */
+ private final Integer y;
- @Override
- public Vec2<Integer> plus(final Vec2<Integer> other) {
- return new Vec2i(x + other.getX(), y + other.getY());
- }
+ @Override
+ public Vec2<Integer> plus(final Vec2<Integer> other) {
+ return new Vec2i(x + other.getX(), y + other.getY());
+ }
- @Override
- public Vec2<Integer> minus(final Vec2<Integer> other) {
- return new Vec2i(x - other.getX(), y - other.getY());
- }
+ @Override
+ public Vec2<Integer> minus(final Vec2<Integer> other) {
+ return new Vec2i(x - other.getX(), y - other.getY());
+ }
- @Override
- public Vec2<Integer> scale(final Integer scaleX, final Integer scaleY) {
- return new Vec2i(x * scaleX, y * scaleY);
- }
+ @Override
+ public Vec2<Integer> scale(final Integer scaleX, final Integer scaleY) {
+ return new Vec2i(x * scaleX, y * scaleY);
+ }
- @Override
- public Vec2<Float> floatValue() {
- return Vec2f.builder().x(this.x.floatValue()).y(this.y.floatValue()).build();
- }
+ @Override
+ public Vec2<Float> floatValue() {
+ return Vec2f.builder().x(this.x.floatValue()).y(this.y.floatValue()).build();
+ }
- @Override
- public Vec2<Integer> transform(final Function<Integer, Integer> xTransform,
- final Function<Integer, Integer> yTransform) {
- return new Vec2i(xTransform.apply(getX()), yTransform.apply(getY()));
- }
+ @Override
+ public Vec2<Integer> transform(final Function<Integer, Integer> xTransform,
+ final Function<Integer, Integer> yTransform) {
+ return new Vec2i(xTransform.apply(getX()), yTransform.apply(getY()));
+ }
- @Override
- public Vec2<Integer> intValue() {
- return this;
- }
+ @Override
+ public Vec2<Integer> intValue() {
+ return this;
+ }
- @Override
- public float length() {
- return (float) sqrt(x * x + y * y);
- }
+ @Override
+ public float length() {
+ return (float) sqrt(x * x + y * y);
+ }
- public static final Vec2<Integer> NORTH = new Vec2i(0, 1);
- public static final Vec2<Integer> SOUTH = new Vec2i(0, -1);
- public static final Vec2<Integer> EAST = new Vec2i(1, 0);
- public static final Vec2<Integer> WEST = new Vec2i(-1, 0);
- public static final Vec2<Integer> ZERO = new Vec2i(0, 0);
+ public static final Vec2<Integer> NORTH = new Vec2i(0, 1);
+ public static final Vec2<Integer> SOUTH = new Vec2i(0, -1);
+ public static final Vec2<Integer> EAST = new Vec2i(1, 0);
+ public static final Vec2<Integer> WEST = new Vec2i(-1, 0);
+ public static final Vec2<Integer> ZERO = new Vec2i(0, 0);
}
diff --git a/core/src/main/java/coffee/liz/ecs/model/Component.java b/core/src/main/java/coffee/liz/ecs/model/Component.java
index f96ba95..2d3a8e7 100644
--- a/core/src/main/java/coffee/liz/ecs/model/Component.java
+++ b/core/src/main/java/coffee/liz/ecs/model/Component.java
@@ -2,7 +2,7 @@ package coffee.liz.ecs.model;
/** Component of an {@link Entity}. */
public interface Component {
- default Class<? extends Component> getKey() {
- return getClass();
- }
+ default Class<? extends Component> getKey() {
+ return getClass();
+ }
}
diff --git a/core/src/main/java/coffee/liz/ecs/model/Entity.java b/core/src/main/java/coffee/liz/ecs/model/Entity.java
index e820e57..7dab667 100644
--- a/core/src/main/java/coffee/liz/ecs/model/Entity.java
+++ b/core/src/main/java/coffee/liz/ecs/model/Entity.java
@@ -18,88 +18,88 @@ import java.util.Set;
@AllArgsConstructor
@Data
public class Entity {
- /** Unique id. */
- private final int id;
+ /** Unique id. */
+ private final int id;
- /** Instances of {@link Component}s. */
- @Builder.Default
- private Map<Class<? extends Component>, Component> componentMap = Collections.synchronizedMap(new HashMap<>());
+ /** Instances of {@link Component}s. */
+ @Builder.Default
+ private Map<Class<? extends Component>, Component> componentMap = Collections.synchronizedMap(new HashMap<>());
- /**
- * Check if entity has component type.
- *
- * @param componentType
- * the {@link Component} class
- * @return true if component exists
- */
- public boolean has(final Class<? extends Component> componentType) {
- return componentMap.containsKey(componentType);
- }
+ /**
+ * Check if entity has component type.
+ *
+ * @param componentType
+ * the {@link Component} class
+ * @return true if component exists
+ */
+ public boolean has(final Class<? extends Component> componentType) {
+ return componentMap.containsKey(componentType);
+ }
- /**
- * Check if entity has all component types.
- *
- * @param components
- * collection of {@link Component} classes
- * @return true if all components exist
- */
- public boolean hasAll(final Collection<Class<? extends Component>> components) {
- return components.stream().allMatch(this::has);
- }
+ /**
+ * Check if entity has all component types.
+ *
+ * @param components
+ * collection of {@link Component} classes
+ * @return true if all components exist
+ */
+ public boolean hasAll(final Collection<Class<? extends Component>> components) {
+ return components.stream().allMatch(this::has);
+ }
- /**
- * Get component by type.
- *
- * @param componentType
- * the {@link Component} class
- * @param <C>
- * component type
- * @return the component or throw {@link IllegalArgumentException}
- */
- @SuppressWarnings("unchecked")
- public <C extends Component> C get(final Class<C> componentType) {
- final C component = (C) componentMap.get(componentType);
- if (component == null) {
- throw new IllegalArgumentException(
- "Entity with id " + getId() + " does not have required component " + componentType.getSimpleName());
- }
- return component;
- }
+ /**
+ * Get component by type.
+ *
+ * @param componentType
+ * the {@link Component} class
+ * @param <C>
+ * component type
+ * @return the component or throw {@link IllegalArgumentException}
+ */
+ @SuppressWarnings("unchecked")
+ public <C extends Component> C get(final Class<C> componentType) {
+ final C component = (C) componentMap.get(componentType);
+ if (component == null) {
+ throw new IllegalArgumentException(
+ "Entity with id " + getId() + " does not have required component " + componentType.getSimpleName());
+ }
+ return component;
+ }
- /**
- * Add component to entity.
- *
- * @param component
- * the {@link Component} to add
- * @param <C>
- * component type
- * @return this {@link Entity} for chaining
- */
- public <C extends Component> Entity add(final C component) {
- componentMap.put(component.getKey(), component);
- return this;
- }
+ /**
+ * Add component to entity.
+ *
+ * @param component
+ * the {@link Component} to add
+ * @param <C>
+ * component type
+ * @return this {@link Entity} for chaining
+ */
+ public <C extends Component> Entity add(final C component) {
+ componentMap.put(component.getKey(), component);
+ return this;
+ }
- /**
- * Remove component from entity.
- *
- * @param componentType
- * the {@link Component} class to remove
- * @param <C>
- * component type
- * @return this {@link Entity} for chaining
- */
- public <C extends Component> Entity remove(final Class<C> componentType) {
- componentMap.remove(componentType);
- return this;
- }
+ /**
+ * Remove component from entity.
+ *
+ * @param componentType
+ * the {@link Component} class to remove
+ * @param <C>
+ * component type
+ * @return this {@link Entity} for chaining
+ */
+ public <C extends Component> Entity remove(final Class<C> componentType) {
+ componentMap.remove(componentType);
+ return this;
+ }
- /**
- * Get all component types.
- *
- * @return set of {@link Component} classes
- */
- public Set<Class<? extends Component>> componentTypes() {
- return componentMap.keySet();
- }
+ /**
+ * Get all component types.
+ *
+ * @return set of {@link Component} classes
+ */
+ public Set<Class<? extends Component>> componentTypes() {
+ return componentMap.keySet();
+ }
}
diff --git a/core/src/main/java/coffee/liz/ecs/model/System.java b/core/src/main/java/coffee/liz/ecs/model/System.java
index ac99818..c4b0bc0 100644
--- a/core/src/main/java/coffee/liz/ecs/model/System.java
+++ b/core/src/main/java/coffee/liz/ecs/model/System.java
@@ -10,24 +10,24 @@ import java.util.Collection;
* is the state of the stuff outside the {@link World}.
*/
public interface System<T> extends AutoCloseable {
- /**
- * {@link System} clazzes that must run before this system.
- *
- * @return {@link Collection} of dependencies.
- */
- Collection<Class<? extends System<T>>> getDependencies();
+ /**
+ * {@link System} clazzes that must run before this system.
+ *
+ * @return {@link Collection} of dependencies.
+ */
+ Collection<Class<? extends System<T>>> getDependencies();
- /**
- * @param world
- * Is the {@link World}.
- * @param state
- * Is the {@link T} state outside the {@param world}.
- * @param dt
- * Is the timestep.
- */
- void update(final World<T> world, final T state, final Duration dt);
+ /**
+ * @param world
+ * Is the {@link World}.
+ * @param state
+ * Is the {@link T} state outside the {@param world}.
+ * @param dt
+ * Is the timestep.
+ */
+ void update(final World<T> world, final T state, final Duration dt);
- @Override
- default void close() {
- }
+ @Override
+ default void close() {
+ }
}
diff --git a/core/src/main/java/coffee/liz/ecs/model/World.java b/core/src/main/java/coffee/liz/ecs/model/World.java
index 05363e8..c59a0d7 100644
--- a/core/src/main/java/coffee/liz/ecs/model/World.java
+++ b/core/src/main/java/coffee/liz/ecs/model/World.java
@@ -11,48 +11,48 @@ import java.util.Set;
* is the state of the stuff outside the world.
*/
public interface World<T> extends AutoCloseable {
- /**
- * Create unique {@link Entity} in the {@link World}.
- *
- * @return created {@link Entity}.
- */
- Entity createEntity();
+ /**
+ * Create unique {@link Entity} in the {@link World}.
+ *
+ * @return created {@link Entity}.
+ */
+ Entity createEntity();
- /**
- * Remove an entity from the {@link World}.
- *
- * @param entity
- * to remove.
- */
- void removeEntity(final Entity entity);
+ /**
+ * Remove an entity from the {@link World}.
+ *
+ * @param entity
+ * to remove.
+ */
+ void removeEntity(final Entity entity);
- /**
- * Get entities with {@link Component}s.
- *
- * @param components
- * to query for.
- * @return All entities with all {@param components}.
- */
- Set<Entity> query(final Collection<Class<? extends Component>> components);
+ /**
+ * Get entities with {@link Component}s.
+ *
+ * @param components
+ * to query for.
+ * @return All entities with all {@param components}.
+ */
+ Set<Entity> query(final Collection<Class<? extends Component>> components);
- /**
- * Integrate the {@link World}.
- *
- * @param state
- * Is the state outside the world.
- * @param duration
- * Is the time step.
- */
- void update(final T state, final Duration duration);
+ /**
+ * Integrate the {@link World}.
+ *
+ * @param state
+ * Is the state outside the world.
+ * @param duration
+ * Is the time step.
+ */
+ void update(final T state, final Duration duration);
- /**
- * Get world {@link System}.
- *
- * @param system
- * is the Clazz.
- * @param <S>
- * is the {@link System} type.
- * @return {@link System} instance of {@param system}.
- */
- <S extends System<T>> S getSystem(final Class<S> system);
+ /**
+ * Get world {@link System}.
+ *
+ * @param system
+ * is the Clazz.
+ * @param <S>
+ * is the {@link System} type.
+ * @return {@link System} instance of {@param system}.
+ */
+ <S extends System<T>> S getSystem(final Class<S> system);
}
diff --git a/core/src/main/java/coffee/liz/lambda/LambdaDriver.java b/core/src/main/java/coffee/liz/lambda/LambdaDriver.java
index 2ba8c70..59cee25 100644
--- a/core/src/main/java/coffee/liz/lambda/LambdaDriver.java
+++ b/core/src/main/java/coffee/liz/lambda/LambdaDriver.java
@@ -20,60 +20,60 @@ import java.util.List;
*/
public class LambdaDriver {
- /**
- * Parses source code into an AST.
- *
- * @param sourceCode
- * the source code (either Lambda or Arrow syntax)
- * @return the parsed program
- */
- public static LambdaProgram parse(final SourceCode sourceCode) {
- return switch (sourceCode) {
- case SourceCode.Lambda(String source) -> parseLambda(source);
- case SourceCode.Arrow(String source) -> parseArrow(source);
- };
- }
+ /**
+ * Parses source code into an AST.
+ *
+ * @param sourceCode
+ * the source code (either Lambda or Arrow syntax)
+ * @return the parsed program
+ */
+ public static LambdaProgram parse(final SourceCode sourceCode) {
+ return switch (sourceCode) {
+ case SourceCode.Lambda(String source) -> parseLambda(source);
+ case SourceCode.Arrow(String source) -> parseArrow(source);
+ };
+ }
- private static LambdaProgram parseLambda(final String source) {
- try (final StringReader reader = new StringReader(source)) {
- return new LambdaParser(reader).Program();
- } catch (final ParseException parseException) {
- throw new RuntimeException("Failed to parse program", parseException);
- }
- }
+ private static LambdaProgram parseLambda(final String source) {
+ try (final StringReader reader = new StringReader(source)) {
+ return new LambdaParser(reader).Program();
+ } catch (final ParseException parseException) {
+ throw new RuntimeException("Failed to parse program", parseException);
+ }
+ }
- private static LambdaProgram parseArrow(final String source) {
- try (final StringReader reader = new StringReader(source)) {
- return new ArrowParser(reader).Program();
- } catch (final ParseException parseException) {
- throw new RuntimeException("Failed to parse program", parseException);
- }
- }
+ private static LambdaProgram parseArrow(final String source) {
+ try (final StringReader reader = new StringReader(source)) {
+ return new ArrowParser(reader).Program();
+ } catch (final ParseException parseException) {
+ throw new RuntimeException("Failed to parse program", parseException);
+ }
+ }
- /**
- * Parses and evaluates lambda calculus programs.
- *
- * @param sourceCode
- * the source code
- * @return the evaluated result
- */
- public static Value interpret(final SourceCode sourceCode) {
- return interpret(sourceCode, List.of());
- }
+ /**
+ * Parses and evaluates lambda calculus programs.
+ *
+ * @param sourceCode
+ * the source code
+ * @return the evaluated result
+ */
+ public static Value interpret(final SourceCode sourceCode) {
+ return interpret(sourceCode, List.of());
+ }
- /**
- * Parses and evaluates lambda calculus programs with "FFI"'s.
- *
- * @param sourceCode
- * the source code
- * @param bindings
- * external Java functions available during evaluation
- * @return the evaluated result
- */
- public static Value interpret(final SourceCode sourceCode, final List<ExternalBinding> bindings) {
- final LambdaProgram program = parse(sourceCode);
- final Expression expression = program.expression();
- final List<Macro> macros = program.macros();
- return NormalOrderEvaluator.evaluate(expression, Environment.from(macros, bindings));
- }
+ /**
+ * Parses and evaluates lambda calculus programs with "FFI"'s.
+ *
+ * @param sourceCode
+ * the source code
+ * @param bindings
+ * external Java functions available during evaluation
+ * @return the evaluated result
+ */
+ public static Value interpret(final SourceCode sourceCode, final List<ExternalBinding> bindings) {
+ final LambdaProgram program = parse(sourceCode);
+ final Expression expression = program.expression();
+ final List<Macro> macros = program.macros();
+ return NormalOrderEvaluator.evaluate(expression, Environment.from(macros, bindings));
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/ast/Expression.java b/core/src/main/java/coffee/liz/lambda/ast/Expression.java
index 6d75a08..c2bdd39 100644
--- a/core/src/main/java/coffee/liz/lambda/ast/Expression.java
+++ b/core/src/main/java/coffee/liz/lambda/ast/Expression.java
@@ -8,21 +8,21 @@ import java.util.Optional;
* Represents an expression in the untyped lambda calculus.
*/
public sealed interface Expression
- permits Expression.AbstractionExpression, Expression.IdentifierExpression, Expression.ApplicationExpression {
+ permits Expression.AbstractionExpression, Expression.IdentifierExpression, Expression.ApplicationExpression {
- Optional<SourceComment> comment();
+ Optional<SourceComment> comment();
- SourceSpan span();
+ SourceSpan span();
- record AbstractionExpression(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span,
- @NonNull String parameter, @NonNull Expression body) implements Expression {
- }
+ record AbstractionExpression(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span,
+ @NonNull String parameter, @NonNull Expression body) implements Expression {
+ }
- record ApplicationExpression(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span,
- @NonNull Expression applicable, @NonNull Expression argument) implements Expression {
- }
+ record ApplicationExpression(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span,
+ @NonNull Expression applicable, @NonNull Expression argument) implements Expression {
+ }
- record IdentifierExpression(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span,
- @NonNull String name) implements Expression {
- }
+ record IdentifierExpression(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span,
+ @NonNull String name) implements Expression {
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/ast/Macro.java b/core/src/main/java/coffee/liz/lambda/ast/Macro.java
index 07ba911..4a485fc 100644
--- a/core/src/main/java/coffee/liz/lambda/ast/Macro.java
+++ b/core/src/main/java/coffee/liz/lambda/ast/Macro.java
@@ -8,5 +8,5 @@ import java.util.Optional;
* A named macro definition that maps an identifier to an expression.
*/
public record Macro(@NonNull Optional<SourceComment> comment, @NonNull SourceSpan span, @NonNull String name,
- @NonNull Expression expression) {
+ @NonNull Expression expression) {
}
diff --git a/core/src/main/java/coffee/liz/lambda/ast/SourceCode.java b/core/src/main/java/coffee/liz/lambda/ast/SourceCode.java
index 200c45e..c2112ad 100644
--- a/core/src/main/java/coffee/liz/lambda/ast/SourceCode.java
+++ b/core/src/main/java/coffee/liz/lambda/ast/SourceCode.java
@@ -4,24 +4,24 @@ package coffee.liz.lambda.ast;
* Represents source code in one of the supported lambda calculus syntaxes.
*/
public sealed interface SourceCode {
- static SourceCode ofLambda(final String source) {
- return new Lambda(source);
- }
+ static SourceCode ofLambda(final String source) {
+ return new Lambda(source);
+ }
- static SourceCode ofArrow(final String source) {
- return new Arrow(source);
- }
+ static SourceCode ofArrow(final String source) {
+ return new Arrow(source);
+ }
- record Lambda(String source) implements SourceCode {
- }
+ record Lambda(String source) implements SourceCode {
+ }
- record Arrow(String source) implements SourceCode {
- }
+ record Arrow(String source) implements SourceCode {
+ }
- /**
- * Supported syntax types for {@link SourceCode}.
- */
- enum Syntax {
- LAMBDA, ARROW
- }
+ /**
+ * Supported syntax types for {@link SourceCode}.
+ */
+ enum Syntax {
+ LAMBDA, ARROW
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/ast/SourceComment.java b/core/src/main/java/coffee/liz/lambda/ast/SourceComment.java
index da6b5ab..8e50f5f 100644
--- a/core/src/main/java/coffee/liz/lambda/ast/SourceComment.java
+++ b/core/src/main/java/coffee/liz/lambda/ast/SourceComment.java
@@ -12,10 +12,10 @@ import lombok.NonNull;
*/
public record SourceComment(@NonNull String text, @NonNull SourceSpan span) {
- /**
- * Returns true if this comment is on the same line as the given span's end.
- */
- public boolean isInlineAfter(final SourceSpan previous) {
- return previous != null && previous.endLine() == this.span.startLine();
- }
+ /**
+ * Returns true if this comment is on the same line as the given span's end.
+ */
+ public boolean isInlineAfter(final SourceSpan previous) {
+ return previous != null && previous.endLine() == this.span.startLine();
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/ast/SourceSpan.java b/core/src/main/java/coffee/liz/lambda/ast/SourceSpan.java
index 7df9bcd..80e06f9 100644
--- a/core/src/main/java/coffee/liz/lambda/ast/SourceSpan.java
+++ b/core/src/main/java/coffee/liz/lambda/ast/SourceSpan.java
@@ -13,12 +13,12 @@ package coffee.liz.lambda.ast;
* 1-based column number where the span ends
*/
public record SourceSpan(int startLine, int startColumn, int endLine, int endColumn) {
- public static final SourceSpan UNKNOWN = new SourceSpan(0, 0, 0, 0);
+ public static final SourceSpan UNKNOWN = new SourceSpan(0, 0, 0, 0);
- /**
- * Returns true if this span ends on the same line that the other span starts.
- */
- public boolean isOnSameLine(final SourceSpan other) {
- return this.endLine == other.startLine;
- }
+ /**
+ * Returns true if this span ends on the same line that the other span starts.
+ */
+ public boolean isOnSameLine(final SourceSpan other) {
+ return this.endLine == other.startLine;
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/bind/ExternalBinding.java b/core/src/main/java/coffee/liz/lambda/bind/ExternalBinding.java
index 4895972..7a8ae40 100644
--- a/core/src/main/java/coffee/liz/lambda/bind/ExternalBinding.java
+++ b/core/src/main/java/coffee/liz/lambda/bind/ExternalBinding.java
@@ -14,10 +14,10 @@ import java.util.function.BiFunction;
*/
public interface ExternalBinding extends BiFunction<Environment, Value, Value> {
- /**
- * Returns the name used to reference this binding in environment.
- *
- * @return the binding name
- */
- String getName();
+ /**
+ * Returns the name used to reference this binding in environment.
+ *
+ * @return the binding name
+ */
+ String getName();
}
diff --git a/core/src/main/java/coffee/liz/lambda/bind/Tick.java b/core/src/main/java/coffee/liz/lambda/bind/Tick.java
index 0fa4de5..c4ad8ee 100644
--- a/core/src/main/java/coffee/liz/lambda/bind/Tick.java
+++ b/core/src/main/java/coffee/liz/lambda/bind/Tick.java
@@ -11,12 +11,12 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
@Getter
public class Tick implements ExternalBinding {
- private final String name = "Tick";
- private final AtomicInteger counter = new AtomicInteger(0);
+ private final String name = "Tick";
+ private final AtomicInteger counter = new AtomicInteger(0);
- @Override
- public Value apply(final Environment environment, final Value value) {
- counter.incrementAndGet();
- return value;
- }
+ @Override
+ public Value apply(final Environment environment, final Value value) {
+ counter.incrementAndGet();
+ return value;
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/bind/ToChurch.java b/core/src/main/java/coffee/liz/lambda/bind/ToChurch.java
index bfddd86..315622a 100644
--- a/core/src/main/java/coffee/liz/lambda/bind/ToChurch.java
+++ b/core/src/main/java/coffee/liz/lambda/bind/ToChurch.java
@@ -22,28 +22,28 @@ import lombok.Getter;
*/
@Getter
public class ToChurch implements ExternalBinding {
- private final String name = "ToChurch";
+ private final String name = "ToChurch";
- /**
- * Converts a free variable containing an integer string to a Church numeral.
- *
- * @param env
- * the current environment
- * @param val
- * a Free value whose name is an integer string
- * @return a Closure representing the Church numeral
- */
- @Override
- public Value apply(final Environment env, final Value val) {
- final Free free = (Free) val;
- final int n = Integer.parseInt(free.name());
+ /**
+ * Converts a free variable containing an integer string to a Church numeral.
+ *
+ * @param env
+ * the current environment
+ * @param val
+ * a Free value whose name is an integer string
+ * @return a Closure representing the Church numeral
+ */
+ @Override
+ public Value apply(final Environment env, final Value val) {
+ final Free free = (Free) val;
+ final int n = Integer.parseInt(free.name());
- Expression body = new IdentifierExpression(Optional.empty(), SourceSpan.UNKNOWN, "x");
- for (int i = 0; i < n; i++) {
- body = new ApplicationExpression(Optional.empty(), SourceSpan.UNKNOWN,
- new IdentifierExpression(Optional.empty(), SourceSpan.UNKNOWN, "f"), body);
- }
+ Expression body = new IdentifierExpression(Optional.empty(), SourceSpan.UNKNOWN, "x");
+ for (int i = 0; i < n; i++) {
+ body = new ApplicationExpression(Optional.empty(), SourceSpan.UNKNOWN,
+ new IdentifierExpression(Optional.empty(), SourceSpan.UNKNOWN, "f"), body);
+ }
- return new Closure(env, "f", new AbstractionExpression(Optional.empty(), SourceSpan.UNKNOWN, "x", body));
- }
+ return new Closure(env, "f", new AbstractionExpression(Optional.empty(), SourceSpan.UNKNOWN, "x", body));
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/eval/Environment.java b/core/src/main/java/coffee/liz/lambda/eval/Environment.java
index 8854719..a4ec24a 100644
--- a/core/src/main/java/coffee/liz/lambda/eval/Environment.java
+++ b/core/src/main/java/coffee/liz/lambda/eval/Environment.java
@@ -18,92 +18,92 @@ import java.util.stream.Collectors;
*/
@RequiredArgsConstructor
public final class Environment {
- /** Named expansions */
- private final Map<String, Expression> macros;
+ /** Named expansions */
+ private final Map<String, Expression> macros;
- /** "FFI" */
- private final Map<String, ExternalBinding> externalBindings;
+ /** "FFI" */
+ private final Map<String, ExternalBinding> externalBindings;
- /** Variable name bound at this scope level. Null for root. */
- @Nullable
- private final String boundName;
+ /** Variable name bound at this scope level. Null for root. */
+ @Nullable
+ private final String boundName;
- /** Lazily-evaluated value for boundName, or null for root. */
- @Nullable
- private final Supplier<Value> boundValue;
+ /** Lazily-evaluated value for boundName, or null for root. */
+ @Nullable
+ private final Supplier<Value> boundValue;
- /** Enclosing scope, or null for root. Forms a linked list of bindings. */
- @Nullable
- private final Environment parent;
+ /** Enclosing scope, or null for root. Forms a linked list of bindings. */
+ @Nullable
+ private final Environment parent;
- /**
- * Creates an environment from macro and external binding lists.
- *
- * @param macros
- * program macro definitions
- * @param externalBindings
- * external Java bindings for FFI
- * @return the new environment
- */
- public static Environment from(final List<Macro> macros, final List<ExternalBinding> externalBindings) {
- return new Environment(macros.stream().collect(Collectors.toMap(Macro::name, Macro::expression)),
- externalBindings.stream().collect(Collectors.toMap(ExternalBinding::getName, Function.identity())),
- null, null, null);
- }
+ /**
+ * Creates an environment from macro and external binding lists.
+ *
+ * @param macros
+ * program macro definitions
+ * @param externalBindings
+ * external Java bindings for FFI
+ * @return the new environment
+ */
+ public static Environment from(final List<Macro> macros, final List<ExternalBinding> externalBindings) {
+ return new Environment(macros.stream().collect(Collectors.toMap(Macro::name, Macro::expression)),
+ externalBindings.stream().collect(Collectors.toMap(ExternalBinding::getName, Function.identity())),
+ null, null, null);
+ }
- /**
- * Creates a child scope.
- *
- * @param name
- * the variable name
- * @param value
- * the value supplier (thunk)
- * @return a new environment with the binding added
- */
- public Environment extend(final String name, final Supplier<Value> value) {
- return new Environment(macros, externalBindings, name, value, this);
- }
+ /**
+ * Creates a child scope.
+ *
+ * @param name
+ * the variable name
+ * @param value
+ * the value supplier (thunk)
+ * @return a new environment with the binding added
+ */
+ public Environment extend(final String name, final Supplier<Value> value) {
+ return new Environment(macros, externalBindings, name, value, this);
+ }
- /**
- * Looks up a name, checking bindings, then macros, then external bindings.
- *
- * @param name
- * the name to look up
- * @return the lookup result, or empty if not found
- */
- public Optional<LookupResult> lookup(final String name) {
- for (Environment env = this; env != null; env = env.parent) {
- if (!name.equals(env.boundName)) {
- continue;
- }
- return Optional.of(new LookupResult.Binding(env.boundValue));
- }
+ /**
+ * Looks up a name, checking bindings, then macros, then external bindings.
+ *
+ * @param name
+ * the name to look up
+ * @return the lookup result, or empty if not found
+ */
+ public Optional<LookupResult> lookup(final String name) {
+ for (Environment env = this; env != null; env = env.parent) {
+ if (!name.equals(env.boundName)) {
+ continue;
+ }
+ return Optional.of(new LookupResult.Binding(env.boundValue));
+ }
- final Expression macro = macros.get(name);
- if (macro != null) {
- return Optional.of(new LookupResult.Macro(macro));
- }
+ final Expression macro = macros.get(name);
+ if (macro != null) {
+ return Optional.of(new LookupResult.Macro(macro));
+ }
- final ExternalBinding external = externalBindings.get(name);
- if (external != null) {
- return Optional.of(new LookupResult.External(external));
- }
+ final ExternalBinding external = externalBindings.get(name);
+ if (external != null) {
+ return Optional.of(new LookupResult.External(external));
+ }
- return Optional.empty();
- }
+ return Optional.empty();
+ }
- /**
- * Result of looking up a name in the environment.
- */
- public sealed interface LookupResult {
- /** A local variable binding. */
- record Binding(Supplier<Value> value) implements LookupResult {
- }
- /** A macro definition. */
- record Macro(Expression expression) implements LookupResult {
- }
- /** An external Java binding. */
- record External(ExternalBinding binding) implements LookupResult {
- }
- }
+ /**
+ * Result of looking up a name in the environment.
+ */
+ public sealed interface LookupResult {
+ /** A local variable binding. */
+ record Binding(Supplier<Value> value) implements LookupResult {
+ }
+ /** A macro definition. */
+ record Macro(Expression expression) implements LookupResult {
+ }
+ /** An external Java binding. */
+ record External(ExternalBinding binding) implements LookupResult {
+ }
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/eval/EvaluationDepthExceededException.java b/core/src/main/java/coffee/liz/lambda/eval/EvaluationDepthExceededException.java
index 7926004..8f2ad2e 100644
--- a/core/src/main/java/coffee/liz/lambda/eval/EvaluationDepthExceededException.java
+++ b/core/src/main/java/coffee/liz/lambda/eval/EvaluationDepthExceededException.java
@@ -7,10 +7,10 @@ import lombok.Getter;
*/
@Getter
public final class EvaluationDepthExceededException extends RuntimeException {
- private final int maxDepth;
+ private final int maxDepth;
- public EvaluationDepthExceededException(final int maxDepth) {
- super("Evaluation exceeded maximum depth of " + maxDepth);
- this.maxDepth = maxDepth;
- }
+ public EvaluationDepthExceededException(final int maxDepth) {
+ super("Evaluation exceeded maximum depth of " + maxDepth);
+ this.maxDepth = maxDepth;
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/eval/NormalOrderEvaluator.java b/core/src/main/java/coffee/liz/lambda/eval/NormalOrderEvaluator.java
index 28eb69b..d9bcba3 100644
--- a/core/src/main/java/coffee/liz/lambda/eval/NormalOrderEvaluator.java
+++ b/core/src/main/java/coffee/liz/lambda/eval/NormalOrderEvaluator.java
@@ -18,84 +18,84 @@ import coffee.liz.lambda.eval.Value.Free;
*/
public final class NormalOrderEvaluator {
- public static final int DEFAULT_MAX_DEPTH = 140;
+ public static final int DEFAULT_MAX_DEPTH = 140;
- /**
- * Evaluates an expression in the given environment with default depth limit.
- *
- * @param term
- * the expression to evaluate
- * @param env
- * the environment containing bindings
- * @return the resulting value
- * @throws EvaluationDepthExceededException
- * if evaluation exceeds {@link #DEFAULT_MAX_DEPTH}
- */
- public static Value evaluate(final Expression term, final Environment env) {
- return evaluate(term, env, DEFAULT_MAX_DEPTH);
- }
+ /**
+ * Evaluates an expression in the given environment with default depth limit.
+ *
+ * @param term
+ * the expression to evaluate
+ * @param env
+ * the environment containing bindings
+ * @return the resulting value
+ * @throws EvaluationDepthExceededException
+ * if evaluation exceeds {@link #DEFAULT_MAX_DEPTH}
+ */
+ public static Value evaluate(final Expression term, final Environment env) {
+ return evaluate(term, env, DEFAULT_MAX_DEPTH);
+ }
- /**
- * Evaluates an expression in the given environment with specified depth limit.
- *
- * @param term
- * the expression to evaluate
- * @param env
- * the environment containing bindings
- * @param maxDepth
- * maximum evaluation depth
- * @return the resulting value
- * @throws EvaluationDepthExceededException
- * if evaluation exceeds maxDepth
- */
- public static Value evaluate(final Expression term, final Environment env, final int maxDepth) {
- return evaluate(term, env, maxDepth, 0);
- }
+ /**
+ * Evaluates an expression in the given environment with specified depth limit.
+ *
+ * @param term
+ * the expression to evaluate
+ * @param env
+ * the environment containing bindings
+ * @param maxDepth
+ * maximum evaluation depth
+ * @return the resulting value
+ * @throws EvaluationDepthExceededException
+ * if evaluation exceeds maxDepth
+ */
+ public static Value evaluate(final Expression term, final Environment env, final int maxDepth) {
+ return evaluate(term, env, maxDepth, 0);
+ }
- private static Value evaluate(final Expression term, final Environment env, final int maxDepth, final int depth) {
- if (depth > maxDepth) {
- throw new EvaluationDepthExceededException(maxDepth);
- }
+ private static Value evaluate(final Expression term, final Environment env, final int maxDepth, final int depth) {
+ if (depth > maxDepth) {
+ throw new EvaluationDepthExceededException(maxDepth);
+ }
- return switch (term) {
- case IdentifierExpression(var _, var _, final String name) ->
- env.lookup(name).map(result -> switch (result) {
- case LookupResult.Binding(final var value) -> value.get();
- case LookupResult.Macro(final var expr) -> evaluate(expr, env, maxDepth, depth + 1);
- case LookupResult.External(final var binding) -> new Free(binding.getName());
- }).orElseGet(() -> new Free(name));
+ return switch (term) {
+ case IdentifierExpression(var _, var _, final String name) ->
+ env.lookup(name).map(result -> switch (result) {
+ case LookupResult.Binding(final var value) -> value.get();
+ case LookupResult.Macro(final var expr) -> evaluate(expr, env, maxDepth, depth + 1);
+ case LookupResult.External(final var binding) -> new Free(binding.getName());
+ }).orElseGet(() -> new Free(name));
- case AbstractionExpression(var _, var _, final String parameter, final Expression body) ->
- new Closure(env, parameter, body);
+ case AbstractionExpression(var _, var _, final String parameter, final Expression body) ->
+ new Closure(env, parameter, body);
- case ApplicationExpression(var _, var _, final Expression func, final Expression arg) ->
- apply(evaluate(func, env, maxDepth, depth + 1), arg, env, maxDepth, depth + 1);
- };
- }
+ case ApplicationExpression(var _, var _, final Expression func, final Expression arg) ->
+ apply(evaluate(func, env, maxDepth, depth + 1), arg, env, maxDepth, depth + 1);
+ };
+ }
- private static Value apply(final Value funcVal, final Expression arg, final Environment argEnv, final int maxDepth,
- final int depth) {
- if (depth > maxDepth) {
- throw new EvaluationDepthExceededException(maxDepth);
- }
+ private static Value apply(final Value funcVal, final Expression arg, final Environment argEnv, final int maxDepth,
+ final int depth) {
+ if (depth > maxDepth) {
+ throw new EvaluationDepthExceededException(maxDepth);
+ }
- return switch (funcVal) {
- case Closure(final Environment closureEnv, final String parameter, final Expression body) -> {
- final Thunk<Value> thunk = new Thunk<>(() -> evaluate(arg, argEnv, maxDepth, depth + 1));
- final Environment newEnv = closureEnv.extend(parameter, thunk);
- yield evaluate(body, newEnv, maxDepth, depth + 1);
- }
+ return switch (funcVal) {
+ case Closure(final Environment closureEnv, final String parameter, final Expression body) -> {
+ final Thunk<Value> thunk = new Thunk<>(() -> evaluate(arg, argEnv, maxDepth, depth + 1));
+ final Environment newEnv = closureEnv.extend(parameter, thunk);
+ yield evaluate(body, newEnv, maxDepth, depth + 1);
+ }
- case Free(final String name) ->
- argEnv.lookup(name).filter(r -> r instanceof LookupResult.External).map(r -> {
- final ExternalBinding binding = ((LookupResult.External) r).binding();
- return binding.apply(argEnv, evaluate(arg, argEnv, maxDepth, depth + 1));
- }).orElseGet(() -> new Application(funcVal, evaluate(arg, argEnv, maxDepth, depth + 1)));
+ case Free(final String name) ->
+ argEnv.lookup(name).filter(r -> r instanceof LookupResult.External).map(r -> {
+ final ExternalBinding binding = ((LookupResult.External) r).binding();
+ return binding.apply(argEnv, evaluate(arg, argEnv, maxDepth, depth + 1));
+ }).orElseGet(() -> new Application(funcVal, evaluate(arg, argEnv, maxDepth, depth + 1)));
- case Application app -> {
- final Value argVal = evaluate(arg, argEnv, maxDepth, depth + 1);
- yield new Application(app, argVal);
- }
- };
- }
+ case Application app -> {
+ final Value argVal = evaluate(arg, argEnv, maxDepth, depth + 1);
+ yield new Application(app, argVal);
+ }
+ };
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/eval/Thunk.java b/core/src/main/java/coffee/liz/lambda/eval/Thunk.java
index 07c89bf..fdbda93 100644
--- a/core/src/main/java/coffee/liz/lambda/eval/Thunk.java
+++ b/core/src/main/java/coffee/liz/lambda/eval/Thunk.java
@@ -12,16 +12,16 @@ import java.util.function.Supplier;
*/
@RequiredArgsConstructor
public final class Thunk<T> implements Supplier<T> {
- private final Supplier<T> thinker; // https://www.youtube.com/shorts/Dzksib8YxSY
- private T cached = null;
- private boolean evaluated = false;
+ private final Supplier<T> thinker; // https://www.youtube.com/shorts/Dzksib8YxSY
+ private T cached = null;
+ private boolean evaluated = false;
- @Override
- public T get() {
- if (!evaluated) {
- cached = thinker.get();
- evaluated = true;
- }
- return cached;
- }
+ @Override
+ public T get() {
+ if (!evaluated) {
+ cached = thinker.get();
+ evaluated = true;
+ }
+ return cached;
+ }
} \ No newline at end of file
diff --git a/core/src/main/java/coffee/liz/lambda/eval/Value.java b/core/src/main/java/coffee/liz/lambda/eval/Value.java
index 58b9ba4..dc459ff 100644
--- a/core/src/main/java/coffee/liz/lambda/eval/Value.java
+++ b/core/src/main/java/coffee/liz/lambda/eval/Value.java
@@ -7,36 +7,36 @@ import coffee.liz.lambda.ast.Expression;
*/
public sealed interface Value permits Value.Closure, Value.Application, Value.Free {
- /**
- * A closure capturing an environment, parameter, and body.
- *
- * @param env
- * the captured environment
- * @param parameter
- * the bound parameter name
- * @param body
- * the lambda body expression
- */
- record Closure(Environment env, String parameter, Expression body) implements Value {
- }
+ /**
+ * A closure capturing an environment, parameter, and body.
+ *
+ * @param env
+ * the captured environment
+ * @param parameter
+ * the bound parameter name
+ * @param body
+ * the lambda body expression
+ */
+ record Closure(Environment env, String parameter, Expression body) implements Value {
+ }
- /**
- * A symbolic application of a function to an argument.
- *
- * @param function
- * the function
- * @param argument
- * the argument
- */
- record Application(Value function, Value argument) implements Value {
- }
+ /**
+ * A symbolic application of a function to an argument.
+ *
+ * @param function
+ * the function
+ * @param argument
+ * the argument
+ */
+ record Application(Value function, Value argument) implements Value {
+ }
- /**
- * A free variable.
- *
- * @param name
- * the variable name
- */
- record Free(String name) implements Value {
- }
+ /**
+ * A free variable.
+ *
+ * @param name
+ * the variable name
+ */
+ record Free(String name) implements Value {
+ }
}
diff --git a/core/src/main/java/coffee/liz/lambda/format/Formatter.java b/core/src/main/java/coffee/liz/lambda/format/Formatter.java
index 1ac3e95..e4fbc0c 100644
--- a/core/src/main/java/coffee/liz/lambda/format/Formatter.java
+++ b/core/src/main/java/coffee/liz/lambda/format/Formatter.java
@@ -21,218 +21,218 @@ import java.util.Optional;
@RequiredArgsConstructor
public final class Formatter {
- private final Syntax syntax;
+ private final Syntax syntax;
- public String format(final LambdaProgram program) {
- final StringBuilder sb = new StringBuilder();
- SourceSpan previousEnd = null;
+ public String format(final LambdaProgram program) {
+ final StringBuilder sb = new StringBuilder();
+ SourceSpan previousEnd = null;
- for (int i = 0; i < program.macros().size(); i++) {
- final Macro macro = program.macros().get(i);
+ for (int i = 0; i < program.macros().size(); i++) {
+ final Macro macro = program.macros().get(i);
- if (macro.comment().isPresent()) {
- final SourceComment comment = macro.comment().get();
- final String leadingPart = getLeadingCommentPart(comment, previousEnd);
- if (!leadingPart.isEmpty()) {
- sb.append(leadingPart);
- if (!leadingPart.endsWith("\n")) {
- sb.append("\n");
- }
- }
- }
+ if (macro.comment().isPresent()) {
+ final SourceComment comment = macro.comment().get();
+ final String leadingPart = getLeadingCommentPart(comment, previousEnd);
+ if (!leadingPart.isEmpty()) {
+ sb.append(leadingPart);
+ if (!leadingPart.endsWith("\n")) {
+ sb.append("\n");
+ }
+ }
+ }
- sb.append("let ").append(macro.name()).append(" = ");
- sb.append(formatExpression(macro.expression(), false));
- sb.append(";");
+ sb.append("let ").append(macro.name()).append(" = ");
+ sb.append(formatExpression(macro.expression(), false));
+ sb.append(";");
- final Optional<String> inlineComment = getInlineCommentAfter(macro.span(), program, i);
- inlineComment.ifPresent(c -> sb.append(" ").append(c));
- sb.append("\n");
+ final Optional<String> inlineComment = getInlineCommentAfter(macro.span(), program, i);
+ inlineComment.ifPresent(c -> sb.append(" ").append(c));
+ sb.append("\n");
- previousEnd = macro.span();
- }
+ previousEnd = macro.span();
+ }
- boolean isTrailingComment = false;
- boolean inlinePartAlreadyOutput = false;
+ boolean isTrailingComment = false;
+ boolean inlinePartAlreadyOutput = false;
- if (program.expression().comment().isPresent()) {
- final SourceComment comment = program.expression().comment().get();
+ if (program.expression().comment().isPresent()) {
+ final SourceComment comment = program.expression().comment().get();
- isTrailingComment = comment.span().startLine() >= program.expression().span().startLine()
- && comment.span().startColumn() > program.expression().span().startColumn();
+ isTrailingComment = comment.span().startLine() >= program.expression().span().startLine()
+ && comment.span().startColumn() > program.expression().span().startColumn();
- if (!isTrailingComment) {
- inlinePartAlreadyOutput = previousEnd != null && comment.isInlineAfter(previousEnd);
+ if (!isTrailingComment) {
+ inlinePartAlreadyOutput = previousEnd != null && comment.isInlineAfter(previousEnd);
- final String leadingPart = getLeadingCommentPart(comment, previousEnd);
- if (!leadingPart.isEmpty()) {
- sb.append(leadingPart);
- if (!leadingPart.endsWith("\n")) {
- sb.append("\n");
- }
- } else if (!program.macros().isEmpty()) {
- sb.append("\n");
- }
- } else if (!program.macros().isEmpty()) {
- sb.append("\n");
- }
- } else if (!program.macros().isEmpty()) {
- sb.append("\n");
- }
+ final String leadingPart = getLeadingCommentPart(comment, previousEnd);
+ if (!leadingPart.isEmpty()) {
+ sb.append(leadingPart);
+ if (!leadingPart.endsWith("\n")) {
+ sb.append("\n");
+ }
+ } else if (!program.macros().isEmpty()) {
+ sb.append("\n");
+ }
+ } else if (!program.macros().isEmpty()) {
+ sb.append("\n");
+ }
+ } else if (!program.macros().isEmpty()) {
+ sb.append("\n");
+ }
- sb.append(formatExpression(program.expression(), false));
+ sb.append(formatExpression(program.expression(), false));
- if (program.expression().comment().isPresent() && !inlinePartAlreadyOutput && isTrailingComment) {
- sb.append(" ").append(program.expression().comment().get().text());
- }
+ if (program.expression().comment().isPresent() && !inlinePartAlreadyOutput && isTrailingComment) {
+ sb.append(" ").append(program.expression().comment().get().text());
+ }
- return sb.toString();
- }
+ return sb.toString();
+ }
- /**
- * Gets the inline portion of a comment (first line if on same line as previous
- * element).
- */
- private String getInlineCommentPart(final SourceComment comment, final SourceSpan previousEnd) {
- if (previousEnd == null || !comment.isInlineAfter(previousEnd)) {
- return "";
- }
- final String text = comment.text();
- final int newlineIndex = text.indexOf('\n');
- return newlineIndex == -1 ? text : text.substring(0, newlineIndex);
- }
+ /**
+ * Gets the inline portion of a comment (first line if on same line as previous
+ * element).
+ */
+ private String getInlineCommentPart(final SourceComment comment, final SourceSpan previousEnd) {
+ if (previousEnd == null || !comment.isInlineAfter(previousEnd)) {
+ return "";
+ }
+ final String text = comment.text();
+ final int newlineIndex = text.indexOf('\n');
+ return newlineIndex == -1 ? text : text.substring(0, newlineIndex);
+ }
- /**
- * Gets the leading portion of a comment (all lines except inline first line).
- */
- private String getLeadingCommentPart(final SourceComment comment, final SourceSpan previousEnd) {
- if (previousEnd == null || !comment.isInlineAfter(previousEnd)) {
- return comment.text();
- }
- final String text = comment.text();
- final int newlineIndex = text.indexOf('\n');
- return newlineIndex == -1 ? "" : text.substring(newlineIndex + 1);
- }
+ /**
+ * Gets the leading portion of a comment (all lines except inline first line).
+ */
+ private String getLeadingCommentPart(final SourceComment comment, final SourceSpan previousEnd) {
+ if (previousEnd == null || !comment.isInlineAfter(previousEnd)) {
+ return comment.text();
+ }
+ final String text = comment.text();
+ final int newlineIndex = text.indexOf('\n');
+ return newlineIndex == -1 ? "" : text.substring(newlineIndex + 1);
+ }
- /**
- * Gets the inline comment that appears after the given span, if any.
- */
- private Optional<String> getInlineCommentAfter(final SourceSpan span, final LambdaProgram program,
- final int macroIndex) {
- if (macroIndex + 1 < program.macros().size()) {
- final Macro nextMacro = program.macros().get(macroIndex + 1);
- if (nextMacro.comment().isPresent() && nextMacro.comment().get().isInlineAfter(span)) {
- final String inlinePart = getInlineCommentPart(nextMacro.comment().get(), span);
- if (!inlinePart.isEmpty()) {
- return Optional.of(inlinePart);
- }
- }
- }
- if (macroIndex == program.macros().size() - 1 && program.expression().comment().isPresent()
- && program.expression().comment().get().isInlineAfter(span)) {
- final String inlinePart = getInlineCommentPart(program.expression().comment().get(), span);
- if (!inlinePart.isEmpty()) {
- return Optional.of(inlinePart);
- }
- }
- return Optional.empty();
- }
+ /**
+ * Gets the inline comment that appears after the given span, if any.
+ */
+ private Optional<String> getInlineCommentAfter(final SourceSpan span, final LambdaProgram program,
+ final int macroIndex) {
+ if (macroIndex + 1 < program.macros().size()) {
+ final Macro nextMacro = program.macros().get(macroIndex + 1);
+ if (nextMacro.comment().isPresent() && nextMacro.comment().get().isInlineAfter(span)) {
+ final String inlinePart = getInlineCommentPart(nextMacro.comment().get(), span);
+ if (!inlinePart.isEmpty()) {
+ return Optional.of(inlinePart);
+ }
+ }
+ }
+ if (macroIndex == program.macros().size() - 1 && program.expression().comment().isPresent()
+ && program.expression().comment().get().isInlineAfter(span)) {
+ final String inlinePart = getInlineCommentPart(program.expression().comment().get(), span);
+ if (!inlinePart.isEmpty()) {
+ return Optional.of(inlinePart);
+ }
+ }
+ return Optional.empty();
+ }
- private String formatExpression(final Expression expr, final boolean needsParens) {
- return switch (expr) {
- case AbstractionExpression abs -> formatAbstraction(abs, needsParens);
- case ApplicationExpression app -> formatApplication(app, needsParens);
- case IdentifierExpression id -> id.name();
- };
- }
+ private String formatExpression(final Expression expr, final boolean needsParens) {
+ return switch (expr) {
+ case AbstractionExpression abs -> formatAbstraction(abs, needsParens);
+ case ApplicationExpression app -> formatApplication(app, needsParens);
+ case IdentifierExpression id -> id.name();
+ };
+ }
- private String formatAbstraction(final AbstractionExpression abs, final boolean needsParens) {
- final StringBuilder sb = new StringBuilder();
+ private String formatAbstraction(final AbstractionExpression abs, final boolean needsParens) {
+ final StringBuilder sb = new StringBuilder();
- if (needsParens) {
- sb.append("(");
- }
- switch (syntax) {
- case LAMBDA -> {
- sb.append("λ").append(abs.parameter()).append(".");
- sb.append(formatExpression(abs.body(), false));
- }
- case ARROW -> {
- sb.append(abs.parameter()).append(" -> ");
- sb.append(formatExpression(abs.body(), false));
- }
- }
- if (needsParens) {
- sb.append(")");
- }
+ if (needsParens) {
+ sb.append("(");
+ }
+ switch (syntax) {
+ case LAMBDA -> {
+ sb.append("λ").append(abs.parameter()).append(".");
+ sb.append(formatExpression(abs.body(), false));
+ }
+ case ARROW -> {
+ sb.append(abs.parameter()).append(" -> ");
+ sb.append(formatExpression(abs.body(), false));
+ }
+ }
+ if (needsParens) {
+ sb.append(")");
+ }
- return sb.toString();
- }
+ return sb.toString();
+ }
- private String formatApplication(final ApplicationExpression app, final boolean needsParens) {
- return switch (syntax) {
- case LAMBDA -> formatLambdaApplication(app, needsParens);
- case ARROW -> formatArrowApplication(app);
- };
- }
+ private String formatApplication(final ApplicationExpression app, final boolean needsParens) {
+ return switch (syntax) {
+ case LAMBDA -> formatLambdaApplication(app, needsParens);
+ case ARROW -> formatArrowApplication(app);
+ };
+ }
- private String formatLambdaApplication(final ApplicationExpression app, final boolean needsParens) {
- final StringBuilder sb = new StringBuilder();
+ private String formatLambdaApplication(final ApplicationExpression app, final boolean needsParens) {
+ final StringBuilder sb = new StringBuilder();
- if (needsParens) {
- sb.append("(");
- }
+ if (needsParens) {
+ sb.append("(");
+ }
- final boolean funcNeedsParens = app.applicable() instanceof AbstractionExpression;
- sb.append(formatExpression(app.applicable(), funcNeedsParens));
+ final boolean funcNeedsParens = app.applicable() instanceof AbstractionExpression;
+ sb.append(formatExpression(app.applicable(), funcNeedsParens));
- sb.append(" ");
+ sb.append(" ");
- final boolean argNeedsParens = app.argument() instanceof ApplicationExpression
- || app.argument() instanceof AbstractionExpression;
- sb.append(formatExpression(app.argument(), argNeedsParens));
+ final boolean argNeedsParens = app.argument() instanceof ApplicationExpression
+ || app.argument() instanceof AbstractionExpression;
+ sb.append(formatExpression(app.argument(), argNeedsParens));
- if (needsParens) {
- sb.append(")");
- }
+ if (needsParens) {
+ sb.append(")");
+ }
- return sb.toString();
- }
+ return sb.toString();
+ }
- private String formatArrowApplication(final ApplicationExpression app) {
- final StringBuilder sb = new StringBuilder();
+ private String formatArrowApplication(final ApplicationExpression app) {
+ final StringBuilder sb = new StringBuilder();
- Expression func = app.applicable();
- final List<Expression> args = new ArrayList<>();
- args.add(app.argument());
+ Expression func = app.applicable();
+ final List<Expression> args = new ArrayList<>();
+ args.add(app.argument());
- while (func instanceof ApplicationExpression appFunc) {
- args.addFirst(appFunc.argument());
- func = appFunc.applicable();
- }
+ while (func instanceof ApplicationExpression appFunc) {
+ args.addFirst(appFunc.argument());
+ func = appFunc.applicable();
+ }
- final boolean funcNeedsParens = func instanceof AbstractionExpression;
- if (funcNeedsParens) {
- sb.append("(");
- }
- sb.append(formatExpression(func, false));
- if (funcNeedsParens) {
- sb.append(")");
- }
+ final boolean funcNeedsParens = func instanceof AbstractionExpression;
+ if (funcNeedsParens) {
+ sb.append("(");
+ }
+ sb.append(formatExpression(func, false));
+ if (funcNeedsParens) {
+ sb.append(")");
+ }
- for (final Expression arg : args) {
- sb.append("(");
- sb.append(formatExpression(arg, false));
- sb.append(")");
- }
+ for (final Expression arg : args) {
+ sb.append("(");
+ sb.append(formatExpression(arg, false));
+ sb.append(")");
+ }
- return sb.toString();
- }
+ return sb.toString();
+ }
- /**
- * Formats a program in the specified syntax.
- */
- public static String emit(final LambdaProgram program, final Syntax syntax) {
- return new Formatter(syntax).format(program);
- }
+ /**
+ * Formats a program in the specified syntax.
+ */
+ public static String emit(final LambdaProgram program, final Syntax syntax) {
+ return new Formatter(syntax).format(program);
+ }
}
diff --git a/core/src/main/java/com/kotcrab/vis/ui/widget/EditorHighlightTextAreaBridge.java b/core/src/main/java/com/kotcrab/vis/ui/widget/EditorHighlightTextAreaBridge.java
index a14c6a7..81cb1d3 100644
--- a/core/src/main/java/com/kotcrab/vis/ui/widget/EditorHighlightTextAreaBridge.java
+++ b/core/src/main/java/com/kotcrab/vis/ui/widget/EditorHighlightTextAreaBridge.java
@@ -1,33 +1,33 @@
package com.kotcrab.vis.ui.widget;
public class EditorHighlightTextAreaBridge extends HighlightTextArea {
- public EditorHighlightTextAreaBridge(final String text, final VisTextFieldStyle style) {
- super(text, style);
- }
+ public EditorHighlightTextAreaBridge(final String text, final VisTextFieldStyle style) {
+ super(text, style);
+ }
- public void editorSyncCursorState() {
- updateCurrentLine();
- showCursor();
- }
+ public void editorSyncCursorState() {
+ updateCurrentLine();
+ showCursor();
+ }
- public void editorSetSelectionEndpoints(final int selectionStart, final int cursorPosition) {
- final int clampedSelectionStart = Math.max(0, Math.min(selectionStart, getText().length()));
- final int clampedCursorPosition = Math.max(0, Math.min(cursorPosition, getText().length()));
- if (clampedSelectionStart == clampedCursorPosition) {
- clearSelection();
- cursor = clampedCursorPosition;
- editorSyncCursorState();
- return;
- }
+ public void editorSetSelectionEndpoints(final int selectionStart, final int cursorPosition) {
+ final int clampedSelectionStart = Math.max(0, Math.min(selectionStart, getText().length()));
+ final int clampedCursorPosition = Math.max(0, Math.min(cursorPosition, getText().length()));
+ if (clampedSelectionStart == clampedCursorPosition) {
+ clearSelection();
+ cursor = clampedCursorPosition;
+ editorSyncCursorState();
+ return;
+ }
- hasSelection = true;
- this.selectionStart = clampedSelectionStart;
- cursor = clampedCursorPosition;
- editorSyncCursorState();
- }
+ hasSelection = true;
+ this.selectionStart = clampedSelectionStart;
+ cursor = clampedCursorPosition;
+ editorSyncCursorState();
+ }
- public void editorSetCursorKeepingSelection(final int cursorPosition) {
- cursor = Math.max(0, Math.min(cursorPosition, getText().length()));
- editorSyncCursorState();
- }
+ public void editorSetCursorKeepingSelection(final int cursorPosition) {
+ cursor = Math.max(0, Math.min(cursorPosition, getText().length()));
+ editorSyncCursorState();
+ }
}