From 065fc70b6a26a8d78e034f7db92c8872367356df Mon Sep 17 00:00:00 2001 From: Daniel Leech Date: Sat, 11 Mar 2023 13:19:45 +0000 Subject: [PATCH] Add inlay hint --- src/InlayHint.php | 186 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/InlayHint.php diff --git a/src/InlayHint.php b/src/InlayHint.php new file mode 100644 index 0000000..7b08f03 --- /dev/null +++ b/src/InlayHint.php @@ -0,0 +1,186 @@ + + */ + public $label; + + /** + * The kind of this hint. Can be omitted in which case the client + * should fall back to a reasonable default. + * + * @var InlayHintKind::*|null + */ + public $kind; + + /** + * Optional text edits that are performed when accepting this inlay hint. + * + * *Note* that edits are expected to change the document so that the inlay + * hint (or its nearest variant) is now part of the document and the inlay + * hint itself is now obsolete. + * + * @var array|null + */ + public $textEdits; + + /** + * The tooltip text when you hover over this item. + * + * @var string|MarkupContent|null + */ + public $tooltip; + + /** + * Render padding before the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + * + * @var bool|null + */ + public $paddingLeft; + + /** + * Render padding after the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + * + * @var bool|null + */ + public $paddingRight; + + /** + * A data entry field that is preserved on an inlay hint between + * a `textDocument/inlayHint` and a `inlayHint/resolve` request. + * + * @var mixed|null + */ + public $data; + + /** + * @param Position $position + * @param string|array $label + * @param InlayHintKind::*|null $kind + * @param array|null $textEdits + * @param string|MarkupContent|null $tooltip + * @param bool|null $paddingLeft + * @param bool|null $paddingRight + * @param mixed|null $data + */ + public function __construct(Position $position, $label, $kind = null, ?array $textEdits = null, $tooltip = null, ?bool $paddingLeft = null, ?bool $paddingRight = null, $data = null) + { + $this->position = $position; + $this->label = $label; + $this->kind = $kind; + $this->textEdits = $textEdits; + $this->tooltip = $tooltip; + $this->paddingLeft = $paddingLeft; + $this->paddingRight = $paddingRight; + $this->data = $data; + } + + /** + * @param array $array + * @return self + */ + public static function fromArray(array $array, bool $allowUnknownKeys = false) + { + $map = [ + 'position' => ['names' => [Position::class], 'iterable' => false], + 'label' => ['names' => [], 'iterable' => false], + 'kind' => ['names' => [], 'iterable' => false], + 'textEdits' => ['names' => [TextEdit::class], 'iterable' => true], + 'tooltip' => ['names' => [MarkupContent::class], 'iterable' => false], + 'paddingLeft' => ['names' => [], 'iterable' => false], + 'paddingRight' => ['names' => [], 'iterable' => false], + 'data' => ['names' => [], 'iterable' => false], + ]; + + foreach ($array as $key => &$value) { + if (!isset($map[$key])) { + if ($allowUnknownKeys) { + unset($array[$key]); + continue; + } + + throw new RuntimeException(sprintf( + 'Parameter "%s" on class "%s" not known, known parameters: "%s"', + $key, + self::class, + implode('", "', array_keys($map)) + )); + } + + // from here we only care about arrays that can be transformed into + // objects + if (!is_array($value)) { + continue; + } + + if (empty($map[$key]['names'])) { + continue; + } + + if ($map[$key]['iterable']) { + $value = array_map(function ($object) use ($map, $key, $allowUnknownKeys) { + if (!is_array($object)) { + return $object; + } + + return self::invokeFromNames($map[$key]['names'], $object, $allowUnknownKeys) ?: $object; + }, $value); + continue; + } + + $names = $map[$key]['names']; + $value = self::invokeFromNames($names, $value, $allowUnknownKeys) ?: $value; + } + + return Invoke::new(self::class, $array); + } + + /** + * @param array $classNames + * @param array $object + */ + private static function invokeFromNames(array $classNames, array $object, bool $allowUnknownKeys): ?object + { + $lastException = null; + foreach ($classNames as $className) { + try { + // @phpstan-ignore-next-line + return call_user_func_array($className . '::fromArray', [$object, $allowUnknownKeys]); + } catch (Exception $exception) { + $lastException = $exception; + continue; + } + } + + throw $lastException; + } + +} \ No newline at end of file