Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.0.1] - 2026-02-15

### Added

- **Hover tooltips for JavaScript files**: Item hover tooltips (state lookups from the REST API and events.log) now work in `.js` automation files, not just `.items` and `.rules` files.
- **Hover tooltips for `.items` files**: Hovering over item names in `.items` configuration files also provides live state information from the REST API and log files.
- **Hover tooltips for sitemap files**: Item name hover tooltips work in `.sitemap` files, including `item=<name>` references on widget lines.
- **Key-value state extraction from log lines**: When hovering over a variable name found in events.log or openhab.log, the extension extracts its value from log lines with the format `someitem="state"` and displays just the state in the tooltip (e.g. `eventslog: true`).

### Configuration

Log file paths can be configured via VS Code settings:

- `openhab.log.eventsLogPath` — Path to `events.log` (default: `/opt/openhab/userdata/logs/events.log`)
- `openhab.log.openhabLogPath` — Path to `openhab.log` (default: `/opt/openhab/userdata/logs/openhab.log`)

### Artefact

- [openhab-1.0.1.vsix](https://github.com/s0170071/openhab-vscode/raw/main/openhab-1.0.1.vsix)

## [1.0.0] - 2021-04-12

- Add native token based authentication (#247)
Expand Down Expand Up @@ -275,4 +295,5 @@ Please change it in your settings after upgrade.
[0.8.0]: https://github.com/openhab/openhab-vscode/compare/0.8.0...0.8.1
[0.8.2]: https://github.com/openhab/openhab-vscode/compare/0.8.1...0.8.2
[1.0.0]: https://github.com/openhab/openhab-vscode/compare/0.8.2...1.0.0
[unreleased]: https://github.com/openhab/openhab-vscode/compare/1.0.0...HEAD
[1.0.1]: https://github.com/s0170071/openhab-vscode/compare/1.0.0...1.0.1
[unreleased]: https://github.com/s0170071/openhab-vscode/compare/1.0.1...HEAD
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
[![Visual Studio Marketplace Downloads)][MarketplaceDownloadBadgeImage]][MarketplaceDownloadBadgeImageLink]
[![Open VSX Downloads][openVsxDownloadBadgeImage]][openVsxDownloadBadgeImageLink]

[openHAB](http://www.openhab.org) is a vendor and techology agnostic open source automation software for your home. This [Visual Studio Code](https://code.visualstudio.com) extension allows you to work with openHAB configuration files (like `*.items`, `*.rules`, `*.sitemap` and `*.script`) thanks to the syntax highlighting, code snippets and integrated search.
[openHAB](http://www.openhab.org) is a vendor and techology agnostic open source automation software for your home. This [Visual Studio Code](https://code.visualstudio.com) extension allows you to work with openHAB configuration files — including `*.items`, `*.rules`, `*.sitemap`, `*.script`, and **JavaScript automation files** (`*.js`) — thanks to syntax highlighting, code snippets, and integrated search.

> **Note:** The extension works with DSL files (`*.items`, `*.rules`, `*.sitemap`), JavaScript automation files (`*.js`), and sitemap files. When you hover over an item or variable name, the extension looks it up against the openHAB REST API and also tries to capture its current value from `events.log` and `openhab.log`. A `.vsix` installer for the latest build is available in the [Download](#download) section below.

The extension is designed with openHAB 2.x in mind - most snippets and design patterns will work in openHAB 2.x

Expand All @@ -24,8 +26,23 @@ The extension is designed with openHAB 2.x in mind - most snippets and design pa
- Quick openHAB console access
- Add Items to Sitemap with one click
- Get live Item states while hovering over item names in the Editor
- Hover tooltips in JavaScript automation files (`.js`), not just DSL files
- Extract item states from log lines: hovering a variable like `geschlossenPrev` shows its value when found in `events.log` with the format `geschlossenPrev="true"`
- Show human readable `Thread::sleep()` times while hovering

### Log Hover Configuration

The extension searches openHAB log files to provide hover tooltips. Configure the paths in VS Code settings:

| Setting | Default | Description |
|---|---|---|
| `openhab.log.eventsLogPath` | `/opt/openhab/userdata/logs/events.log` | Path to the openHAB events log |
| `openhab.log.openhabLogPath` | `/opt/openhab/userdata/logs/openhab.log` | Path to the openHAB application log |

### Download

- [openhab-1.0.1.vsix](https://github.com/s0170071/openhab-vscode/raw/main/openhab-1.0.1.vsix) — Install via `code --install-extension openhab-1.0.1.vsix`

![openHAB2 code snippets](docs/images/openhab-demo.gif)

## Configuration
Expand Down
80 changes: 74 additions & 6 deletions client/src/HoverProvider/HoverProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as utils from '../Utils/Utils'
import axios, { AxiosRequestConfig } from 'axios'
import { ConfigManager } from '../Utils/ConfigManager'
import { OH_CONFIG_PARAMETERS } from '../Utils/types'
import { LogSearchProvider, LogSearchResult } from './LogSearchProvider'

/**
* Handles hover actions in editor windows.
Expand All @@ -26,21 +27,28 @@ export class HoverProvider {
*/
private knownItems:String[]

/**
* Log search provider for events.log lookup
*/
private logSearch: LogSearchProvider

/**
* Regex for Thread::sleep() expression
*/
public static THREAD_SLEEP_REGEX:RegExp = /(?<=sleep\()[0-9]{1,9}(?=\))/gm

/**
* Regex for all hover-relevant wordings
* Matches: sleep(nnn), key="value", key='value', key=value, or plain words
*/
public static HOVERED_WORD_REGEX:RegExp = /(?<=sleep\()[0-9]{1,9}(?=\)){1}|(\w+){1}/gm
public static HOVERED_WORD_REGEX:RegExp = /(?<=sleep\()[0-9]{1,9}(?=\)){1}|\w+=(?:"[^"]*"|'[^']*'|\S+)|\w+/gm

/**
* Only allow the class to call the constructor
*/
public constructor(){
this.updateItems()
this.logSearch = new LogSearchProvider()
}

/**
Expand All @@ -59,12 +67,17 @@ export class HoverProvider {
if(lineMatch && lineMatch.length == 1)
return this.getReadableThreadSleep(hoveredLine)

console.debug(`Checking if => ${hoveredText} <= is a known Item now`)
if(this.knownItems.includes(hoveredText))
return this.getRestItemHover(hoveredText)
// If hoveredText is a key=value pair (e.g. item=FF_Bath_Light or label="My Label"),
// extract the value for item lookup so sitemap/rules references like item=X work correctly.
const kvMatch = hoveredText.match(/^\w+=(?:"([^"]*)"|'([^']*)'|(\S+))$/)
const lookupText = kvMatch ? (kvMatch[1] ?? kvMatch[2] ?? kvMatch[3]) : hoveredText

console.log(`Nothing to hover, waiting...`)
return null
console.debug(`Checking if => ${lookupText} <= is a known Item now`)
if(this.knownItems.includes(lookupText))
return this.getRestItemHover(lookupText)

console.debug(`Checking events.log for => ${lookupText} <=`)
return this.getLogHover(lookupText)
}

/**
Expand Down Expand Up @@ -152,6 +165,61 @@ export class HoverProvider {
return `${h != 0 ? h + ' hours ' : '' }${m != 0 ? m + ' minutes ' : ''}${s != 0 ? s + ' seconds ' : ''}${ms != 0 ? ms + ' milliseconds ' : ''}`;
}

/**
* Searches events.log for the latest mention of the hovered text.
* If a state change or command is found, displays the state prominently.
*
* @param hoveredText The currently hovered text
* @returns A Hover with log information, or null if not found
*/
private async getLogHover(hoveredText: string): Promise<Hover | null> {
try {
const result = await this.logSearch.searchLog(hoveredText)
if (!result) return null

let resultText = new MarkdownString()
resultText.isTrusted = true

if (result.state !== null) {
if (result.kvFromLine) {
// Key=value extracted from raw log line — show just the state
resultText.appendCodeblock(`eventslog: ${result.state}`, 'openhab')
} else {
// Show state prominently
const eventLabel = result.eventType === 'command' ? 'command'
: result.eventType === 'thingStatus' ? 'status'
: 'state'

resultText.appendMarkdown(`**Latest ${eventLabel}** *(from events.log)*\n\n`)
resultText.appendCodeblock(`${result.itemName || hoveredText} → ${result.state}`, 'openhab')

if (result.timestamp) {
resultText.appendMarkdown(`\n$(clock) \`${result.timestamp}\`\n`)
}

resultText.appendMarkdown(`\n---\n`)
resultText.appendMarkdown(`<small>${this._escapeMarkdown(result.rawLine)}</small>\n`)
}
} else {
// No state extracted — show raw log line
resultText.appendMarkdown(`**Last seen in events.log**\n`)
resultText.appendCodeblock(result.rawLine, 'log')
}

return new Hover(resultText)
} catch (e) {
console.debug(`LogHover: error searching for '${hoveredText}': ${e}`)
return null
}
}

/**
* Escape special markdown characters in a string
*/
private _escapeMarkdown(text: string): string {
return text.replace(/([\\`*_{}\[\]()#+\-.!|])/g, '\\$1')
}

/**
* Update known Items array
*
Expand Down
Loading