From 8c3317ebef521c1a205c1b9a289e98be1f7622ba Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Tue, 23 Dec 2025 14:13:32 +0100 Subject: [PATCH] Remove Spring Messaging dependency Signed-off-by: Piotr Olaszewski --- .../shell/docs/EventLoopSnippets.java | 4 +- .../shell/docs/TerminalUiSnippets.java | 5 +- spring-shell-jline/pom.xml | 5 - .../jline/tui/component/TerminalEvent.java | 18 +++ .../jline/tui/component/ViewComponent.java | 5 +- .../message/ShellMessageBuilder.java | 133 ---------------- .../message/ShellMessageHeaderAccessor.java | 149 ------------------ .../StaticShellMessageHeaderAccessor.java | 90 ----------- .../tui/component/message/package-info.java | 4 - .../jline/tui/component/view/TerminalUI.java | 14 +- .../component/view/control/AbstractView.java | 51 +++--- .../tui/component/view/control/AppView.java | 14 +- .../component/view/control/ButtonView.java | 9 +- .../component/view/control/DialogView.java | 7 +- .../tui/component/view/control/InputView.java | 14 +- .../tui/component/view/control/ListView.java | 19 ++- .../tui/component/view/control/MenuView.java | 17 +- .../component/view/control/ProgressView.java | 47 +++--- .../component/view/control/StatusBarView.java | 11 +- .../view/event/DefaultEventLoop.java | 102 +++++------- .../tui/component/view/event/EventLoop.java | 38 +++-- .../AnimationEventLoopProcessor.java | 25 +-- .../processor/TaskEventLoopProcessor.java | 51 +++--- .../view/event/DefaultEventLoopTests.java | 68 ++++---- 24 files changed, 263 insertions(+), 637 deletions(-) create mode 100644 spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/TerminalEvent.java delete mode 100644 spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageBuilder.java delete mode 100644 spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageHeaderAccessor.java delete mode 100644 spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/StaticShellMessageHeaderAccessor.java delete mode 100644 spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/package-info.java diff --git a/spring-shell-docs/src/test/java/org/springframework/shell/docs/EventLoopSnippets.java b/spring-shell-docs/src/test/java/org/springframework/shell/docs/EventLoopSnippets.java index c00db9db0..973a825b1 100644 --- a/spring-shell-docs/src/test/java/org/springframework/shell/docs/EventLoopSnippets.java +++ b/spring-shell-docs/src/test/java/org/springframework/shell/docs/EventLoopSnippets.java @@ -19,7 +19,7 @@ import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.Message; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.TerminalUI; import org.springframework.shell.jline.tui.component.view.event.EventLoop; @@ -34,7 +34,7 @@ void events() { // tag::plainevents[] TerminalUI ui = new TerminalUI(terminal); EventLoop eventLoop = ui.getEventLoop(); - Flux> events = eventLoop.events(); + Flux> events = eventLoop.events(); events.subscribe(); // end::plainevents[] } diff --git a/spring-shell-docs/src/test/java/org/springframework/shell/docs/TerminalUiSnippets.java b/spring-shell-docs/src/test/java/org/springframework/shell/docs/TerminalUiSnippets.java index e0fd9c9f9..008e5611e 100644 --- a/spring-shell-docs/src/test/java/org/springframework/shell/docs/TerminalUiSnippets.java +++ b/spring-shell-docs/src/test/java/org/springframework/shell/docs/TerminalUiSnippets.java @@ -18,7 +18,7 @@ import org.jline.terminal.Terminal; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.TerminalUI; import org.springframework.shell.jline.tui.component.view.TerminalUIBuilder; import org.springframework.shell.jline.tui.component.view.control.BoxView; @@ -65,7 +65,8 @@ void sample() { EventLoop eventLoop = ui.getEventLoop(); eventLoop.keyEvents().subscribe(event -> { if (event.getPlainKey() == Key.q && event.hasCtrl()) { - eventLoop.dispatch(ShellMessageBuilder.ofInterrupt()); + TerminalEvent terminalEvent = new TerminalEvent<>("int", EventLoop.Type.SYSTEM); + eventLoop.dispatch(terminalEvent); } }); ui.run(); diff --git a/spring-shell-jline/pom.xml b/spring-shell-jline/pom.xml index b4253155f..19818d666 100644 --- a/spring-shell-jline/pom.xml +++ b/spring-shell-jline/pom.xml @@ -51,11 +51,6 @@ ST4 ${antlr-st4.version} - - org.springframework - spring-messaging - ${spring-framework.version} - diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/TerminalEvent.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/TerminalEvent.java new file mode 100644 index 000000000..0b7951328 --- /dev/null +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/TerminalEvent.java @@ -0,0 +1,18 @@ +package org.springframework.shell.jline.tui.component; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +import org.springframework.shell.jline.tui.component.view.control.View; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; + +/** + * @author Piotr Olaszewski + */ +public record TerminalEvent(T payload, EventLoop.Type type, @Nullable View view, + @Nullable Map attributes) { + public TerminalEvent(T payload, EventLoop.Type type) { + this(payload, type, null, null); + } +} diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/ViewComponent.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/ViewComponent.java index 658a84cc4..d81228a71 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/ViewComponent.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/ViewComponent.java @@ -20,7 +20,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; import org.springframework.shell.jline.tui.component.view.TerminalUI; import org.springframework.shell.jline.tui.component.view.control.View; import org.springframework.shell.jline.tui.component.view.control.ViewDoneEvent; @@ -32,6 +31,7 @@ * Handles view execution in a non-fullscreen setup. * * @author Janne Valkealahti + * @author Piotr Olaszewski */ public class ViewComponent { @@ -118,7 +118,8 @@ public EventLoop getEventLoop() { * Request exit from an execution loop. */ public void exit() { - eventLoop.dispatch(ShellMessageBuilder.ofInterrupt()); + TerminalEvent terminalEvent = new TerminalEvent<>("int", EventLoop.Type.SYSTEM); + eventLoop.dispatch(terminalEvent); } /** diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageBuilder.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageBuilder.java deleted file mode 100644 index fc20106c0..000000000 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageBuilder.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.shell.jline.tui.component.message; - -import org.jspecify.annotations.Nullable; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.shell.jline.tui.component.view.control.View; -import org.springframework.shell.jline.tui.component.view.event.EventLoop; -import org.springframework.shell.jline.tui.component.view.event.KeyEvent; -import org.springframework.shell.jline.tui.component.view.event.MouseEvent; -import org.springframework.util.Assert; - -/** - * Shell spesific message builder. - * - * @param the payload type. - * @author Janne Valkealahti - * @author Piotr Olaszewski - */ -public final class ShellMessageBuilder { - - private final T payload; - - private final ShellMessageHeaderAccessor headerAccessor; - - private final @Nullable Message originalMessage; - - private ShellMessageBuilder(T payload, @Nullable Message originalMessage) { - Assert.notNull(payload, "payload must not be null"); - this.payload = payload; - this.originalMessage = originalMessage; - this.headerAccessor = new ShellMessageHeaderAccessor(originalMessage); - // if (originalMessage != null) { - // this.modified = (!this.payload.equals(originalMessage.getPayload())); - // } - } - - /** - * Create a builder for a new {@link Message} instance with the provided payload. - * @param The type of the payload. - * @param payload the payload for the new message - * @return A ShellMessageBuilder. - */ - public static ShellMessageBuilder withPayload(T payload) { - return new ShellMessageBuilder<>(payload, null); - } - - /** - * Create a {@code redraw} message. - * @return a redraw message - */ - public static Message ofRedraw() { - return new ShellMessageBuilder<>("redraw", null).setEventType(EventLoop.Type.SYSTEM).setPriority(0).build(); - } - - /** - * Create a {@code interrupt} message. - * @return a interrupt message - */ - public static Message ofInterrupt() { - return new ShellMessageBuilder<>("int", null).setEventType(EventLoop.Type.SYSTEM).setPriority(0).build(); - } - - /** - * Create a {@code signal} message. - * @return a signal message - */ - public static Message ofSignal(String signal) { - return new ShellMessageBuilder<>(signal, null).setEventType(EventLoop.Type.SIGNAL).setPriority(0).build(); - } - - /** - * Create a message of a {@link KeyEvent}. - * @param event the event type - * @return a message with {@link KeyEvent} as a payload - */ - public static Message ofKeyEvent(KeyEvent event) { - return new ShellMessageBuilder<>(event, null).setEventType(EventLoop.Type.KEY).build(); - } - - /** - * Create a message of a {@link MouseEvent}. - * @param event the event type - * @return a message with {@link MouseEvent} as a payload - */ - public static Message ofMouseEvent(MouseEvent event) { - return new ShellMessageBuilder<>(event, null).setEventType(EventLoop.Type.MOUSE).build(); - } - - public static Message ofView(View view, Object args) { - return new ShellMessageBuilder<>(args, null).setEventType(EventLoop.Type.VIEW).setView(view).build(); - } - - public static Message ofViewFocus(String action, View view) { - return new ShellMessageBuilder<>(action, null).setEventType(EventLoop.Type.SYSTEM).setView(view).build(); - } - - public ShellMessageBuilder setPriority(Integer priority) { - return setHeader(ShellMessageHeaderAccessor.PRIORITY, priority); - } - - public ShellMessageBuilder setView(View view) { - return setHeader(ShellMessageHeaderAccessor.VIEW, view); - } - - public ShellMessageBuilder setEventType(EventLoop.Type type) { - return setHeader(ShellMessageHeaderAccessor.EVENT_TYPE, type); - } - - public ShellMessageBuilder setHeader(String headerName, @Nullable Object headerValue) { - this.headerAccessor.setHeader(headerName, headerValue); - return this; - } - - public Message build() { - return new GenericMessage<>(this.payload, this.headerAccessor.toMap()); - } - -} diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageHeaderAccessor.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageHeaderAccessor.java deleted file mode 100644 index 980e3aecb..000000000 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/ShellMessageHeaderAccessor.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.shell.jline.tui.component.message; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.function.BiFunction; - -import org.jspecify.annotations.Nullable; -import reactor.util.context.ContextView; - -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageHeaderAccessor; -import org.springframework.shell.jline.tui.component.view.control.View; -import org.springframework.shell.jline.tui.component.view.event.EventLoop; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; - -/** - * Adds standard shell Headers. - * - * @author Janne Valkealahti - * @author Piotr Olaszewski - */ -public class ShellMessageHeaderAccessor extends MessageHeaderAccessor { - - public static final String PRIORITY = "priority"; - - public static final String VIEW = "view"; - - /** - * Raw source message. - */ - public static final String REACTOR_CONTEXT = "reactorContext"; - - /** - * Raw source message. - */ - public static final String EVENT_TYPE = "eventType"; - - private static final BiFunction TYPE_VERIFY_MESSAGE_FUNCTION = (name, trailer) -> "The '" - + name + trailer; - - private Set readOnlyHeaders = new HashSet<>(); - - public ShellMessageHeaderAccessor(@Nullable Message message) { - super(message); - } - - /** - * Specify a list of headers which should be considered as read only and prohibited - * from being populated in the message. - * @param readOnlyHeaders the list of headers for {@code readOnly} mode. Defaults to - * {@link org.springframework.messaging.MessageHeaders#ID} and - * {@link org.springframework.messaging.MessageHeaders#TIMESTAMP}. - * @see #isReadOnly(String) - */ - public void setReadOnlyHeaders(String... readOnlyHeaders) { - Assert.noNullElements(readOnlyHeaders, "'readOnlyHeaders' must not be contain null items."); - if (!ObjectUtils.isEmpty(readOnlyHeaders)) { - this.readOnlyHeaders = new HashSet<>(Arrays.asList(readOnlyHeaders)); - } - } - - public @Nullable Integer getPriority() { - Number priority = getHeader(PRIORITY, Number.class); - return (priority != null ? priority.intValue() : null); - } - - public @Nullable View getView() { - View view = getHeader(VIEW, View.class); - return view; - } - - /** - * Get a {@link ContextView} header if present. - * @return the {@link ContextView} header if present. - */ - public @Nullable ContextView getReactorContext() { - return getHeader(REACTOR_CONTEXT, ContextView.class); - } - - /** - * Get a {@link EventLoop.Type} header if present. - * @return the {@link EventLoop.Type} header if present. - */ - public EventLoop.@Nullable Type getEventType() { - return getHeader(EVENT_TYPE, EventLoop.Type.class); - } - - @SuppressWarnings("unchecked") - public @Nullable T getHeader(String key, Class type) { - Object value = getHeader(key); - if (value == null) { - return null; - } - if (!type.isAssignableFrom(value.getClass())) { - throw new IllegalArgumentException("Incorrect type specified for header '" + key + "'. Expected [" + type - + "] but actual type is [" + value.getClass() + "]"); - } - return (T) value; - } - - @Override - protected void verifyType(@Nullable String headerName, @Nullable Object headerValue) { - if (headerName != null && headerValue != null) { - super.verifyType(headerName, headerValue); - if (ShellMessageHeaderAccessor.PRIORITY.equals(headerName)) { - Assert.isTrue(Number.class.isAssignableFrom(headerValue.getClass()), - TYPE_VERIFY_MESSAGE_FUNCTION.apply(headerName, "' header value must be a Number.")); - } - } - } - - @Override - public boolean isReadOnly(String headerName) { - return super.isReadOnly(headerName) || this.readOnlyHeaders.contains(headerName); - } - - @Override - public Map toMap() { - if (ObjectUtils.isEmpty(this.readOnlyHeaders)) { - return super.toMap(); - } - else { - Map headers = super.toMap(); - for (String header : this.readOnlyHeaders) { - headers.remove(header); - } - return headers; - } - } - -} diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/StaticShellMessageHeaderAccessor.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/StaticShellMessageHeaderAccessor.java deleted file mode 100644 index 7165dbe8d..000000000 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/StaticShellMessageHeaderAccessor.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.shell.jline.tui.component.message; - -import java.util.UUID; - -import org.jspecify.annotations.Nullable; -import reactor.util.context.Context; -import reactor.util.context.ContextView; - -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.shell.jline.tui.component.view.control.View; -import org.springframework.shell.jline.tui.component.view.event.EventLoop; - -/** - * Lightweight type-safe header accessor avoiding object creation just to access a header. - * - * @author Janne Valkealahti - * @author Piotr Olaszewski - * @see ShellMessageHeaderAccessor - */ -public final class StaticShellMessageHeaderAccessor { - - private StaticShellMessageHeaderAccessor() { - } - - public static @Nullable UUID getId(Message message) { - Object value = message.getHeaders().get(MessageHeaders.ID); - if (value == null) { - return null; - } - return (value instanceof UUID ? (UUID) value : UUID.fromString(value.toString())); - } - - public static @Nullable Long getTimestamp(Message message) { - Object value = message.getHeaders().get(MessageHeaders.TIMESTAMP); - if (value == null) { - return null; - } - return (value instanceof Long ? (Long) value : Long.parseLong(value.toString())); - } - - public static @Nullable Integer getPriority(Message message) { - Number priority = message.getHeaders().get(ShellMessageHeaderAccessor.PRIORITY, Number.class); - return (priority != null ? priority.intValue() : null); - } - - public static @Nullable View getView(Message message) { - View view = message.getHeaders().get(ShellMessageHeaderAccessor.VIEW, View.class); - return view; - } - - /** - * Get a {@link ContextView} header if present. - * @param message the message to get a header from. - * @return the {@link ContextView} header if present. - */ - public static ContextView getReactorContext(Message message) { - ContextView reactorContext = message.getHeaders() - .get(ShellMessageHeaderAccessor.REACTOR_CONTEXT, ContextView.class); - if (reactorContext == null) { - reactorContext = Context.empty(); - } - return reactorContext; - } - - /** - * Get a {@link EventLoop.Type} header if present. - * @param message the message to get a header from. - * @return the {@link EventLoop.Type} header if present. - */ - public static EventLoop.@Nullable Type getEventType(Message message) { - return message.getHeaders().get(ShellMessageHeaderAccessor.EVENT_TYPE, EventLoop.Type.class); - } - -} diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/package-info.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/package-info.java deleted file mode 100644 index cb03126fb..000000000 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/message/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package org.springframework.shell.jline.tui.component.message; - -import org.jspecify.annotations.NullMarked; diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/TerminalUI.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/TerminalUI.java index 8744f655f..9f68ac2f6 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/TerminalUI.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/TerminalUI.java @@ -33,7 +33,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.control.View; import org.springframework.shell.jline.tui.component.view.control.ViewService; import org.springframework.shell.jline.tui.component.view.event.DefaultEventLoop; @@ -148,7 +148,8 @@ public EventLoop getEventLoop() { * is handled as soon as possible. */ public void redraw() { - getEventLoop().dispatch(ShellMessageBuilder.ofRedraw()); + TerminalEvent terminalEvent = new TerminalEvent<>("redraw", EventLoop.Type.SYSTEM); + getEventLoop().dispatch(terminalEvent); } /** @@ -308,7 +309,8 @@ private synchronized void display() { } private void dispatchWinch() { - eventLoop.dispatch(ShellMessageBuilder.ofSignal("WINCH")); + TerminalEvent terminalEvent = new TerminalEvent<>("WINCH", EventLoop.Type.SIGNAL); + eventLoop.dispatch(terminalEvent); } private void registerEventHandling() { @@ -475,12 +477,14 @@ else if (operation == KeyEvent.Key.Mouse) { private void dispatchKeyEvent(KeyEvent event) { log.debug("Dispatch key event: " + event); - eventLoop.dispatch(ShellMessageBuilder.ofKeyEvent(event)); + TerminalEvent terminalEvent = new TerminalEvent<>(event, EventLoop.Type.KEY); + eventLoop.dispatch(terminalEvent); } private void dispatchMouse(MouseEvent event) { log.debug("Dispatch mouse event: " + event); - eventLoop.dispatch(ShellMessageBuilder.ofMouseEvent(event)); + TerminalEvent terminalEvent = new TerminalEvent<>(event, EventLoop.Type.MOUSE); + eventLoop.dispatch(terminalEvent); } private void mouseEvent() { diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AbstractView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AbstractView.java index 6dd90fc54..868c1753b 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AbstractView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AbstractView.java @@ -27,8 +27,7 @@ import reactor.core.Disposable; import reactor.core.Disposables; -import org.springframework.messaging.Message; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.KeyBindingConsumer; import org.springframework.shell.jline.tui.component.view.event.KeyBindingConsumerArgs; @@ -421,15 +420,15 @@ private void registerMouseBinding(Integer mouseType, @Nullable String mouseComma } /** - * Dispatch a {@link Message} into an event loop. - * @param message the message to dispatch + * Dispatch a {@link TerminalEvent} into an event loop. + * @param terminalEvent the message to dispatch */ - protected void dispatch(Message message) { + protected void dispatch(TerminalEvent terminalEvent) { if (eventLoop != null) { - eventLoop.dispatch(message); + eventLoop.dispatch(terminalEvent); } else { - log.warn("Can't dispatch message " + message + " as eventloop is not set"); + log.warn("Can't dispatch event " + terminalEvent + " as eventloop is not set"); } } @@ -437,8 +436,8 @@ protected boolean dispatchRunnable(Runnable runnable) { if (eventLoop == null) { return false; } - Message message = ShellMessageBuilder.withPayload(runnable).setEventType(EventLoop.Type.TASK).build(); - dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>(runnable, EventLoop.Type.TASK); + dispatch(terminalEvent); return true; } @@ -450,10 +449,8 @@ public boolean runViewCommand(@Nullable String command) { if (command != null) { Runnable runnable = commands.get(command); if (runnable != null) { - Message message = ShellMessageBuilder.withPayload(runnable) - .setEventType(EventLoop.Type.TASK) - .build(); - dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>(runnable, EventLoop.Type.TASK); + dispatch(terminalEvent); return true; } } @@ -470,19 +467,15 @@ protected boolean dispatchKeyRunCommand(KeyEvent event, KeyBindingValue keyBindi } Runnable keyRunnable = keyBindingValue.keyRunnable(); if (keyRunnable != null) { - Message message = ShellMessageBuilder.withPayload(keyRunnable) - .setEventType(EventLoop.Type.TASK) - .build(); - dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>(keyRunnable, EventLoop.Type.TASK); + dispatch(terminalEvent); return true; } KeyBindingConsumer keyConsumer = keyBindingValue.keyConsumer(); if (keyConsumer != null) { - Message message = ShellMessageBuilder - .withPayload(new KeyBindingConsumerArgs(keyConsumer, event)) - .setEventType(EventLoop.Type.TASK) - .build(); - dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>( + new KeyBindingConsumerArgs(keyConsumer, event), EventLoop.Type.TASK); + dispatch(terminalEvent); return true; } return false; @@ -498,19 +491,15 @@ protected boolean dispatchMouseRunCommand(MouseEvent event, MouseBindingValue mo } Runnable mouseRunnable = mouseBindingValue.mouseRunnable(); if (mouseRunnable != null) { - Message message = ShellMessageBuilder.withPayload(mouseRunnable) - .setEventType(EventLoop.Type.TASK) - .build(); - dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>(mouseRunnable, EventLoop.Type.TASK); + dispatch(terminalEvent); return true; } MouseBindingConsumer mouseConsumer = mouseBindingValue.mouseConsumer(); if (mouseConsumer != null) { - Message message = ShellMessageBuilder - .withPayload(new MouseBindingConsumerArgs(mouseConsumer, event)) - .setEventType(EventLoop.Type.TASK) - .build(); - dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>( + new MouseBindingConsumerArgs(mouseConsumer, event), EventLoop.Type.TASK); + dispatch(terminalEvent); return true; } return false; diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AppView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AppView.java index 09e6ac1a8..2578a6333 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AppView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/AppView.java @@ -16,7 +16,9 @@ package org.springframework.shell.jline.tui.component.view.control; import org.jspecify.annotations.Nullable; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; + +import org.springframework.shell.jline.tui.component.TerminalEvent; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.KeyEvent; import org.springframework.shell.jline.tui.component.view.event.KeyEvent.Key; import org.springframework.shell.jline.tui.component.view.event.KeyHandler; @@ -166,11 +168,17 @@ public KeyHandler getKeyHandler() { KeyEvent event = args.event(); boolean consumed = false; if (event.isKey(Key.CursorLeft)) { - dispatch(ShellMessageBuilder.ofView(this, AppViewEvent.of(this, AppViewEventArgs.Direction.PREVIOUS))); + AppViewEvent appViewEvent = AppViewEvent.of(this, AppViewEventArgs.Direction.PREVIOUS); + TerminalEvent terminalEvent = new TerminalEvent<>(appViewEvent, EventLoop.Type.VIEW, this, + null); + dispatch(terminalEvent); consumed = true; } else if (event.isKey(Key.CursorRight)) { - dispatch(ShellMessageBuilder.ofView(this, AppViewEvent.of(this, AppViewEventArgs.Direction.NEXT))); + AppViewEvent appViewEvent = AppViewEvent.of(this, AppViewEventArgs.Direction.NEXT); + TerminalEvent terminalEvent = new TerminalEvent<>(appViewEvent, EventLoop.Type.VIEW, this, + null); + dispatch(terminalEvent); consumed = true; } return KeyHandler.resultOf(event, consumed, null); diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ButtonView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ButtonView.java index 3e1206146..e02dda1ac 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ButtonView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ButtonView.java @@ -16,8 +16,10 @@ package org.springframework.shell.jline.tui.component.view.control; import org.jspecify.annotations.Nullable; + +import org.springframework.shell.jline.tui.component.TerminalEvent; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.KeyEvent.Key; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; import org.springframework.shell.jline.tui.component.view.event.KeyHandler; import org.springframework.shell.jline.tui.component.view.event.MouseEvent; import org.springframework.shell.jline.tui.component.view.event.MouseHandler; @@ -108,7 +110,10 @@ private void mouseSelect(MouseEvent event) { } private void dispatch() { - dispatch(ShellMessageBuilder.ofView(this, ButtonViewSelectEvent.of(this))); + ButtonViewSelectEvent buttonViewSelectEvent = ButtonViewSelectEvent.of(this); + TerminalEvent terminalEvent = new TerminalEvent<>(buttonViewSelectEvent, + EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); if (action != null) { dispatchRunnable(action); } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/DialogView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/DialogView.java index 8c6824895..0b58f63f0 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/DialogView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/DialogView.java @@ -20,7 +20,8 @@ import java.util.ListIterator; import org.jspecify.annotations.Nullable; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; + +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.control.ButtonView.ButtonViewSelectEvent; import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.MouseHandler; @@ -143,7 +144,9 @@ protected void drawInternal(Screen screen) { } private void dispatch() { - dispatch(ShellMessageBuilder.ofView(this, DialogViewCloseEvent.of(this))); + DialogViewCloseEvent args = DialogViewCloseEvent.of(this); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); } public record DialogViewItemEventArgs() implements ViewEventArgs { diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/InputView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/InputView.java index 49fe7e74f..db0a27a80 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/InputView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/InputView.java @@ -18,11 +18,12 @@ import java.util.ArrayList; import java.util.stream.Collectors; -import org.jspecify.annotations.Nullable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; +import org.springframework.shell.jline.tui.component.TerminalEvent; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.KeyEvent; import org.springframework.shell.jline.tui.component.view.event.KeyEvent.Key; import org.springframework.shell.jline.tui.component.view.event.KeyHandler; @@ -105,7 +106,10 @@ private int cursorPosition() { } private void dispatchTextChange(String oldText, String newText) { - dispatch(ShellMessageBuilder.ofView(this, InputViewTextChangeEvent.of(this, oldText, newText))); + InputViewTextChangeEvent args = InputViewTextChangeEvent.of(this, oldText, newText); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, this, + null); + dispatch(terminalEvent); } private void add(@Nullable String data) { @@ -153,7 +157,9 @@ private void right() { } private void done() { - dispatch(ShellMessageBuilder.ofView(this, ViewDoneEvent.of(this))); + ViewDoneEvent args = ViewDoneEvent.of(this); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); } public record InputViewTextChangeEventArgs(String oldText, String newText) implements ViewEventArgs { diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ListView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ListView.java index 9b3bceaa5..82a11fc20 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ListView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ListView.java @@ -25,8 +25,10 @@ import java.util.function.BiFunction; import org.jspecify.annotations.Nullable; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; + +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.control.cell.ListCell; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.KeyEvent.Key; import org.springframework.shell.jline.tui.component.view.event.MouseEvent; import org.springframework.shell.jline.tui.component.view.screen.Screen; @@ -243,7 +245,10 @@ else if (start + pos + 1 >= size) { } } if (active != start + pos) { - dispatch(ShellMessageBuilder.ofView(this, ListViewSelectedItemChangedEvent.of(this, selectedItem()))); + ListViewSelectedItemChangedEvent args = ListViewSelectedItemChangedEvent.of(this, selectedItem()); + TerminalEvent> terminalEvent = new TerminalEvent<>(args, + EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); } } @@ -282,7 +287,9 @@ private void down() { private void enter() { if (itemStyle == ItemStyle.NOCHECK) { - dispatch(ShellMessageBuilder.ofView(this, ListViewOpenSelectedItemEvent.of(this, selectedItem()))); + ListViewOpenSelectedItemEvent args = ListViewOpenSelectedItemEvent.of(this, selectedItem()); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); return; } } @@ -297,7 +304,11 @@ private void click(MouseEvent event) { if (active >= 0 && active < items.size()) { pos = index; if (itemStyle == ItemStyle.NOCHECK) { - dispatch(ShellMessageBuilder.ofView(this, ListViewSelectedItemChangedEvent.of(this, selectedItem()))); + ListViewSelectedItemChangedEvent<@Nullable T> args = ListViewSelectedItemChangedEvent.of(this, + selectedItem()); + TerminalEvent> terminalEvent = new TerminalEvent<>(args, + EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); return; } } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/MenuView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/MenuView.java index 3b10a09a4..356b68e2d 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/MenuView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/MenuView.java @@ -22,19 +22,20 @@ import java.util.List; import java.util.Set; -import org.jspecify.annotations.Nullable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; +import org.springframework.shell.jline.tui.component.TerminalEvent; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.KeyEvent.Key; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; import org.springframework.shell.jline.tui.component.view.event.MouseEvent; import org.springframework.shell.jline.tui.component.view.screen.Screen; import org.springframework.shell.jline.tui.component.view.screen.Screen.Writer; +import org.springframework.shell.jline.tui.component.view.screen.ScreenItem; import org.springframework.shell.jline.tui.geom.Dimension; import org.springframework.shell.jline.tui.geom.Rectangle; import org.springframework.shell.jline.tui.style.StyleSettings; -import org.springframework.shell.jline.tui.component.view.screen.ScreenItem; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -249,7 +250,10 @@ private void select() { return; } toggle(item); - dispatch(ShellMessageBuilder.ofView(this, MenuViewOpenSelectedItemEvent.of(this, item))); + MenuViewOpenSelectedItemEvent args = MenuViewOpenSelectedItemEvent.of(this, item); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, + this, null); + dispatch(terminalEvent); if (item.getAction() != null) { dispatchRunnable(item.getAction()); } @@ -278,7 +282,10 @@ else if (index < 0) { if (activeItemIndex != index) { activeItemIndex = index; MenuItem item = items.get(index); - dispatch(ShellMessageBuilder.ofView(this, MenuViewSelectedItemChangedEvent.of(this, item))); + MenuViewSelectedItemChangedEvent args = MenuViewSelectedItemChangedEvent.of(this, item); + TerminalEvent terminalEvent = new TerminalEvent<>(args, + EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); } } } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ProgressView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ProgressView.java index da91c3074..5773e64bd 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ProgressView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/ProgressView.java @@ -19,21 +19,18 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.function.Function; -import org.jspecify.annotations.Nullable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.Disposable; import reactor.core.Disposables; import reactor.core.publisher.Flux; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; -import org.springframework.shell.jline.tui.component.message.ShellMessageHeaderAccessor; -import org.springframework.shell.jline.tui.component.message.StaticShellMessageHeaderAccessor; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.control.cell.TextCell; import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.screen.Screen; @@ -248,7 +245,10 @@ public void start() { startTime = System.currentTimeMillis(); ProgressState state = getState(); scheduleTicks(); - dispatch(ShellMessageBuilder.ofView(this, ProgressViewStartEvent.of(this, state))); + ProgressViewStartEvent args = ProgressViewStartEvent.of(this, state); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, this, + null); + dispatch(terminalEvent); } private Disposable.@Nullable Composite disposables; @@ -265,22 +265,13 @@ private void scheduleTicks() { if (eventLoop == null) { return; } - Flux> ticks = Flux.interval(Duration.ofMillis(50)).map(l -> { - Message message = MessageBuilder.withPayload(l) - .setHeader(ShellMessageHeaderAccessor.EVENT_TYPE, EventLoop.Type.USER) - .setHeader(TAG_KEY, TAG_VALUE) - .build(); - return message; - }); - Disposable ticksDisposable = ticks.subscribe(m -> { - eventLoop.dispatch(m); - }); + Flux> ticks = Flux.interval(Duration.ofMillis(50)) + .map(l -> new TerminalEvent<>(l, EventLoop.Type.USER, null, Map.of(TAG_KEY, TAG_VALUE))); + Disposable ticksDisposable = ticks.subscribe(eventLoop::dispatch); Disposable eventsDisposable = eventLoop.events() - .filter(m -> EventLoop.Type.USER.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .filter(m -> ObjectUtils.nullSafeEquals(m.getHeaders().get(TAG_KEY), TAG_VALUE)) - .subscribe(m -> { - requestRedraw(); - }); + .filter(m -> EventLoop.Type.USER == m.type()) + .filter(m -> ObjectUtils.nullSafeEquals(m.attributes().get(TAG_KEY), TAG_VALUE)) + .subscribe(m -> requestRedraw()); disposables = Disposables.composite(); disposables.add(eventsDisposable); disposables.add(ticksDisposable); @@ -289,7 +280,8 @@ private void scheduleTicks() { private void requestRedraw() { EventLoop eventLoop = getEventLoop(); if (eventLoop != null) { - eventLoop.dispatch(ShellMessageBuilder.ofRedraw()); + TerminalEvent terminalEvent = new TerminalEvent<>("redraw", EventLoop.Type.SYSTEM); + eventLoop.dispatch(terminalEvent); } } @@ -306,7 +298,9 @@ public void stop() { } running = false; ProgressState state = getState(); - dispatch(ShellMessageBuilder.ofView(this, ProgressViewEndEvent.of(this, state))); + ProgressViewEndEvent args = ProgressViewEndEvent.of(this, state); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); } private static class BoxWrapper extends BoxView { @@ -392,7 +386,10 @@ else if (value < tickStart) { } if (changed) { ProgressState state = getState(); - dispatch(ShellMessageBuilder.ofView(this, ProgressViewStateChangeEvent.of(this, state))); + ProgressViewStateChangeEvent args = ProgressViewStateChangeEvent.of(this, state); + TerminalEvent terminalEvent = new TerminalEvent<>(args, EventLoop.Type.VIEW, + this, null); + dispatch(terminalEvent); requestRedraw(); } } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/StatusBarView.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/StatusBarView.java index b10051dfd..41eeae3f3 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/StatusBarView.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/control/StatusBarView.java @@ -21,11 +21,12 @@ import java.util.List; import java.util.ListIterator; -import org.jspecify.annotations.Nullable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; +import org.springframework.shell.jline.tui.component.TerminalEvent; +import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.MouseEvent; import org.springframework.shell.jline.tui.component.view.event.MouseHandler; import org.springframework.shell.jline.tui.component.view.screen.Screen; @@ -140,7 +141,11 @@ public MouseHandler getMouseHandler() { int y = event.y(); StatusItem item = itemAt(x, y); if (item != null) { - dispatch(ShellMessageBuilder.ofView(this, StatusBarViewOpenSelectedItemEvent.of(this, item))); + StatusBarViewOpenSelectedItemEvent selectedItemEvent = StatusBarViewOpenSelectedItemEvent.of(this, + item); + TerminalEvent terminalEvent = new TerminalEvent<>( + selectedItemEvent, EventLoop.Type.VIEW, this, null); + dispatch(terminalEvent); if (item.getAction() != null) { dispatchRunnable(item.getAction()); } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoop.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoop.java index 7d7978328..626a89dec 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoop.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoop.java @@ -23,11 +23,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; -import org.jspecify.annotations.Nullable; -import org.reactivestreams.Publisher; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; +import org.jspecify.annotations.Nullable; +import org.reactivestreams.Publisher; import reactor.core.Disposable; import reactor.core.Disposables; import reactor.core.publisher.Flux; @@ -36,17 +35,16 @@ import reactor.core.publisher.Sinks.Many; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; +import reactor.util.context.Context; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ResolvableType; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.shell.jline.tui.component.message.ShellMessageHeaderAccessor; -import org.springframework.shell.jline.tui.component.message.StaticShellMessageHeaderAccessor; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.control.View; import org.springframework.shell.jline.tui.component.view.control.ViewEvent; import org.springframework.shell.jline.tui.component.view.event.processor.AnimationEventLoopProcessor; import org.springframework.shell.jline.tui.component.view.event.processor.TaskEventLoopProcessor; +import org.springframework.util.Assert; /** * Default implementation of an {@link EventLoop}. @@ -58,11 +56,11 @@ public class DefaultEventLoop implements EventLoop { private final static Log log = LogFactory.getLog(DefaultEventLoop.class); - private final Queue> messageQueue = new PriorityQueue<>(MessageComparator.comparingPriority()); + private final Queue> messageQueue = new PriorityQueue<>(MessageComparator.comparingPriority()); - private final Many> many = Sinks.many().unicast().onBackpressureBuffer(messageQueue); + private final Many> many = Sinks.many().unicast().onBackpressureBuffer(messageQueue); - private Flux> sink; + private Flux> sink; // private final Sinks.Many subscribedSignal = // Sinks.many().replay().limit(1); @@ -90,7 +88,7 @@ public DefaultEventLoop(@Nullable List processors) { private void init() { sink = many.asFlux().flatMap(m -> { - Flux> pm = null; + Flux> pm = null; for (EventLoopProcessor processor : processors) { if (processor.canProcess(m)) { pm = processor.process(m); @@ -105,31 +103,26 @@ private void init() { } @Override - public void dispatch(Message message) { - log.debug("dispatch " + message); - if (!doSend(message, 1000)) { - log.warn("Failed to send message: " + message); + public void dispatch(TerminalEvent terminalEvent) { + log.debug("dispatch " + terminalEvent); + if (!doSend(terminalEvent, 1000)) { + log.warn("Failed to send message: " + terminalEvent); } } @Override - public void dispatch(Publisher> messages) { - subscribeTo(messages); + public void dispatch(Publisher> publisher) { + subscribeTo(publisher); } @Override - public Flux> events() { - return sink - // .doFinally((s) -> subscribedSignal.tryEmitNext(sink.currentSubscriberCount() > - // 0)) - ; + public Flux> events() { + return sink; } @Override public Flux events(EventLoop.Type type, Class clazz) { - return events().filter(m -> type.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .map(m -> m.getPayload()) - .ofType(clazz); + return events().filter(m -> type == m.type()).map(TerminalEvent::payload).ofType(clazz); } @Override @@ -138,37 +131,29 @@ public Flux events(Type type, ParameterizedTypeReference typeRef) { ResolvableType resolvableType = ResolvableType.forType(typeRef); Class rawClass = resolvableType.getRawClass(); Assert.state(rawClass != null, "'rawClass' must not be null"); - return (Flux) events().filter(m -> type.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .map(m -> m.getPayload()) - .ofType(rawClass); + return (Flux) events().filter(m -> type == m.type()).map(TerminalEvent::payload).ofType(rawClass); } @Override public Flux keyEvents() { - return events().filter(m -> EventLoop.Type.KEY.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .map(m -> m.getPayload()) - .ofType(KeyEvent.class); + return events().filter(m -> EventLoop.Type.KEY == m.type()).map(TerminalEvent::payload).ofType(KeyEvent.class); } @Override public Flux mouseEvents() { - return events().filter(m -> EventLoop.Type.MOUSE.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .map(m -> m.getPayload()) + return events().filter(m -> EventLoop.Type.MOUSE == m.type()) + .map(TerminalEvent::payload) .ofType(MouseEvent.class); } @Override public Flux systemEvents() { - return events().filter(m -> EventLoop.Type.SYSTEM.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .map(m -> m.getPayload()) - .ofType(String.class); + return events().filter(m -> EventLoop.Type.SYSTEM == m.type()).map(TerminalEvent::payload).ofType(String.class); } @Override public Flux signalEvents() { - return events().filter(m -> EventLoop.Type.SIGNAL.equals(StaticShellMessageHeaderAccessor.getEventType(m))) - .map(m -> m.getPayload()) - .ofType(String.class); + return events().filter(m -> EventLoop.Type.SIGNAL == m.type()).map(TerminalEvent::payload).ofType(String.class); } @Override @@ -206,7 +191,7 @@ public void onDestroy(Disposable disposable) { // ); // } - private boolean doSend(Message message, long timeout) { + private boolean doSend(TerminalEvent terminalEvent, long timeout) { if (!this.active || this.many.currentSubscriberCount() == 0) { return false; } @@ -218,7 +203,7 @@ private boolean doSend(Message message, long timeout) { } long parkTimeout = 10; long parkTimeoutNs = TimeUnit.MILLISECONDS.toNanos(parkTimeout); - while (this.active && !tryEmitMessage(message)) { + while (this.active && !tryEmitMessage(terminalEvent)) { remainingTime -= parkTimeout; if (timeout >= 0 && remainingTime <= 0) { return false; @@ -228,8 +213,8 @@ private boolean doSend(Message message, long timeout) { return true; } - private boolean tryEmitMessage(Message message) { - return switch (many.tryEmitNext(message)) { + private boolean tryEmitMessage(TerminalEvent terminalEvent) { + return switch (many.tryEmitNext(terminalEvent)) { case OK -> true; case FAIL_NON_SERIALIZED, FAIL_OVERFLOW -> false; case FAIL_ZERO_SUBSCRIBER -> @@ -254,33 +239,23 @@ private boolean tryEmitMessage(Message message) { // .subscribe()); // } - public void subscribeTo(Publisher> publisher) { + public void subscribeTo(Publisher> publisher) { disposables.add(Flux.from(publisher) // .delaySubscription(subscribedSignal.asFlux().filter(Boolean::booleanValue).next()) .publishOn(scheduler) .flatMap((message) -> Mono.just(message) .handle((messageToHandle, syncSink) -> sendReactiveMessage(messageToHandle)) - .contextWrite(StaticShellMessageHeaderAccessor.getReactorContext(message))) + .contextWrite(Context.empty())) .contextCapture() .subscribe()); } - private void sendReactiveMessage(Message message) { - Message messageToSend = message; - // We have just restored Reactor context, so no need in a header anymore. - if (messageToSend.getHeaders().containsKey(ShellMessageHeaderAccessor.REACTOR_CONTEXT)) { - messageToSend = MessageBuilder.fromMessage(message) - .removeHeader(ShellMessageHeaderAccessor.REACTOR_CONTEXT) - .build(); - } + private void sendReactiveMessage(TerminalEvent terminalEvent) { try { - dispatch(messageToSend); - // if (!doSend(messageToSend, 1000)) { - // log.warn("Failed to send message: {}", messageToSend); - // } + dispatch(terminalEvent); } catch (Exception ex) { - log.warn("Error during processing event: " + messageToSend); + log.warn("Error during processing event: " + terminalEvent); } } @@ -292,19 +267,14 @@ public void destroy() { this.scheduler.dispose(); } - private static class MessageComparator implements Comparator> { + private static class MessageComparator implements Comparator> { @Override - public int compare(Message left, Message right) { - Integer l = StaticShellMessageHeaderAccessor.getPriority(left); - Integer r = StaticShellMessageHeaderAccessor.getPriority(right); - if (l != null && r != null) { - return l.compareTo(r); - } + public int compare(TerminalEvent left, TerminalEvent right) { return 0; } - static Comparator> comparingPriority() { + static Comparator> comparingPriority() { return new MessageComparator(); } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/EventLoop.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/EventLoop.java index 27ac3cddd..d360e7f66 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/EventLoop.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/EventLoop.java @@ -21,7 +21,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.messaging.Message; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.control.View; import org.springframework.shell.jline.tui.component.view.control.ViewEvent; @@ -30,19 +30,17 @@ * lifecycle of a component. Orchestration is usually needed around timings of redraws and * and component state updates. * - * Generic message type is a Spring {@link Message} and it's up to an {@code EventLoop} - * implementation how those are processed. - * * @author Janne Valkealahti + * @author Piotr Olaszewski */ public interface EventLoop { /** - * Return a {@link Flux} of {@link Message} events. When subscribed events will be - * received until disposed or {@code EventLoop} terminates. + * Return a {@link Flux} of {@link TerminalEvent} events. When subscribed events will + * be received until disposed or {@code EventLoop} terminates. * @return the events from an event loop */ - Flux> events(); + Flux> events(); /** * Specialisation of {@link #events()} which returns type safe {@link KeyEvent}s. @@ -123,17 +121,17 @@ public interface EventLoop { Flux events(EventLoop.Type type, ParameterizedTypeReference typeRef); /** - * Dispatch {@link Message}s into an {@code EventLoop} from a {@link Publisher}. + * Dispatch {@link TerminalEvent}s into an {@code EventLoop} from a {@link Publisher}. * Usually type is either {@link Mono} or {@link Flux}. - * @param messages the messages to dispatch + * @param publisher the messages to dispatch */ - void dispatch(Publisher> messages); + void dispatch(Publisher> publisher); /** - * Dispatch a {@link Message} into an {@code EventLoop}. - * @param message the message to dispatch + * Dispatch a {@link TerminalEvent} into an {@code EventLoop}. + * @param terminalEvent the message to dispatch */ - void dispatch(Message message); + void dispatch(TerminalEvent terminalEvent); /** * Register {@link Disposable} to get disposed when event loop terminates. @@ -188,20 +186,20 @@ interface EventLoopProcessor { /** * Checks if this processor can process an event. If this method returns - * {@code true} it's quaranteed that {@link #process(Message)} is called to + * {@code true} it's quaranteed that {@link #process(TerminalEvent)} is called to * resolve translation of a message. - * @param message the message + * @param terminalEvent the message * @return true if processor can process an event */ - boolean canProcess(Message message); + boolean canProcess(TerminalEvent terminalEvent); /** - * Process a message and transform it into a new {@link Flux} of {@link Message} - * instances. - * @param message the message to process + * Process a message and transform it into a new {@link Flux} of + * {@link TerminalEvent} instances. + * @param terminalEvent the message to process * @return a flux of messages */ - Flux> process(Message message); + Flux> process(TerminalEvent terminalEvent); } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/AnimationEventLoopProcessor.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/AnimationEventLoopProcessor.java index 7ede15257..19e07d2f9 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/AnimationEventLoopProcessor.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/AnimationEventLoopProcessor.java @@ -19,10 +19,7 @@ import reactor.core.publisher.Flux; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.shell.jline.tui.component.message.ShellMessageHeaderAccessor; -import org.springframework.shell.jline.tui.component.message.StaticShellMessageHeaderAccessor; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.event.EventLoop; import org.springframework.shell.jline.tui.component.view.event.EventLoop.EventLoopProcessor; @@ -30,29 +27,21 @@ * {@link EventLoopProcessor} converting incoming message into animation tick messages. * * @author Janne Valkealahti + * @author Piotr Olaszewski */ public class AnimationEventLoopProcessor implements EventLoopProcessor { @Override - public boolean canProcess(Message message) { - if (EventLoop.Type.SYSTEM.equals(StaticShellMessageHeaderAccessor.getEventType(message))) { - if (message.getHeaders().containsKey("animationstart")) { - return true; - } + public boolean canProcess(TerminalEvent terminalEvent) { + if (EventLoop.Type.SYSTEM == terminalEvent.type()) { + return true; } return false; } @Override - public Flux> process(Message message) { - return Flux.range(0, 40).delayElements(Duration.ofMillis(100)).map(i -> { - return MessageBuilder.withPayload(i) - .setHeader(ShellMessageHeaderAccessor.EVENT_TYPE, EventLoop.Type.SYSTEM) - .setHeader("animationtick", true) - .setHeader("animationfrom", 0) - .setHeader("animationto", 9) - .build(); - }); + public Flux> process(TerminalEvent terminalEvent) { + return Flux.range(0, 40).delayElements(Duration.ofMillis(100)).map(i -> terminalEvent); } } diff --git a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/TaskEventLoopProcessor.java b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/TaskEventLoopProcessor.java index 25b42772b..8ff75b34c 100644 --- a/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/TaskEventLoopProcessor.java +++ b/spring-shell-jline/src/main/java/org/springframework/shell/jline/tui/component/view/event/processor/TaskEventLoopProcessor.java @@ -18,20 +18,21 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.shell.jline.tui.component.message.StaticShellMessageHeaderAccessor; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.event.EventLoop; -import org.springframework.shell.jline.tui.component.view.event.KeyBindingConsumerArgs; import org.springframework.shell.jline.tui.component.view.event.EventLoop.EventLoopProcessor; +import org.springframework.shell.jline.tui.component.view.event.KeyBindingConsumerArgs; import org.springframework.shell.jline.tui.component.view.event.MouseBindingConsumerArgs; +/** + * @author Piotr Olaszewski + */ public class TaskEventLoopProcessor implements EventLoopProcessor { @Override - public boolean canProcess(Message message) { - if (EventLoop.Type.TASK.equals(StaticShellMessageHeaderAccessor.getEventType(message))) { - Object payload = message.getPayload(); + public boolean canProcess(TerminalEvent terminalEvent) { + if (EventLoop.Type.TASK == terminalEvent.type()) { + Object payload = terminalEvent.payload(); if (payload instanceof Runnable) { return true; } @@ -46,46 +47,42 @@ else if (payload instanceof MouseBindingConsumerArgs) { } @Override - public Flux> process(Message message) { - Object payload = message.getPayload(); + public Flux> process(TerminalEvent terminalEvent) { + Object payload = terminalEvent.payload(); if (payload instanceof Runnable) { - return processRunnable(message); + return processRunnable(terminalEvent); } else if (payload instanceof KeyBindingConsumerArgs) { - return processKeyConsumer(message); + return processKeyConsumer(terminalEvent); } else if (payload instanceof MouseBindingConsumerArgs) { - return processMouseConsumer(message); + return processMouseConsumer(terminalEvent); } // should not happen throw new IllegalArgumentException(); } - private Flux> processRunnable(Message message) { - return Mono.just(message.getPayload()) + private Flux> processRunnable(TerminalEvent terminalEvent) { + return Mono.just(terminalEvent.payload()) .ofType(Runnable.class) .flatMap(Mono::fromRunnable) - .then(Mono.just(MessageBuilder.withPayload(new Object()).build())) + .then(Mono.just(new TerminalEvent<>(new Object(), terminalEvent.type()))) .flux(); } - private Flux> processMouseConsumer(Message message) { - return Mono.just(message.getPayload()) + private Flux> processMouseConsumer(TerminalEvent terminalEvent) { + return Mono.just(terminalEvent.payload()) .ofType(MouseBindingConsumerArgs.class) - .flatMap(args -> Mono.fromRunnable(() -> { - args.consumer().accept(args.event()); - })) - .then(Mono.just(MessageBuilder.withPayload(new Object()).build())) + .flatMap(args -> Mono.fromRunnable(() -> args.consumer().accept(args.event()))) + .then(Mono.just(new TerminalEvent<>(new Object(), terminalEvent.type()))) .flux(); } - private Flux> processKeyConsumer(Message message) { - return Mono.just(message.getPayload()) + private Flux> processKeyConsumer(TerminalEvent terminalEvent) { + return Mono.just(terminalEvent.payload()) .ofType(KeyBindingConsumerArgs.class) - .flatMap(args -> Mono.fromRunnable(() -> { - args.consumer().accept(args.event()); - })) - .then(Mono.just(MessageBuilder.withPayload(new Object()).build())) + .flatMap(args -> Mono.fromRunnable(() -> args.consumer().accept(args.event()))) + .then(Mono.just(new TerminalEvent<>(new Object(), terminalEvent.type()))) .flux(); } diff --git a/spring-shell-jline/src/test/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoopTests.java b/spring-shell-jline/src/test/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoopTests.java index 2dd703f06..12c465a7b 100644 --- a/spring-shell-jline/src/test/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoopTests.java +++ b/spring-shell-jline/src/test/java/org/springframework/shell/jline/tui/component/view/event/DefaultEventLoopTests.java @@ -18,21 +18,19 @@ import java.time.Duration; import java.util.EnumSet; import java.util.List; +import java.util.Map; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.shell.jline.tui.component.message.ShellMessageBuilder; +import org.springframework.shell.jline.tui.component.TerminalEvent; import org.springframework.shell.jline.tui.component.view.event.EventLoop.EventLoopProcessor; - -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; class DefaultEventLoopTests { @@ -61,24 +59,24 @@ private void initDefault() { @Test void eventsGetIntoSingleSubscriber() { initDefault(); - Message message = MessageBuilder.withPayload("TEST").build(); + TerminalEvent terminalEvent = new TerminalEvent<>("TEST", EventLoop.Type.SIGNAL); StepVerifier verifier1 = StepVerifier.create(loop.events()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); } @Test void eventsGetIntoMultipleSubscriber() { initDefault(); - Message message = MessageBuilder.withPayload("TEST").build(); + TerminalEvent terminalEvent = new TerminalEvent<>("TEST", EventLoop.Type.SIGNAL); StepVerifier verifier1 = StepVerifier.create(loop.events()).expectNextCount(1).thenCancel().verifyLater(); StepVerifier verifier2 = StepVerifier.create(loop.events()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); verifier2.verify(Duration.ofSeconds(1)); } @@ -86,8 +84,8 @@ void eventsGetIntoMultipleSubscriber() { @Test void canDispatchFlux() { initDefault(); - Message message = MessageBuilder.withPayload("TEST").build(); - Flux> flux = Flux.just(message); + TerminalEvent terminalEvent = new TerminalEvent<>("TEST", EventLoop.Type.SIGNAL); + Flux> flux = Flux.just(terminalEvent); StepVerifier verifier1 = StepVerifier.create(loop.events()).expectNextCount(1).thenCancel().verifyLater(); @@ -98,8 +96,8 @@ void canDispatchFlux() { @Test void canDispatchMono() { initDefault(); - Message message = MessageBuilder.withPayload("TEST").build(); - Mono> mono = Mono.just(message); + TerminalEvent terminalEvent = new TerminalEvent<>("TEST", EventLoop.Type.SIGNAL); + Mono> mono = Mono.just(terminalEvent); StepVerifier verifier1 = StepVerifier.create(loop.events()).expectNextCount(1).thenCancel().verifyLater(); @@ -110,9 +108,9 @@ void canDispatchMono() { @Test void dispatchNoSubscribersDoesNotError() { initDefault(); - Message message = MessageBuilder.withPayload("TEST").build(); + TerminalEvent terminalEvent = new TerminalEvent<>("TEST", EventLoop.Type.SIGNAL); - loop.dispatch(message); + loop.dispatch(terminalEvent); } @Test @@ -129,14 +127,14 @@ static class TestEventLoopProcessor implements EventLoopProcessor { int count; @Override - public boolean canProcess(Message message) { + public boolean canProcess(TerminalEvent terminalEvent) { return true; } @Override - public Flux> process(Message message) { - Message m = MessageBuilder.fromMessage(message).setHeader("count", count++).build(); - return Flux.just(m); + public Flux> process(TerminalEvent terminalEvent) { + return Flux.just(new TerminalEvent<>(terminalEvent.payload(), EventLoop.Type.SIGNAL, null, + Map.of("count", count++))); } } @@ -147,17 +145,17 @@ void processorCreatesSameMessagesForAll() { loop = new DefaultEventLoop(List.of(processor)); StepVerifier verifier1 = StepVerifier.create(loop.events()).assertNext(m -> { - Integer count = m.getHeaders().get("count", Integer.class); + Integer count = (Integer) m.attributes().get("count"); assertThat(count).isZero(); }).thenCancel().verifyLater(); StepVerifier verifier2 = StepVerifier.create(loop.events()).assertNext(m -> { - Integer count = m.getHeaders().get("count", Integer.class); + Integer count = (Integer) m.attributes().get("count"); assertThat(count).isZero(); }).thenCancel().verifyLater(); - Message message = MessageBuilder.withPayload("TEST").build(); - loop.dispatch(message); + TerminalEvent terminalEvent = new TerminalEvent<>("TEST", EventLoop.Type.SIGNAL); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); verifier2.verify(Duration.ofSeconds(1)); } @@ -166,9 +164,9 @@ void processorCreatesSameMessagesForAll() { void taskRunnableShouldExecute() { initDefault(); TestRunnable task = new TestRunnable(); - Message message = ShellMessageBuilder.withPayload(task).setEventType(EventLoop.Type.TASK).build(); + TerminalEvent terminalEvent = new TerminalEvent<>(task, EventLoop.Type.TASK); StepVerifier verifier1 = StepVerifier.create(loop.events()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); assertThat(task.count).isEqualTo(1); } @@ -189,11 +187,11 @@ void keyEvents() { initDefault(); KeyEvent event = KeyEvent.of(KeyEvent.Key.a); - Message message = ShellMessageBuilder.ofKeyEvent(event); + TerminalEvent terminalEvent = new TerminalEvent<>(event, EventLoop.Type.KEY); StepVerifier verifier1 = StepVerifier.create(loop.keyEvents()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); } @@ -205,11 +203,11 @@ void mouseEvents() { org.jline.terminal.MouseEvent.Type.Released, org.jline.terminal.MouseEvent.Button.Button1, EnumSet.noneOf(org.jline.terminal.MouseEvent.Modifier.class), 0, 0); MouseEvent event = MouseEvent.of(jlineMouseEvent); - Message message = ShellMessageBuilder.ofMouseEvent(event); + TerminalEvent terminalEvent = new TerminalEvent<>(event, EventLoop.Type.MOUSE); StepVerifier verifier1 = StepVerifier.create(loop.mouseEvents()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); } @@ -217,11 +215,11 @@ void mouseEvents() { void systemEvents() { initDefault(); - Message message = ShellMessageBuilder.ofRedraw(); + TerminalEvent terminalEvent = new TerminalEvent<>("redraw", EventLoop.Type.SYSTEM); StepVerifier verifier1 = StepVerifier.create(loop.systemEvents()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); } @@ -229,11 +227,11 @@ void systemEvents() { void signalEvents() { initDefault(); - Message message = ShellMessageBuilder.ofSignal("WINCH"); + TerminalEvent terminalEvent = new TerminalEvent<>("WINCH", EventLoop.Type.SIGNAL); StepVerifier verifier1 = StepVerifier.create(loop.signalEvents()).expectNextCount(1).thenCancel().verifyLater(); - loop.dispatch(message); + loop.dispatch(terminalEvent); verifier1.verify(Duration.ofSeconds(1)); }