Skip to content

Commit d256598

Browse files
committed
Make suggestion widgets clickable.
The point of these are to click and replace text in the buffer (so now they do that). Minor style changes as well though it's still a bit ugly...
1 parent cbf50c8 commit d256598

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

lua/lean/infoview/components.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ function components.user_widgets_at(params, sess, use_widgets)
676676
sess = rpc.open(params)
677677
response, err = sess:getWidgets(params.position)
678678
end
679-
return widgets.render_response(response), err
679+
return widgets.render_response(response, params.textDocument.uri), err
680680
end
681681

682682
return components

lua/lean/widgets.lua

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
local Element = require('lean.tui').Element
1414
local dedent = require('lean._util').dedent
1515

16-
---@alias WidgetRenderer fun(self: Widget, props: any): Element[]?
16+
---@alias WidgetRenderer fun(self: Widget, props: any, uri: string): Element[]?
1717

1818
---A Lean user widget.
1919
---@class Widget
@@ -75,9 +75,10 @@ end
7575
---
7676
---Unsupported widgets are ignored after logging a notice.
7777
---@param instance UserWidgetInstance
78+
---@param uri string the URI of the document whose widgets we are rendering
7879
---@return Element?
79-
local function render(instance)
80-
return Widget.from_user_widget(instance):element(instance.props)
80+
local function render(instance, uri)
81+
return Widget.from_user_widget(instance):element(instance.props, uri)
8182
end
8283

8384
---@alias SuggestionText string
@@ -89,17 +90,57 @@ end
8990

9091
---@class TryThisParams
9192
---@field suggestions Suggestion[]
93+
---@field range lsp.Range
94+
---@field header string
95+
---@field isInline boolean
96+
---@field style any
9297

9398
---@param props TryThisParams
94-
implement('Lean.Meta.Tactic.TryThis.tryThisWidget', function(_, props)
99+
implement('Lean.Meta.Tactic.TryThis.tryThisWidget', function(_, props, uri)
95100
local blocks = vim.iter(props.suggestions):map(function(each)
96-
local pre = (each.preInfo or ''):gsub('\n', '\n ')
97-
local post = (each.postInfo or ''):gsub('\n', '\n ')
98-
local text = vim.iter({ pre, each.suggestion, post }):join '\n'
99-
return Element:new { text = text:gsub('\n$', '') }
101+
local children = {}
102+
if each.preInfo then
103+
table.insert(children, Element:new { text = each.preInfo })
104+
end
105+
table.insert(
106+
children,
107+
Element:new {
108+
text = each.suggestion,
109+
hlgroup = 'widgetLink',
110+
}
111+
)
112+
if each.postInfo then
113+
table.insert(children, Element:new { text = each.postInfo })
114+
end
115+
return Element:new {
116+
children = children,
117+
events = {
118+
click = function()
119+
local bufnr = vim.uri_to_bufnr(uri)
120+
if not vim.api.nvim_buf_is_loaded(bufnr) then
121+
return
122+
end
123+
vim.api.nvim_buf_set_text(
124+
bufnr,
125+
props.range.start.line,
126+
props.range.start.character,
127+
props.range['end'].line,
128+
props.range['end'].character,
129+
{ each.suggestion }
130+
)
131+
132+
local this_infoview = require('lean.infoview').get_current_infoview()
133+
local this_info = this_infoview and this_infoview.info
134+
local last_window = this_info and this_info.last_window
135+
if last_window and vim.api.nvim_win_get_buf(last_window) == bufnr then
136+
vim.api.nvim_set_current_win(last_window)
137+
end
138+
end,
139+
},
140+
}
100141
end)
101142
return Element:new {
102-
text = '▶ suggestion:',
143+
text = '▶ suggestion:\n',
103144
children = blocks:totable(),
104145
}
105146
end)
@@ -118,12 +159,12 @@ implement('GoToModuleLink', function(_, props)
118159
go_to_def = function(_)
119160
local this_infoview = require('lean.infoview').get_current_infoview()
120161
local this_info = this_infoview and this_infoview.info
121-
local this_window = this_info and this_info.last_window
122-
if not this_window then
162+
local last_window = this_info and this_info.last_window
163+
if not last_window then
123164
return
124165
end
125166

126-
vim.api.nvim_set_current_win(this_window)
167+
vim.api.nvim_set_current_win(last_window)
127168
-- FIXME: Clearly we need to be able to get a session without touching
128169
-- internals... Probably this should be a method on ctx.
129170
local params = this_info.pin.__position_params
@@ -151,10 +192,16 @@ return {
151192

152193
---Render the given response to one or more TUI elements.
153194
---@param response? UserWidgets
195+
---@param uri string the URI of the document whose widgets we are receiving
154196
---@return Element[]? elements
155-
render_response = function(response)
197+
render_response = function(response, uri)
156198
if response then
157-
return vim.iter(response.widgets):map(render):totable()
199+
return vim
200+
.iter(response.widgets)
201+
:map(function(widget)
202+
return render(widget, uri)
203+
end)
204+
:totable()
158205
end
159206
end,
160207
}

spec/infoview/widgets_spec.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ describe('widgets', function()
6363
▶ suggestion:
6464
exact rfl
6565
]]
66+
67+
infoview.go_to()
68+
helpers.move_cursor { to = { 7, 1 } }
69+
helpers.feed '<CR>'
70+
71+
-- the buffer contents have changed but we also jumped to the lean win
72+
assert.contents.are [[
73+
example : 2 = 2 := by
74+
exact rfl
75+
]]
6676
end
6777
)
6878
)

0 commit comments

Comments
 (0)