|
5 | 5 | ---@field ns integer Namespace for `extmarks`.
|
6 | 6 | ---@field row integer Row of line(**0-indexed**).
|
7 | 7 |
|
| 8 | +---@alias markview.wrap.data.value [ string, string? ][] |
| 9 | + |
| 10 | +---@class markview.wrap.data |
| 11 | +--- |
| 12 | +---@field [integer] [ string, string? ][] |
| 13 | + |
8 | 14 | ------------------------------------------------------------------------------
|
9 | 15 |
|
10 |
| ---[[ Text wrapping for `markview.nvim`. ]] |
| 16 | +--[[ |
| 17 | +Text soft-wrapping support for `markview.nvim`. |
| 18 | +
|
| 19 | +Usage, |
| 20 | +
|
| 21 | +```lua |
| 22 | +vim.o.wrap = true; |
| 23 | +``` |
| 24 | +
|
| 25 | +>[!NOTE] |
| 26 | +> Make sure not to *disable* wrapping for Nodes! |
| 27 | +]] |
11 | 28 | local wrap = {};
|
12 | 29 | local utils = require("markview.utils");
|
13 | 30 |
|
14 |
| ---[[ Gets extmark for `[ lnum, col ]`. ]] |
| 31 | +---@type table<integer, markview.wrap.data> |
| 32 | +wrap.cache = {}; |
| 33 | + |
| 34 | +--[[ Registers `indent` to be used for `range` in `buffer`. ]] |
15 | 35 | ---@param buffer integer
|
16 |
| ----@param ns integer |
17 |
| ----@param lnum integer |
18 |
| ----@param col integer |
19 |
| ----@return vim.api.keyset.get_extmark_item |
20 |
| -wrap.get_extmark = function (buffer, ns, lnum, col) |
21 |
| - local extmarks = vim.api.nvim_buf_get_extmarks(buffer, ns, { lnum, col }, { lnum, col + 1 }, { |
22 |
| - details = true, |
23 |
| - type = "virt_text" |
| 36 | +---@param range { row: integer } |
| 37 | +---@param indent markview.wrap.data.value |
| 38 | +wrap.wrap_indent = function (buffer, range, indent) |
| 39 | + ---|fS |
| 40 | + |
| 41 | + if not wrap.cache[buffer] then |
| 42 | + wrap.cache[buffer] = {}; |
| 43 | + end |
| 44 | + |
| 45 | + local row = range.row; |
| 46 | + |
| 47 | + if not wrap.cache[buffer][row] then |
| 48 | + wrap.cache[buffer][row] = {}; |
| 49 | + end |
| 50 | + |
| 51 | + ---@type integer? Window to use for |
| 52 | + local win = utils.buf_getwin(buffer); |
| 53 | + |
| 54 | + if not win then |
| 55 | + return; |
| 56 | + end |
| 57 | + |
| 58 | + local height = vim.api.nvim_win_text_height(win, { |
| 59 | + start_row = range.row, |
| 60 | + end_row = range.row |
24 | 61 | });
|
25 | 62 |
|
26 |
| - return extmarks[1]; |
| 63 | + if height.all == 1 then |
| 64 | + return; |
| 65 | + end |
| 66 | + |
| 67 | + wrap.cache[buffer][row] = vim.list_extend(wrap.cache[buffer][row], indent); |
| 68 | + |
| 69 | + ---|fE |
27 | 70 | end
|
28 | 71 |
|
29 | 72 | --[[ Provides `wrapped indentation` to some text. ]]
|
30 | 73 | ---@param buffer integer
|
31 |
| ----@param opts markview.wrap.opts |
32 |
| -wrap.wrap_indent = function (buffer, opts) |
| 74 | +wrap.render = function (buffer, ns) |
33 | 75 | ---|fS
|
34 | 76 |
|
| 77 | + ---@type integer? Window to use for |
35 | 78 | local win = utils.buf_getwin(buffer);
|
36 | 79 |
|
37 |
| - local win_width = vim.api.nvim_win_get_width(win); |
38 |
| - local textoff = vim.fn.getwininfo(win)[1].textoff; |
39 |
| - local W = win_width - textoff; |
40 |
| - |
41 |
| - if vim.fn.strdisplaywidth(opts.line or "") < W then |
| 80 | + if not win then |
42 | 81 | return;
|
43 | 82 | end
|
44 | 83 |
|
45 |
| - local win_x = vim.api.nvim_win_get_position(win)[2]; |
46 |
| - local passed_start = false; |
| 84 | + local function render_line (row, indent) |
| 85 | + local textoff = vim.fn.getwininfo(win)[1].textoff; |
47 | 86 |
|
48 |
| - for c = 1, vim.fn.strdisplaywidth(opts.line or "") do |
49 |
| - --- `l` should be 1-indexed. |
50 |
| - ---@type integer |
51 |
| - local x = vim.fn.screenpos(win, opts.row + 1, c).col - (win_x + textoff); |
| 87 | + local win_x = vim.api.nvim_win_get_position(win)[2]; |
52 | 88 |
|
53 |
| - if x ~= 1 then |
54 |
| - goto continue; |
55 |
| - elseif passed_start == false then |
56 |
| - passed_start = true; |
57 |
| - goto continue; |
58 |
| - end |
| 89 | + local text = vim.api.nvim_buf_get_lines(buffer, row, row + 1, false)[1]; |
| 90 | + local chars = vim.fn.split(text, "\\zs"); |
59 | 91 |
|
60 |
| - local extmark = wrap.get_extmark(buffer, opts.ns, opts.row, c - 1); |
| 92 | + local c = 0; |
| 93 | + local before_start = true; |
61 | 94 |
|
62 |
| - if extmark ~= nil then |
63 |
| - local id = extmark[1]; |
64 |
| - local virt_text = extmark[4].virt_text; |
| 95 | + local last_screencol = math.huge; |
65 | 96 |
|
66 |
| - vim.api.nvim_buf_set_extmark(buffer, opts.ns, opts.row, c - 1, { |
67 |
| - id = id, |
| 97 | + for _, char in ipairs(chars) do |
| 98 | + c = c + #char; |
68 | 99 |
|
69 |
| - undo_restore = false, invalidate = true, |
70 |
| - right_gravity = false, |
| 100 | + local x = vim.fn.screenpos(win, row + 1, c).col - (win_x + textoff); |
71 | 101 |
|
72 |
| - virt_text_pos = "inline", |
73 |
| - ---@diagnostic disable-next-line: param-type-mismatch |
74 |
| - virt_text = vim.list_extend(virt_text, opts.indent or {}), |
| 102 | + if x < last_screencol and before_start == true then |
| 103 | + before_start = false; |
| 104 | + elseif x < last_screencol then |
| 105 | + local indent_opts = { |
| 106 | + undo_restore = false, invalidate = true, |
| 107 | + right_gravity = false, |
75 | 108 |
|
76 |
| - hl_mode = "combine", |
77 |
| - }); |
78 |
| - else |
79 |
| - vim.api.nvim_buf_set_extmark(buffer, opts.ns, opts.row, c - 1, { |
80 |
| - undo_restore = false, invalidate = true, |
81 |
| - right_gravity = false, |
| 109 | + virt_text_pos = "inline", |
| 110 | + hl_mode = "combine", |
82 | 111 |
|
83 |
| - virt_text_pos = "inline", |
84 |
| - virt_text = opts.indent or {}, |
| 112 | + virt_text = indent; |
| 113 | + }; |
85 | 114 |
|
86 |
| - hl_mode = "combine", |
87 |
| - }); |
| 115 | + vim.api.nvim_buf_set_extmark( |
| 116 | + buffer, |
| 117 | + ns, |
| 118 | + row, |
| 119 | + c - 1, |
| 120 | + indent_opts |
| 121 | + ); |
| 122 | + end |
| 123 | + |
| 124 | + last_screencol = x; |
88 | 125 | end
|
| 126 | + end |
89 | 127 |
|
90 |
| - ::continue:: |
| 128 | + for row, indent in pairs(wrap.cache[buffer] or {}) do |
| 129 | + render_line(row, indent); |
91 | 130 | end
|
92 | 131 |
|
| 132 | + wrap.cache[buffer] = {}; |
| 133 | + |
93 | 134 | ---|fE
|
94 | 135 | end
|
95 | 136 |
|
|
0 commit comments