https://github.com/lnus/stalker.nvim
Statistics for NeoVim usage
https://github.com/lnus/stalker.nvim
neovim neovim-plugin nvim
Last synced: 5 months ago
JSON representation
Statistics for NeoVim usage
- Host: GitHub
- URL: https://github.com/lnus/stalker.nvim
- Owner: lnus
- License: mit
- Created: 2025-02-02T01:30:34.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-10T23:42:37.000Z (over 1 year ago)
- Last Synced: 2025-10-05T00:44:12.334Z (9 months ago)
- Topics: neovim, neovim-plugin, nvim
- Language: Lua
- Homepage:
- Size: 44.9 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
stalker.nvim
Statistics for NeoVim usage
⚠️ This is very much a work in progress ⚠️
⚠️ Breaking changes WILL be pushed to main ⚠️
## Features
- Live tracking for mode switching
- Live tracking for (some) motions
- Store usage statistics to disk
- Send periodic sync data to a web endpoint
- Send realtime data to a web endpoint
### Tracked data
```
nav = { 'h', 'j', 'k', 'l' },
word = { 'w', 'b', 'e', 'ge' },
scroll = { '', '', '', '' },
find = { 'f', 'F', 't', 'T' },
search = { '*', '#', 'n', 'N' },
paragraph = { '{', '}' },
line = { '0', '$', '^', 'g_' },
indent = { '>', '<', '=', '>>', '<<' },
jumps = { 'gi', 'gv', '', '', 'g;', 'g,' },
```
## Usage
Session tracking should start as soon as NeoVim starts,
along with local storage syncing as well as the
web sync endpoint.
Available commands:
- `:Stalker` - Show current session statistics
- `:StalkerTotals` - Show total statistics
- `:StalkerResetSync` - Reset web sync state after failures
- `:StalkerResetRlSync` - Reset live sync state after failure
### Troubleshooting
- If web sync fails, use `:StalkerResetSync` to reset the sync state
- If live sync fails, use `:StalkerResetRlSync` to reset the sync state
- Check `:messages` for debug output when `verbose = true`
## TODO: Requirements
- NeoVim >= v0.9.0 (I need to double check this)
- cURL, I guess. For some things.
## Installation
### lazy.nvim
```lua
{
'lnus/stalker.nvim',
opts = {} -- config goes here
},
```
Alternatively
```lua
{
'lnus/stalker.nvim',
config = function()
require('stalker').setup {} -- config goes here
end,
},
```
## Configuration
These options can all be passed through `opts` if using [lazy.nvim](https://github.com/folke/lazy.nvim)
```lua
require('stalker').setup{
-- These are the default config values
verbose = false, -- Enable debug logging
-- Storage (Will probably be moved into sub-table)
store_locally = true, -- Should save stats to file
sync_interval = 30, -- Interval for saving to file/send to endpoint
sync_endpoint = nil, -- Optional web sync endpoint
-- Enable or disable specific tracking options
tracking = {
motions = true,
modes = true,
},
-- Realtime
realtime = {
enabled = false, -- What it says on the tin
sync_endpoint = nil, -- Realtime sync endpoint
sync_delay = 200, -- How often to flush&&send buffer in ms
max_buffer_size = 10, -- Force flush&&send buffer if this big
},
}
```
## Data
### Local storage
Local data will be stored within `vim.fn.stdpath 'data'`
in the `stalker` directory.
Session stats and the total of all session stats will be
stored in the `json` format.
### Realtime web endpoint
To set up realtime data syncing, structure config like this:
```lua
require('stalker').setup {
realtime = {
enabled = true,
sync_endpoint = 'http://localhost:8000/live',
headers = {
Authorization = 'Secret-Token',
},
},
}
```
#### Example consumer endpoint (FastAPI)
```python
@app.post("/live")
async def receive_live(request: Request):
# Read the raw body data and decode to string
raw_data = await request.body()
data_str = raw_data.decode("utf-8", errors="replace").strip()
# Split the events by delim (newline)
events = data_str.split("\n") if data_str else []
print("\n=== Stalker Update ===")
print(f"Received {len(events)} ({len(raw_data)} bytes) event(s):")
for event in events:
print(f"Event: {event}")
print("======================\n")
return {"status": "ok"}
```
### Periodic web endpoint
> Note to self: Add config to pass additional headers, for auth etc.
To set up periodic data syncing, structure config like this:
```lua
require('stalker').setup {
sync_endpoint = 'WEB_ENDPOINT'
}
```
#### Example consumer endpoint (FastAPI)
```python
@app.post("/stalker")
async def receive_stats(request: Request):
data = await request.json()
timestamp = datetime.fromtimestamp(data["timestamp"])
print("\n=== Stalker Update ===")
print(f"Time: {timestamp}")
print(f"Event: {data['event_type']}")
print("Stats:")
print(json.dumps(data["stats"], indent=2))
print("===================\n")
return {"status": "ok"}
```
## TODO
- [ ] feat: Add tracking for all modes
- [ ] feat: Add config for custom tracking
- [ ] feat: Add optional command tracking
- This could expose data, so:
- Make it off by default
- Track only base command?
- [ ] feat: Add event types, and send those as well
- Change event: Mode changes (Instead of sending n_to_i)
- Motion event: Motion keys (Currently only event)
- BufEnter event: When entering a buffer, send filetype?
- VimEnter/Session start event (just send on plugin init)
- VimLeave/Session end event (I already autocmd this)
- [ ] perf: Double check the perf of event buffer
- I feel like just posting to an endpoint over and over isn't... great.
- If event buffer feels nice to use,
we can use that for persitent data too, rather than a periodic timer.
So everything registers as an event and then we match over config to
decide if to write to file, send realtime data or big sync to endpoint.
- [ ] refactor: Update file structure of repo
## License
MIT