Skip to content

Commit e7e12a3

Browse files
authored
Merge pull request #8 from YaroSpace/develop
2 parents d67d6d6 + 8d1ab9e commit e7e12a3

File tree

6 files changed

+172
-54
lines changed

6 files changed

+172
-54
lines changed

README.md

+21-6
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ After installing Neovim, it took me some time to configure it, learn its setting
1414
I got fed up of constantly hitting `:`, typing `lua= command`, then typing `:messages` to see the output, only to find out that a made a typo or a
1515
syntax error and retyping the whole thing again, copying the paths from error stacktraces and so on. I needed something better, so there it is.
1616

17+
<br>
18+
1719
## ✨ Features
1820

1921
- Evaluate single line expressions and statements, visually selected lines of code or the whole buffer
20-
- Pretty print Lua objects, including function details and their source paths
21-
- Show normal and error output in the console/buffer, including output of `print()`, errors and stacktraces.
22+
- Pretty print Lua objects, including results of assignments, function details and their source paths
23+
- Show normal and error output inline in the console/buffer, including output of `print()`, errors and stacktraces.
2224
- Syntax highlighting and autocompletion
23-
- Load Neovim’s messages into console for inspection and copy/paste
25+
- Load Neovim’s messages and output of ex commands into console for inspection and copy/paste
2426
- Open links from stacktraces and function sources
2527
- Save / Load / Autosave console session
2628
- Use as a scratch pad for code gists
2729
- Attach code evaluators to any buffer
2830

31+
<br>
2932

3033
## 📦 Installation
3134

@@ -34,12 +37,18 @@ With [lazy.nvim](https://github.com/folke/lazy.nvim):
3437
```lua
3538
return {
3639
"yarospace/lua-console.nvim",
37-
lazy = true, keys = "`", opts = {},
40+
lazy = true,
41+
keys = {'`', '<Leader>`'},
42+
opts = {},
3843
}
3944
```
40-
otherwise, install with your favorite package manager and add
41-
`require('lua-console').setup { custom_options }` somewhere in your config.
45+
otherwise, install with your favorite package manager and add somewhere in your config:
46+
47+
```lua
48+
require('lua-console').setup { your_custom_options }
49+
```
4250

51+
<br>
4352

4453
## ⚙️ Configuration
4554

@@ -87,6 +96,7 @@ opts = {
8796

8897
</details>
8998

99+
<br>
90100

91101
## 🚀 Basic usage (with default mappings)
92102

@@ -110,6 +120,7 @@ opts = {
110120
saved whenever it is toggled or closed.
111121
- You can resize the console with `<C-Up>` and `<C-Down>`.
112122

123+
<br>
113124

114125
## 📓 Notes on globals, locals and preserving execution context
115126

@@ -129,6 +140,7 @@ There are two functions available within the console:
129140
- `_ctx()` - will print the contents of the context
130141
- `_ctx_clear()` - clears the context
131142

143+
<br>
132144

133145
## ⭐ Extra features
134146

@@ -257,6 +269,8 @@ There are two functions available within the console:
257269
]]
258270
```
259271

272+
<br>
273+
260274
## Alternatives and comparison
261275

262276
There are a number of alternatives available, notably:
@@ -268,5 +282,6 @@ There are a number of alternatives available, notably:
268282
Initially, when starting with Lua and Neovim, I tried all the REPLs/code runners I could find. However, I was not satisfied with all of them in one way or another.
269283
Lua-console is an attempt to combine the best features of all of them, like REPL / scratch pad / code runner / debug console, while leaving the UX and config simple.
270284

285+
<br>
271286

272287
## 🔥 All feedback and feature requests are very welcome! Enjoy!

lua/lazy.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
return {
22
'yarospace/lua-console.nvim',
33
lazy = true,
4-
keys = '`',
4+
keys = {'`', '<Leader>`'},
55
opts = {},
66
}

lua/lua-console.lua

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
local config, mappings, utils, injections
1+
local config = require('lua-console.config')
2+
local mappings = require('lua-console.mappings')
3+
local utils = require('lua-console.utils')
4+
local injections = require('lua-console.injections')
25

36
local get_or_create_buffer = function()
47
--- @type number
@@ -77,10 +80,7 @@ end
7780
local setup = function(opts)
7881
_G.Lua_console = { buf = false, win = false, height = 0, ctx = {} }
7982

80-
config = require('lua-console.config').setup(opts)
81-
mappings = require('lua-console.mappings')
82-
utils = require('lua-console.utils')
83-
injections = require('lua-console.injections')
83+
config.setup(opts)
8484

