Skip to content

Commit 3504421

Browse files
committed
add support for launching preview via lsp
1 parent dea4525 commit 3504421

File tree

12 files changed

+542
-273
lines changed

12 files changed

+542
-273
lines changed

lua/typst-preview/commands.lua

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,12 @@ local servers = require 'typst-preview.servers'
66

77
local M = {}
88

9-
---Scroll all preview to cursor position.
10-
function M.sync_with_cursor()
11-
for _, ser in pairs(servers.get_all()) do
12-
servers.sync_with_cursor(ser)
13-
end
14-
end
15-
169
---Create user commands
1710
function M.create_commands()
1811
local function preview_off()
1912
local path = utils.get_buf_path(0)
2013

21-
if path ~= '' and servers.remove(config.opts.get_main_file(path)) then
14+
if path ~= '' and servers.remove{path=config.opts.get_main_file(path)} then
2215
utils.print 'Preview stopped'
2316
else
2417
utils.print 'Preview not running'
@@ -38,16 +31,20 @@ function M.create_commands()
3831
---@param mode mode?
3932
local function preview_on(mode)
4033
-- check if binaries are available and tell them to fetch first
41-
for _, bin in pairs(fetch.bins_to_fetch()) do
42-
if
43-
not config.opts.dependencies_bin[bin.name] and not fetch.up_to_date(bin)
44-
then
45-
utils.notify(
46-
bin.name
47-
.. ' not found or out of date\nPlease run :TypstPreviewUpdate first!',
48-
vim.log.levels.ERROR
49-
)
50-
return
34+
if config.opts.use_lsp then
35+
-- FIXME: Check for tinymist to be connected
36+
else
37+
for _, bin in pairs(fetch.bins_to_fetch()) do
38+
if
39+
not config.opts.dependencies_bin[bin.name] and not fetch.up_to_date(bin)
40+
then
41+
utils.notify(
42+
bin.name
43+
.. ' not found or out of date\nPlease run :TypstPreviewUpdate first!',
44+
vim.log.levels.ERROR
45+
)
46+
return
47+
end
5148
end
5249
end
5350

@@ -58,15 +55,13 @@ function M.create_commands()
5855

5956
mode = mode or 'document'
6057

61-
local ser = servers.get(path)
62-
if ser == nil or ser[mode] == nil then
63-
servers.init(path, mode, function(s)
64-
events.listen(s)
65-
end)
58+
local _, ser = next(servers.get{path=path, mode=mode})
59+
if ser == nil then
60+
servers.init(path, mode, function(s) end)
6661
else
67-
local s = ser[mode]
62+
-- FIXME: try to ping the server to see whether it's really still alive
6863
print 'Opening another frontend'
69-
utils.visit(s.link)
64+
utils.visit(ser.link)
7065
end
7166
end
7267

@@ -93,10 +88,7 @@ function M.create_commands()
9388
if path == nil then
9489
return
9590
end
96-
local sers = servers.get(path)
97-
if sers ~= nil then
98-
mode = servers.get_last_mode(path)
99-
end
91+
mode = servers.get_last_mode(path)
10092
end
10193

10294
preview_on(mode)
@@ -113,7 +105,7 @@ function M.create_commands()
113105
return
114106
end
115107

116-
if servers.get(path) ~= nil then
108+
if next(servers.get{path=path}) ~= nil then
117109
preview_off()
118110
else
119111
preview_on(servers.get_last_mode(path))
@@ -130,7 +122,7 @@ function M.create_commands()
130122
config.set_follow_cursor(not config.get_follow_cursor())
131123
end, {})
132124
vim.api.nvim_create_user_command('TypstPreviewSyncCursor', function()
133-
M.sync_with_cursor()
125+
servers.scroll_preview()
134126
end, {})
135127
end
136128

lua/typst-preview/config.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ local M = {
2020
get_main_file = function(path)
2121
return path
2222
end,
23+
use_lsp = false,
2324
},
2425
}
2526

