├── LICENSE ├── composer.json └── src └── Spinner ├── Asynchronous ├── React │ ├── ReactLoopAdapter.php │ ├── ReactLoopCreator.php │ └── ReactLoopProbe.php ├── Revolt │ ├── RevoltLoopAdapter.php │ ├── RevoltLoopCreator.php │ └── RevoltLoopProbe.php └── bootstrap.php ├── Container ├── A │ └── AContainerEnclosure.php ├── Adapter │ └── ContainerAdapter.php ├── Builder │ ├── ServiceBuilder.php │ └── ServiceSpawnerBuilder.php ├── CircularDependencyDetector.php ├── Container.php ├── Contract │ ├── ICircularDependencyDetector.php │ ├── IContainer.php │ ├── IContainerFactory.php │ ├── IDefinitionRegistry.php │ ├── IIsStorableResolver.php │ ├── IService.php │ ├── IServiceBuilder.php │ ├── IServiceDefinition.php │ ├── IServiceFactory.php │ ├── IServiceSpawner.php │ ├── IServiceSpawnerBuilder.php │ └── IServiceSpawnerFactory.php ├── DefinitionRegistry.php ├── Exception │ ├── CircularDependencyDetected.php │ ├── ClassDoesNotExist.php │ ├── ContainerException.php │ ├── InvalidDefinitionArgument.php │ ├── InvalidOptionsArgument.php │ ├── NotFoundInContainer.php │ ├── SpawnFailed.php │ ├── SpawnerException.php │ ├── UnableToCreateInstance.php │ └── UnableToExtractType.php ├── Factory │ ├── ContainerFactory.php │ ├── ServiceFactory.php │ └── ServiceSpawnerFactory.php ├── Service.php ├── ServiceDefinition.php ├── ServiceIsStorableResolver.php └── ServiceSpawner.php ├── Contract ├── ICreator.php ├── IDeltaTimer.php ├── IFinalizable.php ├── IFrame.php ├── IHasEmptyState.php ├── IHasFrame.php ├── IHasInterval.php ├── IHasIsEnabled.php ├── IHasNullableInterval.php ├── IInitializable.php ├── IInterval.php ├── INowTimer.php ├── IObserver.php ├── IProcedure.php ├── IRenderable.php ├── ISubject.php ├── Mode │ ├── AutoStartMode.php │ ├── CursorVisibilityMode.php │ ├── DriverMode.php │ ├── InitializationMode.php │ ├── LinkerMode.php │ ├── NormalizerMode.php │ ├── RunMethodMode.php │ ├── SignalHandlingMode.php │ └── StylingMethodMode.php ├── Option │ ├── AutoStartOption.php │ ├── CursorVisibilityOption.php │ ├── DriverOption.php │ ├── InitializationOption.php │ ├── LinkerOption.php │ ├── NormalizerOption.php │ ├── RunMethodOption.php │ ├── SignalHandlingOption.php │ └── StylingMethodOption.php ├── Output │ ├── IBufferedOutput.php │ ├── IOutput.php │ └── IWritableStream.php ├── Pattern │ ├── IPattern.php │ └── IProceduralPattern.php └── Probe │ ├── ISignalHandlingOptionCreator.php │ ├── ISignalHandlingProbe.php │ ├── IStaticProbe.php │ ├── IStylingMethodOptionCreator.php │ └── IStylingMethodProbe.php ├── Core ├── A │ ├── ADriver.php │ ├── AFrame.php │ └── ASubject.php ├── Builder │ ├── ConsoleCursorBuilder.php │ ├── Contract │ │ ├── IConsoleCursorBuilder.php │ │ ├── IDeltaTimerBuilder.php │ │ ├── IIntegerNormalizerBuilder.php │ │ ├── ISequenceStateBuilder.php │ │ └── ISequenceStateWriterBuilder.php │ ├── DeltaTimerBuilder.php │ ├── DriverBuilder.php │ ├── IntegerNormalizerBuilder.php │ ├── SequenceStateBuilder.php │ └── SequenceStateWriterBuilder.php ├── CharFrame.php ├── Config │ ├── Builder │ │ ├── DriverConfigBuilder.php │ │ ├── GeneralConfigBuilder.php │ │ ├── LinkerConfigBuilder.php │ │ ├── LoopConfigBuilder.php │ │ ├── NormalizerConfigBuilder.php │ │ ├── OutputConfigBuilder.php │ │ ├── RevolverConfigBuilder.php │ │ └── WidgetRevolverConfigBuilder.php │ ├── Contract │ │ ├── Builder │ │ │ ├── IDriverConfigBuilder.php │ │ │ ├── IGeneralConfigBuilder.php │ │ │ ├── ILinkerConfigBuilder.php │ │ │ ├── ILoopConfigBuilder.php │ │ │ ├── INormalizerConfigBuilder.php │ │ │ ├── IOutputConfigBuilder.php │ │ │ ├── IRevolverConfigBuilder.php │ │ │ └── IWidgetRevolverConfigBuilder.php │ │ ├── Detector │ │ │ ├── IAutoStartModeDetector.php │ │ │ ├── IDriverModeDetector.php │ │ │ ├── IInitializationModeDetector.php │ │ │ └── ILinkerModeDetector.php │ │ ├── Factory │ │ │ ├── IDriverConfigFactory.php │ │ │ ├── IGeneralConfigFactory.php │ │ │ ├── IInitialRootWidgetConfigFactory.php │ │ │ ├── IInitialWidgetConfigFactory.php │ │ │ ├── ILinkerConfigFactory.php │ │ │ ├── ILoopConfigFactory.php │ │ │ ├── INormalizerConfigFactory.php │ │ │ ├── IOutputConfigFactory.php │ │ │ ├── IRevolverConfigFactory.php │ │ │ ├── IRootWidgetConfigFactory.php │ │ │ └── IWidgetConfigFactory.php │ │ ├── IConfigElement.php │ │ ├── IDriverConfig.php │ │ ├── IGeneralConfig.php │ │ ├── ILinkerConfig.php │ │ ├── ILoopConfig.php │ │ ├── INormalizerConfig.php │ │ ├── IOutputConfig.php │ │ ├── IRevolverConfig.php │ │ ├── IRootWidgetConfig.php │ │ ├── IWidgetConfig.php │ │ └── IWidgetRevolverConfig.php │ ├── Detector │ │ ├── AutoStartModeDetector.php │ │ ├── DriverModeDetector.php │ │ ├── InitializationModeDetector.php │ │ └── LinkerModeDetector.php │ ├── DriverConfig.php │ ├── Factory │ │ ├── DriverConfigFactory.php │ │ ├── GeneralConfigFactory.php │ │ ├── InitialRootWidgetConfigFactory.php │ │ ├── InitialWidgetConfigFactory.php │ │ ├── LinkerConfigFactory.php │ │ ├── LoopConfigFactory.php │ │ ├── NormalizerConfigFactory.php │ │ ├── OutputConfigFactory.php │ │ ├── RevolverConfigFactory.php │ │ ├── RootWidgetConfigFactory.php │ │ └── WidgetConfigFactory.php │ ├── GeneralConfig.php │ ├── LinkerConfig.php │ ├── LoopConfig.php │ ├── NormalizerConfig.php │ ├── OutputConfig.php │ ├── RevolverConfig.php │ ├── RootWidgetConfig.php │ ├── Solver │ │ ├── A │ │ │ └── ASolver.php │ │ ├── AutoStartModeSolver.php │ │ ├── Contract │ │ │ ├── IAutoStartModeSolver.php │ │ │ ├── ICursorVisibilityModeSolver.php │ │ │ ├── IDriverMessagesSolver.php │ │ │ ├── IDriverModeSolver.php │ │ │ ├── IInitializationModeSolver.php │ │ │ ├── ILinkerModeSolver.php │ │ │ ├── INormalizerModeSolver.php │ │ │ ├── IRootWidgetSettingsSolver.php │ │ │ ├── IRunMethodModeSolver.php │ │ │ ├── ISignalHandlersContainerSolver.php │ │ │ ├── ISignalHandlingModeSolver.php │ │ │ ├── ISolver.php │ │ │ ├── IStreamSolver.php │ │ │ ├── IStylingMethodModeSolver.php │ │ │ ├── IToleranceSolver.php │ │ │ └── IWidgetSettingsSolver.php │ │ ├── CursorVisibilityModeSolver.php │ │ ├── DriverMessagesSolver.php │ │ ├── DriverModeSolver.php │ │ ├── InitializationModeSolver.php │ │ ├── LinkerModeSolver.php │ │ ├── NormalizerModeSolver.php │ │ ├── RootWidgetSettingsSolver.php │ │ ├── RunMethodModeSolver.php │ │ ├── SignalHandlersContainerSolver.php │ │ ├── SignalHandlingModeSolver.php │ │ ├── StreamSolver.php │ │ ├── StylingMethodModeSolver.php │ │ ├── ToleranceSolver.php │ │ └── WidgetSettingsSolver.php │ ├── WidgetConfig.php │ └── WidgetRevolverConfig.php ├── Contract │ ├── ICharFrame.php │ ├── IDriver.php │ ├── IDriverBuilder.php │ ├── IDriverLinker.php │ ├── IDriverMessages.php │ ├── IDriverProvider.php │ ├── IDriverSetup.php │ ├── IFrameCollection.php │ ├── IIntegerNormalizer.php │ ├── IIntervalComparator.php │ ├── IIntervalNormalizer.php │ ├── IPoint.php │ ├── IPositionedSequenceState.php │ ├── IRenderer.php │ ├── ISequenceState.php │ ├── ISignalHandlersContainer.php │ ├── ISignalHandlingSetup.php │ ├── ISpinner.php │ ├── IStyleFrame.php │ ├── ITolerance.php │ └── IWeakMap.php ├── DeltaTimer.php ├── Driver.php ├── Driver │ └── Renderer.php ├── DriverLinker.php ├── DriverMessages.php ├── DriverProvider.php ├── DriverSetup.php ├── DummyDriverLinker.php ├── DummySignalHandlingSetup.php ├── Factory │ ├── A │ │ └── ADriverProviderFactory.php │ ├── CharFrameRevolverFactory.php │ ├── ConsoleCursorFactory.php │ ├── Contract │ │ ├── IAnsiColorConverterFactory.php │ │ ├── ICharFrameRevolverFactory.php │ │ ├── IConsoleCursorFactory.php │ │ ├── IDeltaTimerFactory.php │ │ ├── IDriverFactory.php │ │ ├── IDriverLinkerFactory.php │ │ ├── IDriverProviderFactory.php │ │ ├── IFrameCollectionFactory.php │ │ ├── IIntervalFactory.php │ │ ├── IIntervalNormalizerFactory.php │ │ ├── ILoopFactory.php │ │ ├── ILoopProviderFactory.php │ │ ├── ISequenceStateWriterFactory.php │ │ ├── ISignalHandlingSetupFactory.php │ │ ├── ISpinnerFactory.php │ │ └── IStyleFrameRevolverFactory.php │ ├── DeltaTimerFactory.php │ ├── DriverFactory.php │ ├── DriverLinkerFactory.php │ ├── DriverProviderFactory.php │ ├── FrameCollectionFactory.php │ ├── IntervalFactory.php │ ├── IntervalNormalizerFactory.php │ ├── SequenceStateWriterFactory.php │ ├── SignalHandlingSetupFactory.php │ ├── SpinnerFactory.php │ └── StyleFrameRevolverFactory.php ├── Feature │ └── Resolver │ │ ├── AutoStartResolver.php │ │ ├── Contract │ │ ├── IAutoStartResolver.php │ │ ├── IInitializationResolver.php │ │ └── ILinkerResolver.php │ │ ├── InitializationResolver.php │ │ └── LinkerResolver.php ├── FrameCollection.php ├── IntegerNormalizer.php ├── Interval.php ├── IntervalComparator.php ├── IntervalNormalizer.php ├── Loop │ ├── Contract │ │ ├── A │ │ │ ├── ALoopAdapter.php │ │ │ └── ALoopProbe.php │ │ ├── ILoop.php │ │ ├── ILoopCreator.php │ │ ├── ILoopCreatorClassExtractor.php │ │ ├── ILoopCreatorClassProvider.php │ │ ├── ILoopProbe.php │ │ ├── ILoopProvider.php │ │ └── ILoopSetup.php │ ├── Factory │ │ ├── LoopFactory.php │ │ └── LoopProviderFactory.php │ ├── LoopCreatorClassExtractor.php │ ├── LoopCreatorClassProvider.php │ ├── LoopProvider.php │ └── LoopSetup.php ├── Output │ ├── BufferedOutput.php │ ├── ConsoleCursor.php │ ├── Contract │ │ ├── Factory │ │ │ └── IResourceStreamFactory.php │ │ ├── IBuffer.php │ │ ├── IConsoleCursor.php │ │ └── ISequenceStateWriter.php │ ├── Factory │ │ └── ResourceStreamFactory.php │ ├── Output.php │ ├── SequenceStateWriter.php │ ├── StringBuffer.php │ └── WritableStream.php ├── Palette │ ├── A │ │ ├── ACharPalette.php │ │ ├── APalette.php │ │ └── AStylePalette.php │ ├── Contract │ │ ├── ICharPalette.php │ │ ├── IPalette.php │ │ ├── IPaletteMode.php │ │ ├── IPaletteOptions.php │ │ ├── IPaletteTemplate.php │ │ └── IStylePalette.php │ ├── Factory │ │ ├── Contract │ │ │ └── IPaletteModeFactory.php │ │ └── PaletteModeFactory.php │ ├── NoCharPalette.php │ ├── NoStylePalette.php │ ├── PaletteMode.php │ ├── PaletteOptions.php │ ├── PaletteTemplate.php │ ├── Rainbow.php │ └── Snake.php ├── Pattern │ ├── Factory │ │ ├── Contract │ │ │ └── IPatternFactory.php │ │ └── PatternFactory.php │ └── Pattern.php ├── Probe │ ├── SignalHandlingOptionCreator.php │ ├── SignalHandlingProbe.php │ ├── StylingMethodOptionCreator.php │ └── StylingMethodProbe.php ├── Revolver │ ├── A │ │ ├── ARevolver.php │ │ └── ARevolverBuilder.php │ ├── Contract │ │ ├── IFrameCollectionRevolver.php │ │ ├── IFrameRevolver.php │ │ ├── IFrameRevolverBuilder.php │ │ ├── IRevolver.php │ │ └── IRevolverBuilder.php │ ├── FrameCollectionRevolver.php │ ├── FrameRevolverBuilder.php │ └── Tolerance.php ├── SequenceState.php ├── Settings │ ├── Builder │ │ └── SettingsProviderBuilder.php │ ├── Contract │ │ ├── Builder │ │ │ └── ISettingsProviderBuilder.php │ │ ├── Detector │ │ │ ├── IDetector.php │ │ │ ├── ILoopSupportDetector.php │ │ │ ├── ISignalHandlingSupportDetector.php │ │ │ └── IStylingMethodDetector.php │ │ ├── Factory │ │ │ ├── IDefaultSettingsFactory.php │ │ │ ├── IDetectedSettingsFactory.php │ │ │ ├── ISettingsProviderFactory.php │ │ │ └── IUserSettingsFactory.php │ │ ├── IDriverSettings.php │ │ ├── IGeneralSettings.php │ │ ├── IHandlerCreator.php │ │ ├── ILinkerSettings.php │ │ ├── ILoopSettings.php │ │ ├── IMessages.php │ │ ├── INormalizerSettings.php │ │ ├── IOutputSettings.php │ │ ├── IRevolverSettings.php │ │ ├── IRootWidgetSettings.php │ │ ├── ISettings.php │ │ ├── ISettingsElement.php │ │ ├── ISettingsProvider.php │ │ ├── ISignalHandlerCreator.php │ │ ├── ISignalHandlerSettings.php │ │ ├── ISpinnerSettings.php │ │ └── IWidgetSettings.php │ ├── Detector │ │ ├── LoopSupportDetector.php │ │ ├── SignalHandlingSupportDetector.php │ │ └── StylingMethodDetector.php │ ├── DriverSettings.php │ ├── Factory │ │ ├── DefaultSettingsFactory.php │ │ ├── DetectedSettingsFactory.php │ │ ├── SettingsProviderFactory.php │ │ └── UserSettingsFactory.php │ ├── GeneralSettings.php │ ├── LinkerSettings.php │ ├── LoopSettings.php │ ├── Messages.php │ ├── NormalizerSettings.php │ ├── OutputSettings.php │ ├── RevolverSettings.php │ ├── RootWidgetSettings.php │ ├── Settings.php │ ├── SettingsProvider.php │ ├── SignalHandlerCreator.php │ ├── SignalHandlerSettings.php │ ├── SpinnerSettings.php │ └── WidgetSettings.php ├── SignalHandlersContainer.php ├── SignalHandlingSetup.php ├── Spinner.php ├── StyleFrame.php └── Widget │ ├── A │ └── AWidget.php │ ├── Builder │ ├── A │ │ └── AWidgetBuilder.php │ ├── WidgetBuilder.php │ └── WidgetRevolverBuilder.php │ ├── Contract │ ├── IHasWidgetContext.php │ ├── IWidget.php │ ├── IWidgetBuilder.php │ ├── IWidgetComposite.php │ ├── IWidgetContext.php │ ├── IWidgetRevolver.php │ └── IWidgetRevolverBuilder.php │ ├── Factory │ ├── Contract │ │ ├── IWidgetFactory.php │ │ └── IWidgetRevolverFactory.php │ ├── WidgetFactory.php │ └── WidgetRevolverFactory.php │ ├── Widget.php │ └── WidgetRevolver.php ├── Exception ├── DomainException.php ├── DriverCanNotBeReplaced.php ├── InvalidArgument.php ├── LogicException.php ├── LoopException.php ├── NotImplemented.php ├── ObserverCanNotBeOverwritten.php ├── RuntimeException.php └── WidgetIsNotAComposite.php ├── Facade.php ├── Probes.php ├── Root ├── A │ └── AFacade.php ├── Contract │ └── IFacade.php └── definitions.php └── bootstrap.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alec 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Spinner/Asynchronous/React/ReactLoopCreator.php: -------------------------------------------------------------------------------- 1 | container->get($id); 26 | } 27 | 28 | /** @inheritDoc */ 29 | public function has(string $id): bool 30 | { 31 | return $this->container->has($id); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Spinner/Container/CircularDependencyDetector.php: -------------------------------------------------------------------------------- 1 | stack->getArrayCopy(), true)) { 23 | throw new CircularDependencyDetected($this->stack); 24 | } 25 | 26 | $this->stack->append($id); 27 | } 28 | 29 | public function pop(): void 30 | { 31 | $key = array_key_last($this->stack->getArrayCopy()); 32 | 33 | if ($key !== null && $this->stack->offsetExists($key)) { 34 | $this->stack->offsetUnset($key); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Spinner/Container/Contract/ICircularDependencyDetector.php: -------------------------------------------------------------------------------- 1 | $id 19 | * 20 | * @psalm-return T 21 | * 22 | * @throws ContainerExceptionInterface Error while retrieving the entry. 23 | * @throws NotFoundExceptionInterface No entry was found for **this** identifier. 24 | * 25 | * @psalm-suppress MoreSpecificImplementedParamType 26 | */ 27 | public function get(string $id); 28 | 29 | public function has(string $id): bool; 30 | } 31 | -------------------------------------------------------------------------------- /src/Spinner/Container/Contract/IContainerFactory.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function load(): Traversable; 15 | 16 | public function bind(IServiceDefinition ...$serviceDefinitions): void; 17 | } 18 | -------------------------------------------------------------------------------- /src/Spinner/Container/Contract/IIsStorableResolver.php: -------------------------------------------------------------------------------- 1 | */ 17 | private readonly ArrayObject $definitions; 18 | 19 | private function __construct( 20 | ArrayObject $definitions = new ArrayObject(), 21 | ) { 22 | /** @var ArrayObject $definitions */ 23 | $this->definitions = $definitions; 24 | } 25 | 26 | public static function getInstance(): IDefinitionRegistry 27 | { 28 | if (self::$instance === null) { 29 | self::$instance = new self(); 30 | } 31 | return self::$instance; 32 | } 33 | 34 | public function load(): Traversable 35 | { 36 | yield from $this->definitions; 37 | } 38 | 39 | public function bind(IServiceDefinition ...$serviceDefinitions): void 40 | { 41 | foreach ($serviceDefinitions as $serviceDefinition) { 42 | $this->definitions->offsetSet($serviceDefinition->getId(), $serviceDefinition); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Spinner/Container/Exception/CircularDependencyDetected.php: -------------------------------------------------------------------------------- 1 | formatStack($dependencyStack); 18 | parent::__construct($message, previous: $previous); 19 | } 20 | 21 | private function formatStack(ArrayObject $stack): string 22 | { 23 | /** @psalm-suppress MixedArgumentTypeCoercion */ 24 | return PHP_EOL . implode(' ➜ ', $stack->getArrayCopy()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Spinner/Container/Exception/ClassDoesNotExist.php: -------------------------------------------------------------------------------- 1 | spawnerFactory, 24 | definitions: $definitionRegistry->load(), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Spinner/Container/Factory/ServiceFactory.php: -------------------------------------------------------------------------------- 1 | getId(); 26 | $isStorable = $this->isStorableResolver->isStorable($serviceDefinition); 27 | 28 | return $this->serviceBuilder 29 | ->withValue($value) 30 | ->withId($id) 31 | ->withIsStorable($isStorable) 32 | ->build() 33 | ; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Spinner/Container/Service.php: -------------------------------------------------------------------------------- 1 | value; 21 | } 22 | 23 | public function isStorable(): bool 24 | { 25 | return $this->storable; 26 | } 27 | 28 | public function getId(): string 29 | { 30 | return $this->id; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Spinner/Container/ServiceIsStorableResolver.php: -------------------------------------------------------------------------------- 1 | getOptions() === IServiceDefinition::SINGLETON; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Spinner/Contract/ICreator.php: -------------------------------------------------------------------------------- 1 | |string $messages 18 | */ 19 | public function append(iterable|string $messages): IBufferedOutput; 20 | } 21 | -------------------------------------------------------------------------------- /src/Spinner/Contract/Output/IOutput.php: -------------------------------------------------------------------------------- 1 | $data 13 | */ 14 | public function write(Traversable $data): void; 15 | } 16 | -------------------------------------------------------------------------------- /src/Spinner/Contract/Pattern/IPattern.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | public static function getCreatorClass(): string; 17 | } 18 | -------------------------------------------------------------------------------- /src/Spinner/Contract/Probe/IStylingMethodOptionCreator.php: -------------------------------------------------------------------------------- 1 | sequence; 20 | } 21 | 22 | public function getWidth(): int 23 | { 24 | return $this->width; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Spinner/Core/Builder/Contract/IConsoleCursorBuilder.php: -------------------------------------------------------------------------------- 1 | validate(); 23 | 24 | return new GeneralConfig( 25 | runMethodMode: $this->runMethodMode, 26 | ); 27 | } 28 | 29 | private function validate(): void 30 | { 31 | match (true) { 32 | $this->runMethodMode === null => throw new LogicException('RunMethodMode is not set.'), 33 | default => null, 34 | }; 35 | } 36 | 37 | public function withRunMethodMode(RunMethodMode $runMethodMode): IGeneralConfigBuilder 38 | { 39 | $clone = clone $this; 40 | $clone->runMethodMode = $runMethodMode; 41 | return $clone; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Builder/LinkerConfigBuilder.php: -------------------------------------------------------------------------------- 1 | validate(); 23 | 24 | return new LinkerConfig( 25 | linkerMode: $this->linkerMode, 26 | ); 27 | } 28 | 29 | /** 30 | * @throws LogicException 31 | */ 32 | private function validate(): void 33 | { 34 | match (true) { 35 | $this->linkerMode === null => throw new LogicException('LinkerMode is not set.'), 36 | default => null, 37 | }; 38 | } 39 | 40 | public function withLinkerMode(LinkerMode $linkerMode): ILinkerConfigBuilder 41 | { 42 | $clone = clone $this; 43 | $clone->linkerMode = $linkerMode; 44 | return $clone; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Builder/NormalizerConfigBuilder.php: -------------------------------------------------------------------------------- 1 | validate(); 23 | 24 | return new NormalizerConfig( 25 | normalizerMode: $this->normalizerMode, 26 | ); 27 | } 28 | 29 | private function validate(): void 30 | { 31 | match (true) { 32 | $this->normalizerMode === null => throw new LogicException('NormalizerMode is not set.'), 33 | default => null, 34 | }; 35 | } 36 | 37 | public function withNormalizerMode(NormalizerMode $normalizerMode): INormalizerConfigBuilder 38 | { 39 | $clone = clone $this; 40 | $clone->normalizerMode = $normalizerMode; 41 | return $clone; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Builder/RevolverConfigBuilder.php: -------------------------------------------------------------------------------- 1 | validate(); 23 | 24 | return new RevolverConfig( 25 | tolerance: $this->tolerance, 26 | ); 27 | } 28 | 29 | /** 30 | * @throws LogicException 31 | */ 32 | private function validate(): void 33 | { 34 | match (true) { 35 | $this->tolerance === null => throw new LogicException('Tolerance is not set.'), 36 | default => null, 37 | }; 38 | } 39 | 40 | public function withTolerance(ITolerance $tolerance): IRevolverConfigBuilder 41 | { 42 | $clone = clone $this; 43 | $clone->tolerance = $tolerance; 44 | return $clone; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Contract/Builder/IDriverConfigBuilder.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | public function getIdentifier(): string; 13 | } 14 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Contract/IDriverConfig.php: -------------------------------------------------------------------------------- 1 | loopConfig->getAutoStartMode() === AutoStartMode::ENABLED; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Detector/DriverModeDetector.php: -------------------------------------------------------------------------------- 1 | driverConfig->getDriverMode() === DriverMode::ENABLED; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Detector/InitializationModeDetector.php: -------------------------------------------------------------------------------- 1 | outputConfig->getInitializationMode() === InitializationMode::ENABLED; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Detector/LinkerModeDetector.php: -------------------------------------------------------------------------------- 1 | linkerConfig->getLinkerMode() === LinkerMode::ENABLED; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/DriverConfig.php: -------------------------------------------------------------------------------- 1 | driverMessages; 27 | } 28 | 29 | public function getDriverMode(): DriverMode 30 | { 31 | return $this->driverMode; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Factory/DriverConfigFactory.php: -------------------------------------------------------------------------------- 1 | driverConfigBuilder 25 | ->withDriverMessages( 26 | $this->driverMessagesSolver->solve() 27 | ) 28 | ->withDriverMode( 29 | $this->driverModeSolver->solve() 30 | ) 31 | ->build() 32 | ; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Factory/GeneralConfigFactory.php: -------------------------------------------------------------------------------- 1 | generalConfigBuilder 23 | ->withRunMethodMode( 24 | $this->runMethodModeSolver->solve() 25 | ) 26 | ->build() 27 | ; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Factory/LinkerConfigFactory.php: -------------------------------------------------------------------------------- 1 | linkerConfigBuilder 23 | ->withLinkerMode( 24 | $this->linkerModeSolver->solve(), 25 | ) 26 | ->build() 27 | ; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Factory/NormalizerConfigFactory.php: -------------------------------------------------------------------------------- 1 | normalizerConfigBuilder 23 | ->withNormalizerMode( 24 | $this->normalizerModeSolver->solve() 25 | ) 26 | ->build() 27 | ; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Factory/RevolverConfigFactory.php: -------------------------------------------------------------------------------- 1 | revolverConfigBuilder 23 | ->withTolerance( 24 | $this->toleranceSolver->solve() 25 | ) 26 | ->build() 27 | ; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/GeneralConfig.php: -------------------------------------------------------------------------------- 1 | runMethodMode; 20 | } 21 | 22 | /** 23 | * @return class-string 24 | */ 25 | public function getIdentifier(): string 26 | { 27 | return IGeneralConfig::class; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/LinkerConfig.php: -------------------------------------------------------------------------------- 1 | linkerMode; 20 | } 21 | 22 | /** 23 | * @return class-string 24 | */ 25 | public function getIdentifier(): string 26 | { 27 | return ILinkerConfig::class; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/LoopConfig.php: -------------------------------------------------------------------------------- 1 | autoStartMode; 24 | } 25 | 26 | public function getSignalHandlingMode(): SignalHandlingMode 27 | { 28 | return $this->signalHandlersMode; 29 | } 30 | 31 | /** 32 | * @return class-string 33 | */ 34 | public function getIdentifier(): string 35 | { 36 | return ILoopConfig::class; 37 | } 38 | 39 | public function getSignalHandlersContainer(): ISignalHandlersContainer 40 | { 41 | return $this->signalHandlersContainer; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/NormalizerConfig.php: -------------------------------------------------------------------------------- 1 | normalizerMode; 20 | } 21 | 22 | /** 23 | * @return class-string 24 | */ 25 | public function getIdentifier(): string 26 | { 27 | return INormalizerConfig::class; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/OutputConfig.php: -------------------------------------------------------------------------------- 1 | stylingMethodMode; 25 | } 26 | 27 | public function getCursorVisibilityMode(): CursorVisibilityMode 28 | { 29 | return $this->cursorVisibilityMode; 30 | } 31 | 32 | public function getInitializationMode(): InitializationMode 33 | { 34 | return $this->initializationMode; 35 | } 36 | 37 | public function getStream(): mixed 38 | { 39 | return $this->stream; 40 | } 41 | 42 | /** 43 | * @return class-string 44 | */ 45 | public function getIdentifier(): string 46 | { 47 | return IOutputConfig::class; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/RevolverConfig.php: -------------------------------------------------------------------------------- 1 | tolerance; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/RootWidgetConfig.php: -------------------------------------------------------------------------------- 1 | leadingSpacer; 23 | } 24 | 25 | public function getTrailingSpacer(): IFrame 26 | { 27 | return $this->trailingSpacer; 28 | } 29 | 30 | public function getWidgetRevolverConfig(): IWidgetRevolverConfig 31 | { 32 | return $this->revolverConfig; 33 | } 34 | 35 | /** 36 | * @return class-string 37 | */ 38 | public function getIdentifier(): string 39 | { 40 | return IRootWidgetConfig::class; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Solver/A/ASolver.php: -------------------------------------------------------------------------------- 1 | $id 26 | * 27 | * @psalm-return T|null 28 | */ 29 | protected function extractSettingsElement(ISettings $settings, string $id): ?ISettingsElement 30 | { 31 | return $settings->get($id); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/Solver/Contract/IAutoStartModeSolver.php: -------------------------------------------------------------------------------- 1 | doSolve( 17 | $this->extractStream($this->settingsProvider->getUserSettings()), 18 | $this->extractStream($this->settingsProvider->getDetectedSettings()), 19 | $this->extractStream($this->settingsProvider->getDefaultSettings()), 20 | ); 21 | } 22 | 23 | private function doSolve( 24 | mixed $userStream, 25 | mixed $detectedStream, 26 | mixed $defaultStream 27 | ): mixed { 28 | return $userStream 29 | ?? $detectedStream 30 | ?? $defaultStream 31 | ?? throw new InvalidArgument( 32 | 'Unable to solve "stream".' 33 | ); 34 | } 35 | 36 | protected function extractStream(ISettings $settings): mixed 37 | { 38 | return $this->extractSettingsElement($settings, IOutputSettings::class)?->getStream(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/WidgetConfig.php: -------------------------------------------------------------------------------- 1 | leadingSpacer; 23 | } 24 | 25 | public function getTrailingSpacer(): IFrame 26 | { 27 | return $this->trailingSpacer; 28 | } 29 | 30 | public function getWidgetRevolverConfig(): IWidgetRevolverConfig 31 | { 32 | return $this->revolverConfig; 33 | } 34 | 35 | /** 36 | * @return class-string 37 | */ 38 | public function getIdentifier(): string 39 | { 40 | return IWidgetConfig::class; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Spinner/Core/Config/WidgetRevolverConfig.php: -------------------------------------------------------------------------------- 1 | stylePalette; 23 | } 24 | 25 | public function getCharPalette(): IPalette 26 | { 27 | return $this->charPalette; 28 | } 29 | 30 | public function getRevolverConfig(): IRevolverConfig 31 | { 32 | return $this->revolverConfig; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Spinner/Core/Contract/ICharFrame.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | interface IFrameCollection extends Countable, ArrayAccess 17 | { 18 | /** 19 | * @psalm-return T 20 | */ 21 | public function get(int $index): IFrame; 22 | 23 | public function lastIndex(): int; 24 | } 25 | -------------------------------------------------------------------------------- /src/Spinner/Core/Contract/IIntegerNormalizer.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function getHandlerCreators(): Traversable; 16 | } 17 | -------------------------------------------------------------------------------- /src/Spinner/Core/Contract/ISignalHandlingSetup.php: -------------------------------------------------------------------------------- 1 | 16 | * @extends IteratorAggregate 17 | */ 18 | interface IWeakMap extends ArrayAccess, Countable, IteratorAggregate 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /src/Spinner/Core/DeltaTimer.php: -------------------------------------------------------------------------------- 1 | current = $startTime; 19 | } 20 | 21 | public function getDelta(): float 22 | { 23 | $last = $this->current; 24 | $this->current = $this->nowTimer->now(); 25 | return $this->current - $last; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Spinner/Core/DriverMessages.php: -------------------------------------------------------------------------------- 1 | finalMessage; 20 | } 21 | 22 | public function getInterruptionMessage(): string 23 | { 24 | return $this->interruptionMessage; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Spinner/Core/DriverProvider.php: -------------------------------------------------------------------------------- 1 | driver; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Spinner/Core/DriverSetup.php: -------------------------------------------------------------------------------- 1 | driverLinker->link($driver); 23 | 24 | $this->signalHandlingSetup->setup($driver); 25 | 26 | $driver->initialize(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Spinner/Core/DummyDriverLinker.php: -------------------------------------------------------------------------------- 1 | driverFactory->create(); 24 | 25 | $driverProvider = 26 | new DriverProvider( 27 | driver: $driver, 28 | ); 29 | 30 | $this->driverSetup->setup($driver); 31 | 32 | return $driverProvider; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Spinner/Core/Factory/ConsoleCursorFactory.php: -------------------------------------------------------------------------------- 1 | cursorBuilder 25 | ->withBuffer( 26 | $this->buffer 27 | ) 28 | ->withCursorVisibilityMode( 29 | $this->outputConfig->getCursorVisibilityMode() 30 | ) 31 | ->build() 32 | ; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Spinner/Core/Factory/Contract/IAnsiColorConverterFactory.php: -------------------------------------------------------------------------------- 1 | timerBuilder 24 | ->withStartTime($this->startTime) 25 | ->withNowTimer($this->nowTimer) 26 | ->build() 27 | ; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Spinner/Core/Factory/DriverLinkerFactory.php: -------------------------------------------------------------------------------- 1 | isLinkerEnabled()) { 25 | return new DriverLinker( 26 | loop: $this->loopProvider->getLoop(), 27 | ); 28 | } 29 | 30 | return new DummyDriverLinker(); 31 | } 32 | 33 | private function isLinkerEnabled(): bool 34 | { 35 | return $this->loopProvider->hasLoop() && $this->linkerResolver->isEnabled(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Spinner/Core/Factory/DriverProviderFactory.php: -------------------------------------------------------------------------------- 1 | loopProvider->hasLoop() && $this->isSignalHandlingEnabled()) { 25 | return new SignalHandlingSetup( 26 | $this->loopProvider->getLoop(), 27 | $this->loopConfig, 28 | ); 29 | } 30 | 31 | return new DummySignalHandlingSetup(); 32 | } 33 | 34 | private function isSignalHandlingEnabled(): bool 35 | { 36 | return $this->loopConfig->getSignalHandlingMode() === SignalHandlingMode::ENABLED; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Spinner/Core/Feature/Resolver/AutoStartResolver.php: -------------------------------------------------------------------------------- 1 | driverModeDetector->isEnabled() && $this->autoStartModeDetector->isEnabled(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Spinner/Core/Feature/Resolver/Contract/IAutoStartResolver.php: -------------------------------------------------------------------------------- 1 | driverModeDetector->isEnabled() && $this->initializationModeDetector->isEnabled(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Spinner/Core/Feature/Resolver/LinkerResolver.php: -------------------------------------------------------------------------------- 1 | linkerModeDetector->isEnabled() && $this->driverModeDetector->isEnabled(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Spinner/Core/IntervalComparator.php: -------------------------------------------------------------------------------- 1 | toMicroseconds() < $smallest->toMicroseconds()) { 18 | $smallest = $interval; 19 | } 20 | } 21 | 22 | return $smallest; 23 | } 24 | 25 | public function largest(IInterval $first, ?IInterval ...$other): IInterval 26 | { 27 | $largest = $first; 28 | 29 | foreach ($other as $interval) { 30 | if ($interval instanceof IInterval && $interval->toMicroseconds() > $largest->toMicroseconds()) { 31 | $largest = $interval; 32 | } 33 | } 34 | 35 | return $largest; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Spinner/Core/IntervalNormalizer.php: -------------------------------------------------------------------------------- 1 | integerNormalizer->normalize((int)$interval->toMilliseconds()) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Spinner/Core/Loop/Contract/A/ALoopAdapter.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | abstract public static function getCreatorClass(): string; 21 | } 22 | -------------------------------------------------------------------------------- /src/Spinner/Core/Loop/Contract/ILoop.php: -------------------------------------------------------------------------------- 1 | > $probes 15 | * 16 | * @psalm-return class-string|null 17 | */ 18 | public function extract(Traversable $probes): ?string; 19 | } 20 | -------------------------------------------------------------------------------- /src/Spinner/Core/Loop/Contract/ILoopCreatorClassProvider.php: -------------------------------------------------------------------------------- 1 | |null */ 10 | public function getCreatorClass(): ?string; 11 | } 12 | -------------------------------------------------------------------------------- /src/Spinner/Core/Loop/Contract/ILoopProbe.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public static function getCreatorClass(): string; 15 | } 16 | -------------------------------------------------------------------------------- /src/Spinner/Core/Loop/Contract/ILoopProvider.php: -------------------------------------------------------------------------------- 1 | loop instanceof ILoop; 21 | } 22 | 23 | public function getLoop(): ILoop 24 | { 25 | return $this->loop ?? throw new DomainException('Loop is not set.'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Spinner/Core/Loop/LoopSetup.php: -------------------------------------------------------------------------------- 1 | autoStartResolver->isEnabled()) { 21 | $loop->autoStart(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Spinner/Core/Output/BufferedOutput.php: -------------------------------------------------------------------------------- 1 | output->write($this->buffer->flush()); 22 | } 23 | 24 | public function append(iterable|string $messages): IBufferedOutput 25 | { 26 | $this->buffer->append($messages); 27 | 28 | return $this; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Spinner/Core/Output/Contract/Factory/IResourceStreamFactory.php: -------------------------------------------------------------------------------- 1 | |string $message 15 | */ 16 | public function append(iterable|string $message): IBuffer; 17 | 18 | /** 19 | * Yields buffer content and clears buffer. 20 | * 21 | * @return Traversable 22 | */ 23 | public function flush(): Traversable; 24 | } 25 | -------------------------------------------------------------------------------- /src/Spinner/Core/Output/Contract/IConsoleCursor.php: -------------------------------------------------------------------------------- 1 | outputConfig->getStream() 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Spinner/Core/Output/Output.php: -------------------------------------------------------------------------------- 1 | write($messages, true, $options); 21 | } 22 | 23 | public function write(iterable|string $messages, bool $newline = false, int $options = 0): void 24 | { 25 | $this->stream->write( 26 | $this->homogenize($messages, $newline) 27 | ); 28 | } 29 | 30 | /** 31 | * @return Traversable 32 | */ 33 | private function homogenize(iterable|string $messages, bool $newline = false): Traversable 34 | { 35 | if (!is_iterable($messages)) { 36 | $messages = [$messages]; 37 | } 38 | 39 | /** @psalm-suppress MixedAssignment */ 40 | foreach ($messages as $message) { 41 | if (is_string($message)) { 42 | if ($newline) { 43 | $message .= PHP_EOL; 44 | } 45 | yield $message; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Spinner/Core/Output/StringBuffer.php: -------------------------------------------------------------------------------- 1 | buffer; 22 | $this->buffer = ''; 23 | } 24 | 25 | public function append(iterable|string $message): IBuffer 26 | { 27 | if (!is_iterable($message)) { 28 | $message = [$message]; 29 | } 30 | /** @var string $item */ 31 | foreach ($message as $item) { 32 | $this->buffer .= $item; 33 | } 34 | return $this; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Spinner/Core/Output/WritableStream.php: -------------------------------------------------------------------------------- 1 | stream = $stream; 34 | } 35 | 36 | /** 37 | * @codeCoverageIgnore 38 | * 39 | * @inheritDoc 40 | */ 41 | public function write(Traversable $data): void 42 | { 43 | /** @var string $item */ 44 | foreach ($data as $item) { 45 | if (fwrite($this->stream, $item) === false) { 46 | throw new RuntimeException('Was unable to write to a stream.'); 47 | } 48 | } 49 | // fflush($this->stream); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Spinner/Core/Palette/A/APalette.php: -------------------------------------------------------------------------------- 1 | create($palette) 24 | public function getTemplate(?IPaletteMode $mode = null): IPaletteTemplate 25 | { 26 | return new PaletteTemplate( 27 | $this->getEntries($mode), 28 | $this->getOptions($mode), 29 | ); 30 | } 31 | 32 | /** 33 | * @return Traversable