8585
mappings.set_global_mappings()
8686
mappings.set_console_commands()

lua/lua-console/mappings.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
local M = {}
22

3-
local console = require('lua-console')
43
local config = require('lua-console.config')
54
local utils = require('lua-console.utils')
65

@@ -13,6 +12,7 @@ local function set_map(buf, map, opts, mode)
1312
end
1413

1514
M.set_global_mappings = function()
15+
local console = require('lua-console')
1616
local m = config.mappings
1717

1818
set_map(nil, m.toggle, {

lua/lua-console/utils.lua

+86-41
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ local to_string = function(tbl, sep, trim)
55
tbl = tbl or {}
66
sep = sep or '\n'
77

8+
if type(tbl) ~= 'table' then tbl = { tbl } end
9+
810
local line = table.concat(tbl, sep)
911
local patterns = { '\\r', '\\t', '\\n' }
1012

@@ -123,9 +125,9 @@ local get_path_lnum = function(path)
123125
return path, lnum
124126
end
125127

126-
---Determines if there is an assigment on the line and returns its value
127-
---@param line string[]
128-
local get_assignment = function(line)
128+
----Determines if there is an assigment on the line and returns its value
129+
----@param line string[]
130+
local get_line_assignment = function(line)
129131
if not line or #line == 0 then return end
130132

131133
local lhs = line[1]:match('^(.-)%s*=')
@@ -138,39 +140,29 @@ local get_assignment = function(line)
138140
end
139141
end
140142

141-
local print_buffer = {}
142-
143-
---@param buf number
144-
---@param lines string[] Text to append to current buffer after current selection
145-
local append_current_buffer = function(buf, lines)
146-
if not lines or #lines == 0 then return end
147-
143+
local get_last_assignment = function()
144+
local ctx = get_ctx()
148145
local lnum = vim.fn.line('.')
149-
local prefix = config.buffer.result_prefix
150-
local empty_results = { 'nil', '', '""', "''" }
151146

152-
local virtual_text
153-
local line = lines[#lines]
154-
155-
if vim.tbl_contains(empty_results, line) then
156-
table.remove(lines)
157-
virtual_text = line
158-
end
147+
local last_var = ctx._last_assignment
148+
local last_val = ctx[ctx._last_assignment]
159149

160-
local assignment_value = get_assignment(vim.fn.getbufline(buf, lnum, lnum))
161-
if assignment_value ~= nil then virtual_text = assignment_value end
150+
if not last_var then return end
162151

163-
if virtual_text then show_virtual_text(buf, 3, prefix .. virtual_text, lnum - 1, 'eol', 'Comment') end
152+
local line
153+
local offset = 0
164154

165-
if #lines == 0 then return end
155+
for i = lnum - 1, 0, -1 do
156+
line = vim.api.nvim_buf_get_lines(0, i, i + 1, false)[1]
166157

167-
lines[1] = prefix .. lines[1]
168-
table.insert(lines, 1, '') -- insert an empty line
158+
if line:match('^%s*' .. last_var .. '%s*=') then break end
159+
offset = offset + 1
160+
end
169161

170-
vim.api.nvim_buf_set_lines(buf, lnum, lnum, false, lines)
162+
return last_var, last_val, offset
171163
end
172164

173-
---Pretty prints objects and appends to print_buffer
165+
---Pretty prints objects
174166
---@param ... any[]
175167
---@return string[]
176168
local pretty_print = function(...)
@@ -187,10 +179,47 @@ local pretty_print = function(...)
187179
result = result .. var_no .. vim.inspect(o)
188180
end
189181

190-
result = to_table(result)
191-
vim.list_extend(print_buffer, result)
182+
return to_table(result)
183+
end
184+
185+
local print_buffer = {}
186+
187+
local print_to_buffer = function(...)
188+
local ret = pretty_print(...)
189+
vim.list_extend(print_buffer, ret)
190+
end
191+
192+
---@param buf number
193+
---@param lines string[] Text to append to current buffer after current selection
194+
local append_current_buffer = function(buf, lines)
195+
if not lines or #lines == 0 then return end
196+
197+
local lnum = vim.fn.line('.')
198+
local prefix = config.buffer.result_prefix
199+
local empty_results = { 'nil', '', '""', "''" }
200+
201+
local virtual_text
202+
local line = lines[#lines]
203+
204+
local last_assigned_var, last_assigned_val, last_assignment_offset = get_last_assignment()
205+
if last_assigned_var then
206+
virtual_text = to_string(pretty_print(last_assigned_val), '', true)
207+
show_virtual_text(buf, 3, prefix .. virtual_text, lnum - last_assignment_offset - 1, 'eol', 'Comment')
208+
end
209+
210+
if vim.tbl_contains(empty_results, line) then
211+
table.remove(lines)
212+
213+
virtual_text = get_line_assignment(vim.fn.getbufline(buf, lnum, lnum)) or line
214+
show_virtual_text(buf, 4, prefix .. virtual_text, lnum - 1, 'eol', 'Comment')
215+
end
216+
217+
if #lines == 0 then return end
218+
219+
lines[1] = prefix .. lines[1]
220+
table.insert(lines, 1, '') -- insert an empty line
192221

193-
-- return result
222+
vim.api.nvim_buf_set_lines(buf, lnum, lnum, false, lines)
194223
end
195224

196225
local function remove_empty_lines(tbl)
@@ -227,11 +256,11 @@ local function clean_stacktrace(error)
227256
return lines
228257
end
229258

230-
local function add_return(tbl)
231-
if vim.fn.trim(tbl[#tbl]) == 'end' then return tbl end
259+
local function add_return(tbl, lnum)
260+
if to_string(tbl[lnum], '', true):match('^%s*end') then return tbl end
232261

233262
local ret = vim.deepcopy(tbl)
234-
ret[#ret] = 'return ' .. ret[#ret]
263+
ret[lnum] = 'return ' .. ret[lnum]
235264

236265
return ret
237266
end
@@ -245,19 +274,26 @@ function get_ctx(buf)
245274
local ctx = lc.ctx[buf]
246275
if config.buffer.preserve_context and ctx then return ctx end
247276

248-
local env, mt = {}, {}
277+
local env, mt, values = {}, {}, {}
249278

250279
mt = {
251-
print = pretty_print,
280+
print = print_to_buffer,
252281
_ctx = function()
253-
return vim.tbl_extend('force', {}, env)
282+
return vim.deepcopy(values)
254283
end,
255284
_ctx_clear = function()
256285
lc.ctx[buf] = nil
257286
end,
258287
__index = function(_, key)
259-
return mt[key] and mt[key] or _G[key]
288+
return mt[key] and mt[key] or values[key] or _G[key]
260289
end,
290+
__newindex = function(_, k, v)
291+
values[k] = v
292+
mt._last_assignment = k
293+
end,
294+
_reset_last_assignment = function()
295+
mt._last_assignment = nil
296+
end
261297
}
262298

263299
lc.ctx[buf] = env
@@ -271,10 +307,17 @@ end
271307
function lua_evaluator(lines, ctx)
272308
vim.validate { lines = { lines, 'table' } }
273309

274-
local lines_with_return = add_return(lines)
275310
local env = ctx or get_ctx()
311+
env._reset_last_assignment()
276312

277-
if not select(2, load(to_string(lines_with_return), '', 't', env)) then lines = lines_with_return end
313+
local lines_with_return_first_line = add_return(lines, 1)
314+
local lines_with_return_last_line = add_return(lines, #lines)
315+
316+
if not select(2, load(to_string(lines_with_return_first_line), '', 't', env)) then
317+
lines = lines_with_return_first_line
318+
elseif not select(2, load(to_string(lines_with_return_last_line), '', 't', env)) then
319+
lines = lines_with_return_last_line
320+
end
278321

279322
local code, error = load(to_string(lines), 'Lua console: ', 't', env)
280323
if error then return to_table(error) end
@@ -289,9 +332,9 @@ function lua_evaluator(lines, ctx)
289332
table.remove(result, 1)
290333

291334
if #result > 0 then
292-
pretty_print(unpack(result))
335+
print_to_buffer(unpack(result))
293336
else
294-
pretty_print(nil)
337+
print_to_buffer(nil)
295338
end
296339
else
297340
vim.list_extend(print_buffer, clean_stacktrace(err))
@@ -476,6 +519,8 @@ local attach_toggle = function(buf)
476519
end
477520

478521
mappings.set_evaluator_mappings(buf, toggle)
522+
vim.api.nvim_set_option_value('syntax', 'on', { buf = buf })
523+
479524
vim.notify(
480525
('Evaluator %s for buffer [%s:%s]'):format(toggle and 'attached' or 'dettached', name, buf),
481526
vim.log.levels.INFO

0 commit comments

Comments
 (0)