@@ -102,4 +102,110 @@ describe("markdown-plus utils", function()
102102 vim .api .nvim_buf_delete (buf , { force = true })
103103 end )
104104 end )
105+
106+ describe (" get_char_end_byte" , function ()
107+ it (" returns correct byte index for ASCII characters" , function ()
108+ local line = " hello world"
109+ -- ASCII characters are 1 byte each, so end byte = input byte
110+ assert .are .equal (1 , utils .get_char_end_byte (line , 1 )) -- 'h'
111+ assert .are .equal (6 , utils .get_char_end_byte (line , 6 )) -- ' '
112+ assert .are .equal (11 , utils .get_char_end_byte (line , 11 )) -- 'd'
113+ end )
114+
115+ it (" returns correct byte index for multi-byte characters" , function ()
116+ local line = " 这是一段文本" -- Each Chinese character is 3 bytes in UTF-8
117+ -- 这 = bytes 1-3
118+ assert .are .equal (3 , utils .get_char_end_byte (line , 1 ))
119+ -- 是 = bytes 4-6
120+ assert .are .equal (6 , utils .get_char_end_byte (line , 4 ))
121+ -- 一 = bytes 7-9
122+ assert .are .equal (9 , utils .get_char_end_byte (line , 7 ))
123+ -- 段 = bytes 10-12
124+ assert .are .equal (12 , utils .get_char_end_byte (line , 10 ))
125+ -- 文 = bytes 13-15
126+ assert .are .equal (15 , utils .get_char_end_byte (line , 13 ))
127+ -- 本 = bytes 16-18 (last character)
128+ assert .are .equal (18 , utils .get_char_end_byte (line , 16 ))
129+ end )
130+
131+ it (" returns correct byte index for mixed ASCII and multi-byte" , function ()
132+ local line = " hello 世界" -- "hello " = 6 bytes, 世=3 bytes, 界=3 bytes
133+ assert .are .equal (1 , utils .get_char_end_byte (line , 1 )) -- 'h'
134+ assert .are .equal (6 , utils .get_char_end_byte (line , 6 )) -- ' '
135+ assert .are .equal (9 , utils .get_char_end_byte (line , 7 )) -- '世' (bytes 7-9)
136+ assert .are .equal (12 , utils .get_char_end_byte (line , 10 )) -- '界' (bytes 10-12)
137+ end )
138+
139+ it (" handles byte position beyond line length" , function ()
140+ local line = " test"
141+ assert .are .equal (4 , utils .get_char_end_byte (line , 100 ))
142+ end )
143+ end )
144+
145+ describe (" get_visual_selection with multi-byte characters" , function ()
146+ it (" handles visual selection of multi-byte characters" , function ()
147+ local buf = vim .api .nvim_create_buf (false , true )
148+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { " 这是一段文本" })
149+ vim .api .nvim_set_current_buf (buf )
150+
151+ -- Select all text
152+ vim .api .nvim_win_set_cursor (0 , { 1 , 0 })
153+ vim .cmd (" normal! v$" )
154+
155+ local selection = utils .get_visual_selection ()
156+
157+ -- Should select the entire line
158+ assert .are .equal (1 , selection .start_row )
159+ assert .are .equal (1 , selection .end_row )
160+ assert .are .equal (1 , selection .start_col )
161+ assert .are .equal (18 , selection .end_col ) -- Full line is 18 bytes
162+
163+ -- Verify the text extraction works correctly
164+ local text =
165+ utils .get_text_in_range (selection .start_row , selection .start_col , selection .end_row , selection .end_col )
166+ assert .are .equal (" 这是一段文本" , text )
167+
168+ vim .api .nvim_buf_delete (buf , { force = true })
169+ end )
170+
171+ it (" handles partial selection of multi-byte characters" , function ()
172+ local buf = vim .api .nvim_create_buf (false , true )
173+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { " 这是一段文本" })
174+ vim .api .nvim_set_current_buf (buf )
175+
176+ -- Select first two characters (这是)
177+ vim .api .nvim_win_set_cursor (0 , { 1 , 0 })
178+ vim .cmd (" normal! v" )
179+ vim .cmd (" normal! l" ) -- Move to second char
180+
181+ local selection = utils .get_visual_selection ()
182+
183+ -- Should get correct byte positions
184+ assert .are .equal (1 , selection .start_col )
185+ assert .are .equal (6 , selection .end_col ) -- End of second char (是)
186+
187+ local text =
188+ utils .get_text_in_range (selection .start_row , selection .start_col , selection .end_row , selection .end_col )
189+ assert .are .equal (" 这是" , text )
190+
191+ vim .api .nvim_buf_delete (buf , { force = true })
192+ end )
193+
194+ it (" handles mixed ASCII and multi-byte selection" , function ()
195+ local buf = vim .api .nvim_create_buf (false , true )
196+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { " hello 世界" })
197+ vim .api .nvim_set_current_buf (buf )
198+
199+ -- Select entire line
200+ vim .api .nvim_win_set_cursor (0 , { 1 , 0 })
201+ vim .cmd (" normal! v$" )
202+
203+ local selection = utils .get_visual_selection ()
204+ local text =
205+ utils .get_text_in_range (selection .start_row , selection .start_col , selection .end_row , selection .end_col )
206+ assert .are .equal (" hello 世界" , text )
207+
208+ vim .api .nvim_buf_delete (buf , { force = true })
209+ end )
210+ end )
105211end )
0 commit comments