-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add log level highlighting #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Add log_level_hl and log_level_groups to default config - Add highlight_log_levels() function with word-boundary matching - Add backfill_log_levels() for existing buffer content - Track log_level_hl state per buffer - Hook into on_lines callback to highlight new lines - Add public API: log_level_hl_enable/disable/toggle Supports uppercase keywords: TRACE, DEBUG, INFO, WARN, WARNING, ERROR Uses Neovim's diagnostic highlight groups by default.
- Add highlight_log_levels() function for file-tail buffers - Add file_log_level_hl_enable/disable functions - Hook highlighting into file poller callback - Add commands: TailLogLevelHlEnable/Disable/Toggle
- Update description and features list - Add log_level_hl config option to setup example - Document new commands and Lua API functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for highlighting log level keywords (TRACE, DEBUG, INFO, WARN, WARNING, ERROR) in tail.nvim buffers. The feature is opt-in and uses Neovim's diagnostic highlight groups by default, with support for customization.
Key Changes:
- Implements log level highlighting using frontier patterns for word boundary matching
- Adds new configuration options (
log_level_hlandlog_level_groups) - Provides new commands and Lua API functions for controlling the feature at runtime
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| plugin/tail.lua | Adds log level highlighting implementation for file-based tail buffers, including namespace creation, highlighting logic, enable/disable functions, and new user commands |
| lua/tail/init.lua | Implements log level highlighting for non-file buffers with configuration support, integrates with the on_lines handler, and exposes public API functions |
| README.md | Documents the new log level highlighting feature, including usage examples and API reference |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| cfg = { | ||
| follow = true, | ||
| ts_enabled = false, | ||
| ts_format = "%Y-%m-%d %H:%M:%S ", |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default config created here is missing the ts_hl field which is present in other similar initializations (see line 204 and file_timestamps_enable around line 356). This inconsistency could lead to bugs if code expects ts_hl to be present. The field should be initialized to maintain consistency with other config initializations.
| ts_format = "%Y-%m-%d %H:%M:%S ", | |
| ts_format = "%Y-%m-%d %H:%M:%S ", | |
| ts_hl = false, |
| require("tail").setup({ | ||
| -- uncomment the next line to enable timestamps by default | ||
| -- timestamps = true, | ||
| -- enable timestamps by default | ||
| timestamps = false, | ||
| -- customise the format (see `:help os.date`) | ||
| timestamp_format = "%Y-%m-%d %H:%M:%S", | ||
| -- customise the highlight group used for the timestamp | ||
| timestamp_hl = "Comment", | ||
| -- enable log level highlighting by default | ||
| log_level_hl = false, | ||
| }) |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The README documentation is incomplete. According to the PR description, users should be able to customize highlight groups via the log_level_groups config option, but this is not documented in the setup example. Consider adding documentation showing users how to customize the highlight groups, similar to how the PR description shows this feature.
| local log_level_groups = { | ||
| TRACE = "DiagnosticHint", | ||
| DEBUG = "DiagnosticHint", | ||
| INFO = "DiagnosticInfo", | ||
| WARN = "DiagnosticWarn", | ||
| WARNING = "DiagnosticWarn", | ||
| ERROR = "DiagnosticError", | ||
| } |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The highlight groups are hardcoded here in plugin/tail.lua but should respect the user's configuration from tail.opts.log_level_groups. Currently, if a user configures custom highlight groups via setup(), they will work for non-file buffers but not for file-based tail buffers because this local table is not reading from the config. Consider accessing tail.opts.log_level_groups instead.
| local ns_loglevel = vim.api.nvim_create_namespace("tail-loglevel") | ||
|
|
||
| -- default log level highlight groups (same as init.lua) | ||
| local log_level_groups = { | ||
| TRACE = "DiagnosticHint", | ||
| DEBUG = "DiagnosticHint", | ||
| INFO = "DiagnosticInfo", | ||
| WARN = "DiagnosticWarn", | ||
| WARNING = "DiagnosticWarn", | ||
| ERROR = "DiagnosticError", | ||
| } | ||
|
|
||
| --- Highlight log level keywords in the given line range (1-based, inclusive) | ||
| ---@param bufnr number | ||
| ---@param start_line number 1-based start line | ||
| ---@param end_line number 1-based end line (inclusive) | ||
| local function highlight_log_levels(bufnr, start_line, end_line) | ||
| if not vim.api.nvim_buf_is_valid(bufnr) then | ||
| return | ||
| end | ||
|
|
||
| local lines = vim.api.nvim_buf_get_lines(bufnr, start_line - 1, end_line, false) | ||
|
|
||
| for i, line in ipairs(lines) do | ||
| local lnum = start_line + i - 1 | ||
|
|
||
| for keyword, hl_group in pairs(log_level_groups) do | ||
| -- Use frontier pattern for word boundary matching (uppercase only) | ||
| local pattern = "%f[%w]" .. keyword .. "%f[%W]" | ||
| local search_start = 1 | ||
|
|
||
| while true do | ||
| local match_start, match_end = line:find(pattern, search_start) | ||
| if not match_start then | ||
| break | ||
| end | ||
|
|
||
| vim.api.nvim_buf_set_extmark(bufnr, ns_loglevel, lnum - 1, match_start - 1, { | ||
| end_col = match_end, | ||
| hl_group = hl_group, | ||
| }) | ||
|
|
||
| search_start = match_end + 1 | ||
| end | ||
| end | ||
| end |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is duplicated in lua/tail/init.lua (lines 157-187). The two implementations are nearly identical, which creates a maintainability issue. Consider extracting this to a shared utility module to avoid code duplication and ensure consistent behavior across file and non-file buffers.
| local ns_loglevel = vim.api.nvim_create_namespace("tail-loglevel") | |
| -- default log level highlight groups (same as init.lua) | |
| local log_level_groups = { | |
| TRACE = "DiagnosticHint", | |
| DEBUG = "DiagnosticHint", | |
| INFO = "DiagnosticInfo", | |
| WARN = "DiagnosticWarn", | |
| WARNING = "DiagnosticWarn", | |
| ERROR = "DiagnosticError", | |
| } | |
| --- Highlight log level keywords in the given line range (1-based, inclusive) | |
| ---@param bufnr number | |
| ---@param start_line number 1-based start line | |
| ---@param end_line number 1-based end line (inclusive) | |
| local function highlight_log_levels(bufnr, start_line, end_line) | |
| if not vim.api.nvim_buf_is_valid(bufnr) then | |
| return | |
| end | |
| local lines = vim.api.nvim_buf_get_lines(bufnr, start_line - 1, end_line, false) | |
| for i, line in ipairs(lines) do | |
| local lnum = start_line + i - 1 | |
| for keyword, hl_group in pairs(log_level_groups) do | |
| -- Use frontier pattern for word boundary matching (uppercase only) | |
| local pattern = "%f[%w]" .. keyword .. "%f[%W]" | |
| local search_start = 1 | |
| while true do | |
| local match_start, match_end = line:find(pattern, search_start) | |
| if not match_start then | |
| break | |
| end | |
| vim.api.nvim_buf_set_extmark(bufnr, ns_loglevel, lnum - 1, match_start - 1, { | |
| end_col = match_end, | |
| hl_group = hl_group, | |
| }) | |
| search_start = match_end + 1 | |
| end | |
| end | |
| end | |
| -- re-use the namespace from the core tail module if available, so highlights stay consistent | |
| local ns_loglevel = tail.ns_loglevel or vim.api.nvim_create_namespace("tail-loglevel") | |
| --- Highlight log level keywords in the given line range (1-based, inclusive) | |
| --- Delegates to the implementation in the core `tail` module to avoid code duplication. | |
| ---@param bufnr number | |
| ---@param start_line number 1-based start line | |
| ---@param end_line number 1-based end line (inclusive) | |
| local function highlight_log_levels(bufnr, start_line, end_line) | |
| -- If the core module exposes a shared implementation, delegate to it. | |
| if type(tail.highlight_log_levels) == "function" then | |
| return tail.highlight_log_levels(bufnr, start_line, end_line) | |
| end | |
| -- Fallback: keep behavior safe (no-op) if the shared implementation is not available. | |
| if not vim.api.nvim_buf_is_valid(bufnr) then | |
| return | |
| end |
|
The code and this PR were AI-generated. I’m testing this new feature locally, and it works nicely so far. This PR can be used:
Alternatively, it can be closed without additional comments if it falls outside the scope of this plugin. |
Summary
Add support for highlighting log level keywords (TRACE, DEBUG, INFO, WARN, WARNING, ERROR) using Neovim's diagnostic highlight groups.
Features
log_level_groupsconfiglog_level_hl = truein setup)New Commands
:TailLogLevelHlEnable:TailLogLevelHlDisable:TailLogLevelHlToggleNew Lua API
Configuration