feat: add hover provider for virtual sensors to display entity details
This commit is contained in:
@@ -244,7 +244,7 @@ class ADVirtualSensorDefinitionProvider implements vscode.DefinitionProvider {
|
|||||||
|
|
||||||
invalidate() { this.cache = undefined; }
|
invalidate() { this.cache = undefined; }
|
||||||
|
|
||||||
private async getSensors(): Promise<VirtualSensorEntry[]> {
|
async getSensors(): Promise<VirtualSensorEntry[]> {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (this.cache && now < this.cacheExpiry) { return this.cache; }
|
if (this.cache && now < this.cacheExpiry) { return this.cache; }
|
||||||
this.cache = await findAllVirtualSensors();
|
this.cache = await findAllVirtualSensors();
|
||||||
@@ -282,6 +282,46 @@ class ADVirtualSensorDefinitionProvider implements vscode.DefinitionProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ADVirtualSensorHoverProvider implements vscode.HoverProvider {
|
||||||
|
constructor(
|
||||||
|
private haClient: HAClient,
|
||||||
|
private defProvider: ADVirtualSensorDefinitionProvider
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async provideHover(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
): Promise<vscode.Hover | undefined> {
|
||||||
|
// Find a virtual sensor whose definition is on this exact line
|
||||||
|
const sensors = await this.defProvider.getSensors();
|
||||||
|
const match = sensors.find(
|
||||||
|
s => s.uri.fsPath === document.uri.fsPath && s.line === position.line
|
||||||
|
);
|
||||||
|
if (!match) { return undefined; }
|
||||||
|
|
||||||
|
const entity = this.haClient.getEntity(match.sensorId);
|
||||||
|
if (!entity) { return undefined; }
|
||||||
|
|
||||||
|
const md = new vscode.MarkdownString();
|
||||||
|
md.isTrusted = true;
|
||||||
|
const friendly = entity.attributes?.friendly_name as string | undefined;
|
||||||
|
md.appendMarkdown(`### ${friendly || entity.entity_id}\n\n`);
|
||||||
|
md.appendMarkdown(`| | |\n|---|---|\n`);
|
||||||
|
md.appendMarkdown(`| **Entity** | \`${entity.entity_id}\` |\n`);
|
||||||
|
md.appendMarkdown(`| **State** | **\`${entity.state}\`** |\n`);
|
||||||
|
if (entity.attributes) {
|
||||||
|
const skip = new Set(['friendly_name', 'icon', 'entity_picture', 'supported_features', 'supported_color_modes']);
|
||||||
|
for (const [key, value] of Object.entries(entity.attributes).filter(([k]) => !skip.has(k)).slice(0, 12)) {
|
||||||
|
const display = typeof value === 'object' ? JSON.stringify(value) : String(value);
|
||||||
|
const truncated = display.length > 60 ? display.substring(0, 57) + '...' : display;
|
||||||
|
md.appendMarkdown(`| ${key.replace(/\|/g, '\\|')} | \`${truncated.replace(/\|/g, '\\|')}\` |\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md.appendMarkdown(`\n*Last changed: ${entity.last_changed}*`);
|
||||||
|
return new vscode.Hover(md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function updateContextualButton(editor: vscode.TextEditor | undefined) {
|
function updateContextualButton(editor: vscode.TextEditor | undefined) {
|
||||||
@@ -367,6 +407,10 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||||||
vscode.languages.registerDefinitionProvider(
|
vscode.languages.registerDefinitionProvider(
|
||||||
{ scheme: 'file', language: 'yaml' },
|
{ scheme: 'file', language: 'yaml' },
|
||||||
virtualSensorDefProvider
|
virtualSensorDefProvider
|
||||||
|
),
|
||||||
|
vscode.languages.registerHoverProvider(
|
||||||
|
{ scheme: 'file', language: 'yaml' },
|
||||||
|
new ADVirtualSensorHoverProvider(haClient, virtualSensorDefProvider)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user