Skip to content

Commit cc37d38

Browse files
committed
fix: improve logging
1 parent fe96417 commit cc37d38

File tree

5 files changed

+103
-65
lines changed

5 files changed

+103
-65
lines changed

README.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ require("live-command").setup {
8888
change = "DiffChange",
8989
},
9090
},
91-
debug = false,
9291
}
9392
```
9493

@@ -123,15 +122,6 @@ deletion edits will not be undone which is otherwise done to make the text chang
123122

124123
---
125124

126-
`debug: boolean`
127-
128-
Default: `false`
129-
130-
If `true`, more stuff (not only errors) will be logged. After previewing a command,
131-
you can view the log by running `:LiveCommandLog`.
132-
133-
---
134-
135125
Like this project? Give it a :star: to show your support!
136126

137127
Also consider checking out my other plugin [inc-rename.nvim](https://github.com/smjonas/inc-rename.nvim),

lua/live-command/init.lua

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ M.defaults = {
1111
}
1212

1313
local api = vim.api
14+
15+
---@type Logger
16+
local logger
17+
1418
---@class Remote
1519
local remote
1620

@@ -22,18 +26,6 @@ local should_cache_lines = true
2226
local cached_lines
2327
local prev_lazyredraw
2428

25-
local logs = {}
26-
local function log(msg, level)
27-
level = level or "TRACE"
28-
if M.debug or level ~= "TRACE" then
29-
msg = type(msg) == "function" and msg() or msg
30-
logs[level] = logs[level] or {}
31-
for _, line in ipairs(vim.split(msg .. "\n", "\n")) do
32-
table.insert(logs[level], line)
33-
end
34-
end
35-
end
36-
3729
-- Inserts str_2 into str_1 at the given position.
3830
local function string_insert(str_1, str_2, pos)
3931
return str_1:sub(1, pos - 1) .. str_2 .. str_1:sub(pos)
@@ -55,7 +47,7 @@ local function add_inline_highlights(line, cached_lns, updated_lines, undo_delet
5547
local line_a = splice(cached_lns[line])
5648
local line_b = splice(updated_lines[line])
5749
local line_diff = vim.diff(line_a, line_b, { result_type = "indices" })
58-
log(function()
50+
logger.trace(function()
5951
return ("Changed lines (line %d):\nOriginal: '%s' (len=%d)\nUpdated: '%s' (len=%d)\n\nInline hunks: %s"):format(
6052
line,
6153
cached_lns[line],
@@ -113,10 +105,10 @@ local function get_diff_highlights(cached_lns, updated_lines, line_range, opts)
113105
local hunks = vim.diff(table.concat(cached_lns, "\n"), table.concat(updated_lines, "\n"), {
114106
result_type = "indices",
115107
})
116-
log(("Visible line range: %d-%d"):format(line_range[1], line_range[2]))
108+
logger.trace(("Visible line range: %d-%d"):format(line_range[1], line_range[2]))
117109

118110
for i, hunk in ipairs(hunks) do
119-
log(function()
111+
logger.trace(function()
120112
return ("Hunk %d/%d: %s"):format(i, #hunks, vim.inspect(hunk))
121113
end)
122114

@@ -132,7 +124,7 @@ local function get_diff_highlights(cached_lns, updated_lines, line_range, opts)
132124
end_line = start_line + (count_a - count_b) - 1
133125
end
134126

135-
log(function()
127+
logger.trace(function()
136128
return ("Lines %d-%d:\nOriginal: %s\nUpdated: %s"):format(
137129
start_line,
138130
end_line,
@@ -187,10 +179,15 @@ M._preview_across_lines = get_diff_highlights
187179

188180
---@param cmd string
189181
local function run_cmd(cmd)
182+
if not chan_id then
183+
logger.trace("run_cmd: skipped as chan_id is not set")
184+
return
185+
end
186+
190187
local cursor_pos = api.nvim_win_get_cursor(0)
191188
cursor_row, cursor_col = cursor_pos[1], cursor_pos[2]
192189

193-
log(function()
190+
logger.trace(function()
194191
return ("Previewing command: %s (l=%d,c=%d)"):format(cmd, cursor_row, cursor_col)
195192
end)
196193
return remote.run_cmd(chan_id, cmd, cursor_row, cursor_col)
@@ -201,7 +198,6 @@ local function command_preview(opts, preview_ns, preview_buf)
201198
-- Any errors that occur in the preview function are not directly shown to the user but stored in vim.v.errmsg.
202199
-- Related: https://github.com/neovim/neovim/issues/18910.
203200
vim.v.errmsg = ""
204-
logs = {}
205201
local args = opts.cmd_args
206202
local command = opts.command
207203

@@ -244,7 +240,7 @@ local function command_preview(opts, preview_ns, preview_buf)
244240
set_lines(updated_lines)
245241
-- This should not happen
246242
if not opts.line1 then
247-
log("No line1 range provided", "ERROR")
243+
logger.error("No line1 range provided")
248244
end
249245
return 2
250246
end
@@ -258,7 +254,7 @@ local function command_preview(opts, preview_ns, preview_buf)
258254
undo_deletions = command.hl_groups["deletion"] ~= false,
259255
inline_highlighting = command.inline_highlighting,
260256
})
261-
log(function()
257+
logger.trace(function()
262258
return "Highlights: " .. vim.inspect(highlights)
263259
end)
264260

@@ -283,12 +279,12 @@ local function restore_buffer_state()
283279
vim.o.lazyredraw = prev_lazyredraw
284280
should_cache_lines = true
285281
if vim.v.errmsg ~= "" then
286-
log(("An error occurred in the preview function:\n%s"):format(vim.inspect(vim.v.errmsg)), "ERROR")
282+
logger.error(("An error occurred in the preview function:\n%s"):format(vim.inspect(vim.v.errmsg)))
287283
end
288284
end
289285

290286
local function execute_command(command)
291-
log("Executing command: " .. command)
287+
logger.trace("Executing command: " .. command)
292288
vim.cmd(command)
293289
restore_buffer_state()
294290
end
@@ -408,22 +404,18 @@ M.setup = function(user_config)
408404
local config = vim.tbl_deep_extend("force", M.defaults, user_config or {})
409405
validate_config(config)
410406
create_user_commands(config.commands)
407+
logger = require("live-command.logger")
411408
remote = require("live-command.remote")
412409

413-
remote.init_rpc(function(id)
410+
remote.init_rpc(logger, function(id)
414411
chan_id = id
415412
end)
416413
create_autocmds()
414+
end
417415

418-
M.debug = user_config.debug
419-
420-
api.nvim_create_user_command("LiveCommandLog", function()
421-
local msg = ("live-command log\n================\n\n%s%s"):format(
422-
logs.ERROR and "[ERROR]\n" .. table.concat(logs.ERROR, "\n") .. (logs.TRACE and "\n" or "") or "",
423-
logs.TRACE and "[TRACE]\n" .. table.concat(logs.TRACE, "\n") or ""
424-
)
425-
vim.notify(msg)
426-
end, { nargs = 0 })
416+
---@param logger_ Logger
417+
M._set_logger = function(logger_)
418+
logger = logger_
427419
end
428420

429421
M.version = "1.3.0"

lua/live-command/logger.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---@class Logger
2+
local M = {}
3+
4+
---@type Log[]
5+
local logs = {}
6+
7+
---@class Log
8+
---@field msg string
9+
---@field level number
10+
11+
---@param msg string|fun():string
12+
M.trace = function(msg)
13+
msg = type(msg) == "function" and msg() or msg
14+
table.insert(logs, { msg = msg, level = vim.log.levels.TRACE })
15+
end
16+
17+
M.error = function(msg)
18+
msg = type(msg) == "function" and msg() or msg
19+
table.insert(logs, { msg = msg, level = vim.log.levels.ERROR })
20+
end
21+
22+
vim.api.nvim_create_user_command("LiveCommandLog", function()
23+
local msgs = {}
24+
for i, log in ipairs(logs) do
25+
local level = ""
26+
if log.level == vim.log.levels.TRACE then
27+
level = "[TRACE] "
28+
elseif log.level == vim.log.levels.ERROR then
29+
level = "[ERROR] "
30+
end
31+
msgs[i] = level .. log.msg
32+
end
33+
vim.notify(table.concat(msgs, "\n"))
34+
end, { nargs = 0 })
35+
36+
return M

lua/live-command/remote.lua

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
---@class Remote
22
local M = {}
33

4-
local tmp_file = os.tmpname()
4+
---@type Logger
5+
local logger
6+
57
local uv = vim.loop
8+
local tmp_file = os.tmpname()
69
local dirty = true
710

811
---@type number
912
local reference_time
1013

11-
local REFERENCE_TIME_OFFSET = 1
14+
local REFERENCE_TIME_OFFSET = -1
1215

1316
---@param server_address string
1417
---@param on_chan_id fun(chan_id:number)
@@ -31,17 +34,22 @@ local try_connect = function(server_address, on_chan_id, num_retries)
3134
end
3235

3336
--- Starts a new Nvim instance and connects to it via RPC.
37+
---@param logger_ Logger
3438
---@param on_chan_id fun(chan_id: number)
35-
M.init_rpc = function(on_chan_id)
39+
M.init_rpc = function(logger_, on_chan_id)
40+
logger = logger_
3641
local basename = vim.fs.normalize(vim.fn.stdpath("cache"))
3742
local server_address = basename .. "/live_command_server.pipe"
3843

3944
-- Try to connect to an existing server that has already been spawned
4045
local success = try_connect(server_address, on_chan_id, 1)
4146
if success then
47+
logger.trace(("init_rpc: connected to existing server"):format(reference_time))
4248
return
4349
end
4450

51+
logger.trace("init_rpc: spawning new server")
52+
4553
-- Use environment variables from parent process
4654
local env = { "LIVECOMMAND_NVIM_SERVER=1" }
4755
for k, v in pairs(uv.os_environ()) do
@@ -60,40 +68,41 @@ M.init_rpc = function(on_chan_id)
6068
handle:close()
6169
end)
6270
)
71+
6372
assert(handle)
6473
success = try_connect(server_address, on_chan_id, 100)
65-
if not success then
74+
if success then
75+
logger.trace("init_rpc: connected to server")
76+
else
6677
vim.notify("[live-command.nvim] failed to connect to remote Neovim instance after 1000 ms", vim.log.levels.ERROR)
6778
end
6879
end
6980

70-
-- The global dirty flag indicates that other spawned Nvim instances need to reload the
71-
-- temp file. The flag is encoded by increasing the modified time of the temp file.
72-
local set_global_dirty_flag = function()
81+
---@return boolean
82+
local check_global_dirty_flag = function()
7383
local stat = uv.fs_stat(tmp_file)
74-
uv.fs_utime(tmp_file, stat.atime.nsec, reference_time + REFERENCE_TIME_OFFSET)
75-
local new_stat = uv.fs_stat(tmp_file)
76-
assert(new_stat.atime.nsec == stat.atime.nsec)
84+
local is_dirty = stat.mtime.sec == reference_time + REFERENCE_TIME_OFFSET
85+
logger.trace("check_global_dirty_flag: " .. tostring(is_dirty))
86+
return is_dirty
7787
end
7888

79-
---@return boolean
80-
local check_global_dirty_flag = function()
89+
-- The global dirty flag indicates that other spawned Nvim instances need to reload the
90+
-- temp file. The flag is encoded by decreasing the modified time of the temp file by 1.
91+
local set_global_dirty_flag = function(is_set)
8192
local stat = uv.fs_stat(tmp_file)
82-
local x = stat.mtime.sec == reference_time + REFERENCE_TIME_OFFSET
83-
if x then
84-
print("DIRRY")
85-
end
86-
return x
93+
local mtime = is_set and reference_time + REFERENCE_TIME_OFFSET or reference_time
94+
uv.fs_utime(tmp_file, stat.atime.sec, mtime)
95+
logger.trace("set_global_dirty_flag: " .. tostring(is_set))
8796
end
8897

89-
M.on_buffer_updated = function()
98+
M.on_buffer_updated = function(e)
9099
dirty = true
91100
end
92101

93102
M.on_buffer_saved = function()
94103
-- Writing a buffer to disk sets the global dirty flag
95104
if dirty then
96-
set_global_dirty_flag()
105+
set_global_dirty_flag(true)
97106
end
98107
end
99108

@@ -104,9 +113,13 @@ M.sync = function(chan_id)
104113
return
105114
end
106115

107-
dirty = dirty or check_global_dirty_flag()
116+
local checked_global_dirty_flag = false
117+
if not dirty then
118+
dirty = check_global_dirty_flag()
119+
checked_global_dirty_flag = true
120+
end
121+
108122
if dirty then
109-
print("dirty")
110123
-- Synchronize buffers by writing out the current buffer contents to a temporary file.
111124
-- Remove A and F option values to not affect the alternate file and the buffer name.
112125
vim.cmd("let c=&cpoptions | set cpoptions-=A | set cpoptions-=F | silent w! " .. tmp_file .. " | let &cpoptions=c")
@@ -118,6 +131,9 @@ M.sync = function(chan_id)
118131
false
119132
)
120133
dirty = false
134+
if checked_global_dirty_flag then
135+
set_global_dirty_flag(false)
136+
end
121137
end
122138
end
123139

tests/init_spec.lua

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
local live_command = require("live-command")
22

33
describe("inline_highlights", function()
4+
setup(function()
5+
live_command._set_logger(require("live-command.logger"))
6+
end)
7+
48
-- Checks for the case when the end of the line was unchanged
59
it("single insertion", function()
610
local highlights = {}
@@ -56,7 +60,7 @@ describe("inline_highlights", function()
5660
{ kind = "change", line = 1, column = 1, length = 4 },
5761
{ kind = "change", line = 1, column = 8, length = 1 },
5862
}, highlights)
59-
assert.are_same({"test = Function()"}, updated_lines)
63+
assert.are_same({ "test = Function()" }, updated_lines)
6064
end)
6165

6266
it("change should not use negative column values", function()
@@ -81,7 +85,7 @@ describe("inline_highlights", function()
8185
{ kind = "deletion", line = 1, column = 3, length = 2 },
8286
{ kind = "deletion", line = 1, column = 6, length = 19 },
8387
}, highlights)
84-
assert.are_same({"le plugins.nvim-surround"}, updated_lines)
88+
assert.are_same({ "le plugins.nvim-surround" }, updated_lines)
8589
end)
8690

8791
it("deletion", function()

0 commit comments

Comments
 (0)