lua/typst-preview/events/editor.lua

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,24 @@ function M.register_autocmds(bufnr)
1111
local autocmds = {
1212
{
1313
event = { 'TextChanged', 'TextChangedI', 'TextChangedP', 'InsertLeave' },
14-
callback = function(ser, _)
14+
callback = function(_ev)
1515
servers.update_memory_file(
16-
ser,
1716
utils.get_buf_path(bufnr),
1817
utils.get_buf_content(bufnr)
1918
)
2019
end,
2120
},
2221
{
2322
event = { 'CursorMoved' },
24-
callback = function(ser, _)
23+
callback = function(_ev)
2524
if not config.get_follow_cursor() then
2625
return
2726
end
2827
local line = vim.api.nvim_win_get_cursor(0)[1]
2928
if last_line ~= line then
3029
-- No scroll when on the same line in insert mode
3130
last_line = line
32-
servers.sync_with_cursor(ser)
31+
servers.scroll_preview()
3332
end
3433
end,
3534
},
@@ -40,11 +39,7 @@ function M.register_autocmds(bufnr)
4039
{
4140
event = autocmd.event,
4241
opts = {
43-
callback = function(ev)
44-
for _, ser in pairs(servers.get_all()) do
45-
autocmd.callback(ser, ev)
46-
end
47-
end,
42+
callback = autocmd.callback,
4843
buffer = bufnr,
4944
},
5045
},

lua/typst-preview/events/init.lua

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1+
local config = require 'typst-preview.config'
12
local event_server = require 'typst-preview.events.server'
23
local utils = require 'typst-preview.utils'
34
local editor = require 'typst-preview.events.editor'
45
local servers = require 'typst-preview.servers'
56

67
local M = {}
78

8-
---Listen to Server's event
9-
---All buffers are already watched via auto command
10-
---@param s Server
11-
function M.listen(s)
12-
event_server.add_listeners(s)
13-
end
14-
15-
---Register autocmds to register autocmds for filetype
9+
---Setup listeners for server -> editor communication, and register filetype
10+
---autocmds that setup listeners for editor -> server communication.
1611
function M.init()
12+
-- Listen to Server's event
13+
servers.listen_scroll(event_server.on_editor_scroll_to)
14+
15+
if config.opts.use_lsp then
16+
-- When using tinymist via vim.lsp, we don't need to update document state
17+
-- nvim already handles it in that case.
18+
-- FIXME: Do we still want to use the VimLeavePre autocmd below? Or is it
19+
-- sufficient that nvim shuts down tinymist?
20+
return
21+
end
22+
23+
-- Register autocmds to register autocmds for filetype
1724
utils.create_autocmds('typst-preview-all-autocmds', {
1825
{
1926
event = 'FileType',

lua/typst-preview/events/server.lua

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,40 @@ local utils = require 'typst-preview.utils'
33

44
local M = {}
55

6-
---Register event listener
7-
---@param s Server
8-
function M.add_listeners(s)
9-
servers.listen_scroll(s, function(event)
10-
local function editorScrollTo()
11-
utils.debug(event.end_.row .. ' ' .. event.end_.column)
12-
s.suppress = true
13-
local row = event.end_.row + 1
14-
local max_row = vim.fn.line '$'
15-
if row < 1 then
16-
row = 1
17-
end
18-
if row > max_row then
19-
row = max_row
20-
end
21-
local column = event.end_.column - 1
22-
local max_column = vim.fn.col '$' - 1
23-
if column < 0 then
24-
column = 0
25-
end
26-
if column > max_column then
27-
column = max_column
28-
end
29-
vim.api.nvim_win_set_cursor(0, { row, column })
30-
vim.defer_fn(function()
31-
s.suppress = false
32-
end, 100)
6+
---@param jump OnEditorJumpData
7+
function M.on_editor_scroll_to(jump)
8+
local function editorScrollTo()
9+
-- FIXME: What was the original reasoning for this throttling? Is it still
10+
-- needed? How to best implement for LSP?
11+
-- s.suppress = true
12+
local row = jump.end_.row + 1
13+
local max_row = vim.fn.line '$'
14+
if row < 1 then
15+
row = 1
3316
end
34-
35-
if event.filepath ~= utils.get_buf_path(0) then
36-
vim.cmd('e ' .. event.filepath)
37-
vim.defer_fn(editorScrollTo, 100)
38-
else
39-
editorScrollTo()
17+
if row > max_row then
18+
row = max_row
19+
end
20+
local column = jump.end_.column - 1
21+
local max_column = vim.fn.col '$' - 1
22+
if column < 0 then
23+
column = 0
4024
end
41-
end)
25+
if column > max_column then
26+
column = max_column
27+
end
28+
vim.api.nvim_win_set_cursor(0, { row, column })
29+
-- vim.defer_fn(function()
30+
-- s.suppress = false
31+
-- end, 100)
32+
end
33+
34+
if jump.filepath ~= utils.get_buf_path(0) then
35+
vim.cmd('e ' .. jump.filepath)
36+
vim.defer_fn(editorScrollTo, 100)
37+
else
38+
editorScrollTo()
39+
end
4240
end
4341

4442
return M

lua/typst-preview/fetch.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,13 @@ end
198198
---@param quiet boolean
199199
---@param callback function|nil
200200
function M.fetch(quiet, callback)
201+
if config.opts.use_lsp then
202+
if callback ~= nil then
203+
callback()
204+
end
205+
return
206+
end
207+
201208
if callback == nil then
202209
callback = function() end
203210
end

lua/typst-preview/servers/base.lua

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
local M = {}
2+
3+
-- Tinymist API types
4+
5+
---@class PreviewResult
6+
---@field staticServerAddr string|nil
7+
---@field staticServerPort number|nil
8+
---@field dataPlanePort number|nil
9+
---@field isPrimary boolean|nil
10+
11+
---@class JumpInfo
12+
---@field filepath string
13+
---@field start number[] | nil
14+
---@field end number[] | nil
15+
16+
-- Parsed JumpInfo
17+
18+
---@class Location
19+
---@field row number
20+
---@field column number
21+
22+
---@class OnEditorJumpData
23+
---@field filepath string
24+
---@field start Location
25+
---@field end_ Location
26+
27+
-- Server and related types
28+
29+
---@alias mode 'document'|'slide'
30+
31+
---@class (exact) Server
32+
---@field path string Unsaved buffer will not be previewable.
33+
---@field mode mode
34+
---@field link string
35+
---@field suppress boolean Prevent server initiated event to trigger editor initiated events.
36+
---@field close fun()
37+
---@field scroll_to fun(data)
38+
---@field update_memory_file fun(data)
39+
---@field remove_memory_file fun(data)
40+
41+
function M.new_server(path, mode, link)
42+
return {
43+
path = path,
44+
mode = mode,
45+
link = link,
46+
suppress = false,
47+
close = function() end,
48+
scroll_to = function() end,
49+
update_memory_file = function() end,
50+
remove_memory_file = function() end,
51+
}
52+
end
53+
54+
---@class(exact) ServerFilter
55+
---@field path? string
56+
---@field mode? mode
57+
---@field task_id? string
58+
59+
---@param server Server
60+
---@param filter ServerFilter
61+
---@return boolean
62+
function M.server_matches(server, filter)
63+
for k, v in pairs(filter) do
64+
if server[k] ~= v then
65+
return false
66+
end
67+
end
68+
return true
69+
end
70+
71+
return M

0 commit comments

Comments
 (0)