blob: 0187a175a8264084d8581f723391e0a06590da10 [file] [log] [blame]
Bram Moolenaard3f78dc2017-02-25 14:21:10 +01001" Test spell checking
Bram Moolenaar5bcc5a12019-08-06 22:48:02 +02002" Note: this file uses latin1 encoding, but is used with utf-8 encoding.
Bram Moolenaard3f78dc2017-02-25 14:21:10 +01003
Bram Moolenaarb46fecd2019-06-15 17:58:09 +02004source check.vim
5CheckFeature spell
Bram Moolenaard3f78dc2017-02-25 14:21:10 +01006
Bram Moolenaar7751d1d2019-10-18 20:37:08 +02007source screendump.vim
8
Bram Moolenaar1a0f2002017-07-28 15:38:10 +02009func TearDown()
10 set nospell
11 call delete('Xtest.aff')
12 call delete('Xtest.dic')
13 call delete('Xtest.latin1.add')
14 call delete('Xtest.latin1.add.spl')
15 call delete('Xtest.latin1.spl')
16 call delete('Xtest.latin1.sug')
17endfunc
18
Bram Moolenaard3f78dc2017-02-25 14:21:10 +010019func Test_wrap_search()
20 new
21 call setline(1, ['The', '', 'A plong line with two zpelling mistakes', '', 'End'])
22 set spell wrapscan
23 normal ]s
24 call assert_equal('plong', expand('<cword>'))
25 normal ]s
26 call assert_equal('zpelling', expand('<cword>'))
27 normal ]s
28 call assert_equal('plong', expand('<cword>'))
29 bwipe!
30 set nospell
31endfunc
Bram Moolenaar5b276aa2017-04-22 23:49:52 +020032
Bram Moolenaarb73fa622017-12-21 20:27:47 +010033func Test_curswant()
34 new
35 call setline(1, ['Another plong line', 'abcdefghijklmnopq'])
36 set spell wrapscan
37 normal 0]s
38 call assert_equal('plong', expand('<cword>'))
39 normal j
40 call assert_equal(9, getcurpos()[2])
41 normal 0[s
42 call assert_equal('plong', expand('<cword>'))
43 normal j
44 call assert_equal(9, getcurpos()[2])
45
46 normal 0]S
47 call assert_equal('plong', expand('<cword>'))
48 normal j
49 call assert_equal(9, getcurpos()[2])
50 normal 0[S
51 call assert_equal('plong', expand('<cword>'))
52 normal j
53 call assert_equal(9, getcurpos()[2])
54
55 normal 1G0
56 call assert_equal('plong', spellbadword()[0])
57 normal j
58 call assert_equal(9, getcurpos()[2])
59
60 bwipe!
61 set nospell
62endfunc
63
Bram Moolenaar5b276aa2017-04-22 23:49:52 +020064func Test_z_equal_on_invalid_utf8_word()
65 split
66 set spell
67 call setline(1, "\xff")
68 norm z=
69 set nospell
70 bwipe!
71endfunc
Bram Moolenaar545cb792017-05-23 11:31:22 +020072
Bram Moolenaar156d3912022-06-18 14:09:08 +010073func Test_z_equal_on_single_character()
74 " this was decrementing the index below zero
75 new
76 norm a0\Ê
77 norm zW
78 norm z=
79
80 bwipe!
81endfunc
82
Bram Moolenaar872e4512018-07-20 23:36:26 +020083" Test spellbadword() with argument
84func Test_spellbadword()
85 set spell
86
87 call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +020088 call assert_equal(['another', 'caps'], 'A sentence. another sentence'->spellbadword())
Bram Moolenaar872e4512018-07-20 23:36:26 +020089
Bram Moolenaar362b44b2020-06-10 21:47:00 +020090 call assert_equal(['TheCamelWord', 'bad'], 'TheCamelWord asdf'->spellbadword())
91 set spelloptions=camel
92 call assert_equal(['asdf', 'bad'], 'TheCamelWord asdf'->spellbadword())
93 set spelloptions=
94
Bram Moolenaar872e4512018-07-20 23:36:26 +020095 set spelllang=en
96 call assert_equal(['', ''], spellbadword('centre'))
97 call assert_equal(['', ''], spellbadword('center'))
98 set spelllang=en_us
99 call assert_equal(['centre', 'local'], spellbadword('centre'))
100 call assert_equal(['', ''], spellbadword('center'))
101 set spelllang=en_gb
102 call assert_equal(['', ''], spellbadword('centre'))
103 call assert_equal(['center', 'local'], spellbadword('center'))
104
105 " Create a small word list to test that spellbadword('...')
106 " can return ['...', 'rare'].
107 e Xwords
108 insert
109foo
110foobar/?
111.
112 w!
113 mkspell! Xwords.spl Xwords
114 set spelllang=Xwords.spl
115 call assert_equal(['foobar', 'rare'], spellbadword('foo foobar'))
116
Bram Moolenaar152e79e2020-06-10 15:32:08 +0200117 " Typo should be detected even without the 'spell' option.
Bram Moolenaar872e4512018-07-20 23:36:26 +0200118 set spelllang=en_gb nospell
119 call assert_equal(['', ''], spellbadword('centre'))
Bram Moolenaar152e79e2020-06-10 15:32:08 +0200120 call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
121 call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence'))
122
123 set spelllang=
124 call assert_fails("call spellbadword('maxch')", 'E756:')
Bram Moolenaar96fdf432020-09-11 18:11:50 +0200125 call assert_fails("spelldump", 'E756:')
Bram Moolenaar872e4512018-07-20 23:36:26 +0200126
127 call delete('Xwords.spl')
128 call delete('Xwords')
129 set spelllang&
130 set spell&
131endfunc
132
Bram Moolenaard569a9e2020-09-28 23:13:15 +0200133func Test_spell_file_missing()
134 let s:spell_file_missing = 0
135 augroup TestSpellFileMissing
136 autocmd! SpellFileMissing * let s:spell_file_missing += 1
137 augroup END
138
139 set spell spelllang=ab_cd
140 let messages = GetMessages()
141 call assert_equal('Warning: Cannot find word list "ab.utf-8.spl" or "ab.ascii.spl"', messages[-1])
142 call assert_equal(1, s:spell_file_missing)
143
144 new XTestSpellFileMissing
145 augroup TestSpellFileMissing
146 autocmd! SpellFileMissing * bwipe
147 augroup END
148 call assert_fails('set spell spelllang=ab_cd', 'E797:')
149
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100150 " clean up
151 augroup TestSpellFileMissing
152 autocmd! SpellFileMissing
153 augroup END
Bram Moolenaard569a9e2020-09-28 23:13:15 +0200154 augroup! TestSpellFileMissing
155 unlet s:spell_file_missing
156 set spell& spelllang&
157 %bwipe!
158endfunc
159
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200160func Test_spelldump()
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100161 " In case the spell file is not found avoid getting the download dialog, we
162 " would get stuck at the prompt.
163 let g:en_not_found = 0
164 augroup TestSpellFileMissing
165 au! SpellFileMissing * let g:en_not_found = 1
166 augroup END
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200167 set spell spelllang=en
168 spellrare! emacs
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100169 if g:en_not_found
170 call assert_report("Could not find English spell file")
171 else
172 spelldump
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200173
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100174 " Check assumption about region: 1: us, 2: au, 3: ca, 4: gb, 5: nz.
175 call assert_equal('/regions=usaucagbnz', getline(1))
176 call assert_notequal(0, search('^theater/1$')) " US English only.
177 call assert_notequal(0, search('^theatre/2345$')) " AU, CA, GB or NZ English.
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200178
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100179 call assert_notequal(0, search('^emacs/?$')) " ? for a rare word.
180 call assert_notequal(0, search('^the the/!$')) " ! for a wrong word.
181 endif
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200182
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100183 " clean up
184 unlet g:en_not_found
185 augroup TestSpellFileMissing
186 autocmd! SpellFileMissing
187 augroup END
188 augroup! TestSpellFileMissing
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200189 bwipe
190 set spell&
191endfunc
192
193func Test_spelldump_bang()
194 new
195 call setline(1, 'This is a sample sentence.')
196 redraw
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100197
198 " In case the spell file is not found avoid getting the download dialog, we
199 " would get stuck at the prompt.
200 let g:en_not_found = 0
201 augroup TestSpellFileMissing
202 au! SpellFileMissing * let g:en_not_found = 1
203 augroup END
204
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200205 set spell
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200206
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100207 if g:en_not_found
208 call assert_report("Could not find English spell file")
209 else
210 redraw
211 spelldump!
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200212
Bram Moolenaarfc9f0fd2022-06-15 16:57:44 +0100213 " :spelldump! includes the number of times a word was found while updating
214 " the screen.
215 " Common word count starts at 10, regular word count starts at 0.
216 call assert_notequal(0, search("^is\t11$")) " common word found once.
217 call assert_notequal(0, search("^the\t10$")) " common word never found.
218 call assert_notequal(0, search("^sample\t1$")) " regular word found once.
219 call assert_equal(0, search("^screen\t")) " regular word never found.
220 endif
221
222 " clean up
223 unlet g:en_not_found
224 augroup TestSpellFileMissing
225 autocmd! SpellFileMissing
226 augroup END
227 augroup! TestSpellFileMissing
Bram Moolenaarf12f0022020-10-07 12:58:44 +0200228 %bwipe!
229 set spell&
230endfunc
231
Bram Moolenaar8c7ad362020-09-27 13:58:38 +0200232func Test_spelllang_inv_region()
233 set spell spelllang=en_xx
234 let messages = GetMessages()
235 call assert_equal('Warning: region xx not supported', messages[-1])
236 set spell& spelllang&
237endfunc
238
239func Test_compl_with_CTRL_X_CTRL_K_using_spell()
240 " When spell checking is enabled and 'dictionary' is empty,
241 " CTRL-X CTRL-K in insert mode completes using the spelling dictionary.
242 new
243 set spell spelllang=en dictionary=
244
245 set ignorecase
246 call feedkeys("Senglis\<c-x>\<c-k>\<esc>", 'tnx')
247 call assert_equal(['English'], getline(1, '$'))
248 call feedkeys("SEnglis\<c-x>\<c-k>\<esc>", 'tnx')
249 call assert_equal(['English'], getline(1, '$'))
250
251 set noignorecase
252 call feedkeys("Senglis\<c-x>\<c-k>\<esc>", 'tnx')
253 call assert_equal(['englis'], getline(1, '$'))
254 call feedkeys("SEnglis\<c-x>\<c-k>\<esc>", 'tnx')
255 call assert_equal(['English'], getline(1, '$'))
256
257 set spelllang=en_us
258 call feedkeys("Stheat\<c-x>\<c-k>\<esc>", 'tnx')
259 call assert_equal(['theater'], getline(1, '$'))
260 set spelllang=en_gb
261 call feedkeys("Stheat\<c-x>\<c-k>\<esc>", 'tnx')
262 " FIXME: commented out, expected theatre bug got theater. See issue #7025.
263 " call assert_equal(['theatre'], getline(1, '$'))
264
265 bwipe!
266 set spell& spelllang& dictionary& ignorecase&
267endfunc
268
Bram Moolenaar545cb792017-05-23 11:31:22 +0200269func Test_spellreall()
270 new
271 set spell
272 call assert_fails('spellrepall', 'E752:')
273 call setline(1, ['A speling mistake. The same speling mistake.',
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200274 \ 'Another speling mistake.'])
Bram Moolenaar545cb792017-05-23 11:31:22 +0200275 call feedkeys(']s1z=', 'tx')
276 call assert_equal('A spelling mistake. The same speling mistake.', getline(1))
277 call assert_equal('Another speling mistake.', getline(2))
278 spellrepall
279 call assert_equal('A spelling mistake. The same spelling mistake.', getline(1))
280 call assert_equal('Another spelling mistake.', getline(2))
281 call assert_fails('spellrepall', 'E753:')
282 set spell&
283 bwipe!
284endfunc
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200285
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100286" Test spellsuggest({word} [, {max} [, {capital}]])
287func Test_spellsuggest()
Bram Moolenaar152e79e2020-06-10 15:32:08 +0200288 " Verify suggestions are given even when spell checking is not enabled.
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100289 set nospell
Bram Moolenaar152e79e2020-06-10 15:32:08 +0200290 call assert_equal(['march', 'March'], spellsuggest('marrch', 2))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100291
292 set spell
293
294 " With 1 argument.
Bram Moolenaar76734052019-12-26 14:30:15 +0100295 call assert_equal(['march', 'March'], spellsuggest('marrch')[0:1])
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100296
297 " With 2 arguments.
Bram Moolenaar76734052019-12-26 14:30:15 +0100298 call assert_equal(['march', 'March'], spellsuggest('marrch', 2))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100299
300 " With 3 arguments.
Bram Moolenaar76734052019-12-26 14:30:15 +0100301 call assert_equal(['march'], spellsuggest('marrch', 1, 0))
302 call assert_equal(['March'], spellsuggest('marrch', 1, 1))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100303
304 " Test with digits and hyphen.
305 call assert_equal('Carbon-14', spellsuggest('Carbon-15')[0])
306
307 " Comment taken from spellsuggest.c explains the following test cases:
308 "
309 " If there are more UPPER than lower case letters suggest an
310 " ALLCAP word. Otherwise, if the first letter is UPPER then
311 " suggest ONECAP. Exception: "ALl" most likely should be "All",
312 " require three upper case letters.
Bram Moolenaar76734052019-12-26 14:30:15 +0100313 call assert_equal(['THIRD', 'third'], spellsuggest('thIRD', 2))
314 call assert_equal(['third', 'THIRD'], spellsuggest('tHIrd', 2))
315 call assert_equal(['Third'], spellsuggest('THird', 1))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100316 call assert_equal(['All'], spellsuggest('ALl', 1))
317
Dominique Pellef645ee42021-12-05 13:21:18 +0000318 " Special suggestion for repeated 'the the'.
319 call assert_inrange(0, 2, index(spellsuggest('the the', 3), 'the'))
320 call assert_inrange(0, 2, index(spellsuggest('the the', 3), 'the'))
321 call assert_inrange(0, 2, index(spellsuggest('The the', 3), 'The'))
322
Bram Moolenaar0e05de42020-03-25 22:23:46 +0100323 call assert_fails("call spellsuggest('maxch', [])", 'E745:')
324 call assert_fails("call spellsuggest('maxch', 2, [])", 'E745:')
325
Bram Moolenaar152e79e2020-06-10 15:32:08 +0200326 set spelllang=
327 call assert_fails("call spellsuggest('maxch')", 'E756:')
328 set spelllang&
329
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100330 set spell&
331endfunc
332
333" Test 'spellsuggest' option with methods fast, best and double.
334func Test_spellsuggest_option_methods()
335 set spell
336
Bram Moolenaar76734052019-12-26 14:30:15 +0100337 for e in ['latin1', 'utf-8']
338 exe 'set encoding=' .. e
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100339
Bram Moolenaar76734052019-12-26 14:30:15 +0100340 set spellsuggest=fast
341 call assert_equal(['Stick', 'Stitch'], spellsuggest('Stich', 2), e)
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100342
Bram Moolenaar76734052019-12-26 14:30:15 +0100343 " With best or double option, "Stitch" should become the top suggestion
344 " because of better phonetic matching.
345 set spellsuggest=best
346 call assert_equal(['Stitch', 'Stick'], spellsuggest('Stich', 2), e)
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100347
Bram Moolenaar76734052019-12-26 14:30:15 +0100348 set spellsuggest=double
349 call assert_equal(['Stitch', 'Stick'], spellsuggest('Stich', 2), e)
350 endfor
351
352 set spell& spellsuggest& encoding&
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100353endfunc
354
355" Test 'spellsuggest' option with value file:{filename}
356func Test_spellsuggest_option_file()
357 set spell spellsuggest=file:Xspellsuggest
358 call writefile(['emacs/vim',
359 \ 'theribal/terrible',
360 \ 'teribal/terrrible',
361 \ 'terribal'],
362 \ 'Xspellsuggest')
363
364 call assert_equal(['vim'], spellsuggest('emacs', 2))
365 call assert_equal(['terrible'], spellsuggest('theribal',2))
366
367 " If the suggestion is misspelled (*terrrible* with 3 r),
368 " it should not be proposed.
369 " The entry for "terribal" should be ignored because of missing slash.
370 call assert_equal([], spellsuggest('teribal', 2))
371 call assert_equal([], spellsuggest('terribal', 2))
372
373 set spell spellsuggest=best,file:Xspellsuggest
374 call assert_equal(['vim', 'Emacs'], spellsuggest('emacs', 2))
375 call assert_equal(['terrible', 'tribal'], spellsuggest('theribal', 2))
376 call assert_equal(['tribal'], spellsuggest('teribal', 1))
377 call assert_equal(['tribal'], spellsuggest('terribal', 1))
378
379 call delete('Xspellsuggest')
380 call assert_fails("call spellsuggest('vim')", "E484: Can't open file Xspellsuggest")
381
382 set spellsuggest& spell&
383endfunc
384
385" Test 'spellsuggest' option with value {number}
386" to limit the number of suggestions
387func Test_spellsuggest_option_number()
388 set spell spellsuggest=2,best
389 new
390
391 " We limited the number of suggestions to 2, so selecting
392 " the 1st and 2nd suggestion should correct the word, but
393 " selecting a 3rd suggestion should do nothing.
Bram Moolenaar76734052019-12-26 14:30:15 +0100394 call setline(1, 'A baord')
395 norm $1z=
396 call assert_equal('A board', getline(1))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100397
Bram Moolenaar76734052019-12-26 14:30:15 +0100398 call setline(1, 'A baord')
399 norm $2z=
400 call assert_equal('A bard', getline(1))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100401
Bram Moolenaar76734052019-12-26 14:30:15 +0100402 call setline(1, 'A baord')
403 norm $3z=
404 call assert_equal('A baord', getline(1))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100405
Bram Moolenaar76734052019-12-26 14:30:15 +0100406 let a = execute('norm $z=')
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100407 call assert_equal(
408 \ "\n"
Bram Moolenaar76734052019-12-26 14:30:15 +0100409 \ .. "Change \"baord\" to:\n"
410 \ .. " 1 \"board\"\n"
411 \ .. " 2 \"bard\"\n"
Bram Moolenaard281b7c2020-06-10 16:39:32 +0200412 \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100413
414 set spell spellsuggest=0
Bram Moolenaar76734052019-12-26 14:30:15 +0100415 call assert_equal("\nSorry, no suggestions", execute('norm $z='))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100416
417 " Unlike z=, function spellsuggest(...) should not be affected by the
418 " max number of suggestions (2) set by the 'spellsuggest' option.
Bram Moolenaar76734052019-12-26 14:30:15 +0100419 call assert_equal(['board', 'bard', 'broad'], spellsuggest('baord', 3))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100420
421 set spellsuggest& spell&
422 bwipe!
423endfunc
424
425" Test 'spellsuggest' option with value expr:{expr}
426func Test_spellsuggest_option_expr()
427 " A silly 'spellsuggest' function which makes suggestions all uppercase
428 " and makes the score of each suggestion the length of the suggested word.
429 " So shorter suggestions are preferred.
430 func MySuggest()
431 let spellsuggest_save = &spellsuggest
Bram Moolenaar76734052019-12-26 14:30:15 +0100432 set spellsuggest=3,best
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100433 let result = map(spellsuggest(v:val, 3), "[toupper(v:val), len(v:val)]")
434 let &spellsuggest = spellsuggest_save
435 return result
436 endfunc
437
Bram Moolenaar76734052019-12-26 14:30:15 +0100438 set spell spellsuggest=expr:MySuggest()
439 call assert_equal(['BARD', 'BOARD', 'BROAD'], spellsuggest('baord', 3))
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100440
441 new
Bram Moolenaar76734052019-12-26 14:30:15 +0100442 call setline(1, 'baord')
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100443 let a = execute('norm z=')
444 call assert_equal(
445 \ "\n"
Bram Moolenaar76734052019-12-26 14:30:15 +0100446 \ .. "Change \"baord\" to:\n"
447 \ .. " 1 \"BARD\"\n"
448 \ .. " 2 \"BOARD\"\n"
449 \ .. " 3 \"BROAD\"\n"
Bram Moolenaard281b7c2020-06-10 16:39:32 +0200450 \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100451
452 " With verbose, z= should show the score i.e. word length with
453 " our SpellSuggest() function.
454 set verbose=1
455 let a = execute('norm z=')
456 call assert_equal(
457 \ "\n"
Bram Moolenaar76734052019-12-26 14:30:15 +0100458 \ .. "Change \"baord\" to:\n"
459 \ .. " 1 \"BARD\" (4 - 0)\n"
460 \ .. " 2 \"BOARD\" (5 - 0)\n"
461 \ .. " 3 \"BROAD\" (5 - 0)\n"
Bram Moolenaard281b7c2020-06-10 16:39:32 +0200462 \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
Bram Moolenaare9a8d1f2019-12-25 13:36:36 +0100463
464 set spell& spellsuggest& verbose&
465 bwipe!
466endfunc
467
Dominique Pelle81b573d2022-03-22 21:14:55 +0000468" Test for 'spellsuggest' expr errors
Bram Moolenaar8dfcce32020-03-18 19:32:26 +0100469func Test_spellsuggest_expr_errors()
470 " 'spellsuggest'
471 func MySuggest()
472 return range(3)
473 endfunc
474 set spell spellsuggest=expr:MySuggest()
475 call assert_equal([], spellsuggest('baord', 3))
476
477 " Test for 'spellsuggest' expression returning a non-list value
478 func! MySuggest2()
479 return 'good'
480 endfunc
481 set spellsuggest=expr:MySuggest2()
482 call assert_equal([], spellsuggest('baord'))
483
484 " Test for 'spellsuggest' expression returning a list with dict values
485 func! MySuggest3()
486 return [[{}, {}]]
487 endfunc
488 set spellsuggest=expr:MySuggest3()
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200489 call assert_fails("call spellsuggest('baord')", 'E731:')
Bram Moolenaar8dfcce32020-03-18 19:32:26 +0100490
491 set nospell spellsuggest&
492 delfunc MySuggest
493 delfunc MySuggest2
494 delfunc MySuggest3
495endfunc
496
Bram Moolenaar585ee072022-01-29 11:22:17 +0000497func Test_spellsuggest_timeout()
498 set spellsuggest=timeout:30
499 set spellsuggest=timeout:-123
500 set spellsuggest=timeout:999999
501 call assert_fails('set spellsuggest=timeout', 'E474:')
502 call assert_fails('set spellsuggest=timeout:x', 'E474:')
503 call assert_fails('set spellsuggest=timeout:-x', 'E474:')
504 call assert_fails('set spellsuggest=timeout:--9', 'E474:')
505endfunc
506
Bram Moolenaar5c686172022-03-13 20:12:25 +0000507func Test_spellsuggest_visual_end_of_line()
508 let enc_save = &encoding
509 set encoding=iso8859
510
511 " This was reading beyond the end of the line.
512 norm R00000000000
513 sil norm 0
514 sil! norm i00000)
515 sil! norm i00000)
516 call feedkeys("\<CR>")
517 norm z=
518
519 let &encoding = enc_save
520endfunc
521
Bram Moolenaar9049b682018-08-31 22:26:53 +0200522func Test_spellinfo()
523 new
Bram Moolenaarc25e7022019-10-10 14:08:26 +0200524 let runtime = substitute($VIMRUNTIME, '\\', '/', 'g')
Bram Moolenaar9049b682018-08-31 22:26:53 +0200525
526 set enc=latin1 spell spelllang=en
Bram Moolenaarc25e7022019-10-10 14:08:26 +0200527 call assert_match("^\nfile: " .. runtime .. "/spell/en.latin1.spl\n$", execute('spellinfo'))
Bram Moolenaar9049b682018-08-31 22:26:53 +0200528
529 set enc=cp1250 spell spelllang=en
Bram Moolenaarc25e7022019-10-10 14:08:26 +0200530 call assert_match("^\nfile: " .. runtime .. "/spell/en.ascii.spl\n$", execute('spellinfo'))
Bram Moolenaar9049b682018-08-31 22:26:53 +0200531
Bram Moolenaar30276f22019-01-24 17:59:39 +0100532 set enc=utf-8 spell spelllang=en
Bram Moolenaarc25e7022019-10-10 14:08:26 +0200533 call assert_match("^\nfile: " .. runtime .. "/spell/en.utf-8.spl\n$", execute('spellinfo'))
Bram Moolenaar9049b682018-08-31 22:26:53 +0200534
535 set enc=latin1 spell spelllang=en_us,en_nz
536 call assert_match("^\n" .
Bram Moolenaarc25e7022019-10-10 14:08:26 +0200537 \ "file: " .. runtime .. "/spell/en.latin1.spl\n" .
538 \ "file: " .. runtime.. "/spell/en.latin1.spl\n$", execute('spellinfo'))
Bram Moolenaar9049b682018-08-31 22:26:53 +0200539
540 set spell spelllang=
541 call assert_fails('spellinfo', 'E756:')
542
543 set nospell spelllang=en
544 call assert_fails('spellinfo', 'E756:')
545
Bram Moolenaar8f130ed2019-04-10 22:15:19 +0200546 call assert_fails('set spelllang=foo/bar', 'E474:')
547 call assert_fails('set spelllang=foo\ bar', 'E474:')
548 call assert_fails("set spelllang=foo\\\nbar", 'E474:')
549 call assert_fails("set spelllang=foo\\\rbar", 'E474:')
550 call assert_fails("set spelllang=foo+bar", 'E474:')
551
Bram Moolenaar9049b682018-08-31 22:26:53 +0200552 set enc& spell& spelllang&
553 bwipe
554endfunc
555
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200556func Test_zz_basic()
557 call LoadAffAndDic(g:test_data_aff1, g:test_data_dic1)
558 call RunGoodBad("wrong OK puts. Test the end",
559 \ "bad: inputs comment ok Ok. test d\xE9\xF4l end the",
560 \["Comment", "deol", "d\xE9\xF4r", "input", "OK", "output", "outputs", "outtest", "put", "puts",
561 \ "test", "testen", "testn", "the end", "uk", "wrong"],
562 \[
563 \ ["bad", ["put", "uk", "OK"]],
564 \ ["inputs", ["input", "puts", "outputs"]],
565 \ ["comment", ["Comment", "outtest", "the end"]],
566 \ ["ok", ["OK", "uk", "put"]],
567 \ ["Ok", ["OK", "Uk", "Put"]],
568 \ ["test", ["Test", "testn", "testen"]],
569 \ ["d\xE9\xF4l", ["deol", "d\xE9\xF4r", "test"]],
570 \ ["end", ["put", "uk", "test"]],
571 \ ["the", ["put", "uk", "test"]],
572 \ ]
573 \ )
574
575 call assert_equal("gebletegek", soundfold('goobledygoook'))
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200576 call assert_equal("kepereneven", 'kóopërÿnôven'->soundfold())
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200577 call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale'))
578endfunc
579
580" Postponed prefixes
581func Test_zz_prefixes()
582 call LoadAffAndDic(g:test_data_aff2, g:test_data_dic1)
583 call RunGoodBad("puts",
584 \ "bad: inputs comment ok Ok end the. test d\xE9\xF4l",
585 \ ["Comment", "deol", "d\xE9\xF4r", "OK", "put", "input", "output", "puts", "outputs", "test", "outtest", "testen", "testn", "the end", "uk", "wrong"],
586 \ [
587 \ ["bad", ["put", "uk", "OK"]],
588 \ ["inputs", ["input", "puts", "outputs"]],
589 \ ["comment", ["Comment"]],
590 \ ["ok", ["OK", "uk", "put"]],
591 \ ["Ok", ["OK", "Uk", "Put"]],
592 \ ["end", ["put", "uk", "deol"]],
593 \ ["the", ["put", "uk", "test"]],
594 \ ["test", ["Test", "testn", "testen"]],
595 \ ["d\xE9\xF4l", ["deol", "d\xE9\xF4r", "test"]],
596 \ ])
597endfunc
598
599"Compound words
600func Test_zz_compound()
601 call LoadAffAndDic(g:test_data_aff3, g:test_data_dic3)
602 call RunGoodBad("foo m\xEF foobar foofoobar barfoo barbarfoo",
603 \ "bad: bar la foom\xEF barm\xEF m\xEFfoo m\xEFbar m\xEFm\xEF lala m\xEFla lam\xEF foola labar",
604 \ ["foo", "m\xEF"],
605 \ [
606 \ ["bad", ["foo", "m\xEF"]],
607 \ ["bar", ["barfoo", "foobar", "foo"]],
608 \ ["la", ["m\xEF", "foo"]],
609 \ ["foom\xEF", ["foo m\xEF", "foo", "foofoo"]],
610 \ ["barm\xEF", ["barfoo", "m\xEF", "barbar"]],
611 \ ["m\xEFfoo", ["m\xEF foo", "foo", "foofoo"]],
612 \ ["m\xEFbar", ["foobar", "barbar", "m\xEF"]],
613 \ ["m\xEFm\xEF", ["m\xEF m\xEF", "m\xEF"]],
614 \ ["lala", []],
615 \ ["m\xEFla", ["m\xEF", "m\xEF m\xEF"]],
616 \ ["lam\xEF", ["m\xEF", "m\xEF m\xEF"]],
617 \ ["foola", ["foo", "foobar", "foofoo"]],
618 \ ["labar", ["barbar", "foobar"]],
619 \ ])
620
621 call LoadAffAndDic(g:test_data_aff4, g:test_data_dic4)
622 call RunGoodBad("word util bork prebork start end wordutil wordutils pro-ok bork borkbork borkborkbork borkborkborkbork borkborkborkborkbork tomato tomatotomato startend startword startwordword startwordend startwordwordend startwordwordwordend prebork preborkbork preborkborkbork nouword",
623 \ "bad: wordutilize pro borkborkborkborkborkbork tomatotomatotomato endstart endend startstart wordend wordstart preborkprebork preborkpreborkbork startwordwordwordwordend borkpreborkpreborkbork utilsbork startnouword",
624 \ ["bork", "prebork", "end", "pro-ok", "start", "tomato", "util", "utilize", "utils", "word", "nouword"],
625 \ [
626 \ ["bad", ["end", "bork", "word"]],
627 \ ["wordutilize", ["word utilize", "wordutils", "wordutil"]],
628 \ ["pro", ["bork", "word", "end"]],
629 \ ["borkborkborkborkborkbork", ["bork borkborkborkborkbork", "borkbork borkborkborkbork", "borkborkbork borkborkbork"]],
630 \ ["tomatotomatotomato", ["tomato tomatotomato", "tomatotomato tomato", "tomato tomato tomato"]],
631 \ ["endstart", ["end start", "start"]],
632 \ ["endend", ["end end", "end"]],
633 \ ["startstart", ["start start"]],
634 \ ["wordend", ["word end", "word", "wordword"]],
635 \ ["wordstart", ["word start", "bork start"]],
636 \ ["preborkprebork", ["prebork prebork", "preborkbork", "preborkborkbork"]],
637 \ ["preborkpreborkbork", ["prebork preborkbork", "preborkborkbork", "preborkborkborkbork"]],
638 \ ["startwordwordwordwordend", ["startwordwordwordword end", "startwordwordwordword", "start wordwordwordword end"]],
639 \ ["borkpreborkpreborkbork", ["bork preborkpreborkbork", "bork prebork preborkbork", "bork preborkprebork bork"]],
640 \ ["utilsbork", ["utilbork", "utils bork", "util bork"]],
641 \ ["startnouword", ["start nouword", "startword", "startborkword"]],
642 \ ])
643
644endfunc
645
646"Test affix flags with two characters
647func Test_zz_affix()
648 call LoadAffAndDic(g:test_data_aff5, g:test_data_dic5)
649 call RunGoodBad("fooa1 fooa\xE9 bar prebar barbork prebarbork startprebar start end startend startmiddleend nouend",
650 \ "bad: foo fooa2 prabar probarbirk middle startmiddle middleend endstart startprobar startnouend",
651 \ ["bar", "barbork", "end", "fooa1", "fooa\xE9", "nouend", "prebar", "prebarbork", "start"],
652 \ [
653 \ ["bad", ["bar", "end", "fooa1"]],
654 \ ["foo", ["fooa1", "fooa\xE9", "bar"]],
655 \ ["fooa2", ["fooa1", "fooa\xE9", "bar"]],
656 \ ["prabar", ["prebar", "bar", "bar bar"]],
657 \ ["probarbirk", ["prebarbork"]],
658 \ ["middle", []],
659 \ ["startmiddle", ["startmiddleend", "startmiddlebar"]],
660 \ ["middleend", []],
661 \ ["endstart", ["end start", "start"]],
662 \ ["startprobar", ["startprebar", "start prebar", "startbar"]],
663 \ ["startnouend", ["start nouend", "startend"]],
664 \ ])
665
666 call LoadAffAndDic(g:test_data_aff6, g:test_data_dic6)
667 call RunGoodBad("meea1 meea\xE9 bar prebar barbork prebarbork leadprebar lead end leadend leadmiddleend",
668 \ "bad: mee meea2 prabar probarbirk middle leadmiddle middleend endlead leadprobar",
669 \ ["bar", "barbork", "end", "lead", "meea1", "meea\xE9", "prebar", "prebarbork"],
670 \ [
671 \ ["bad", ["bar", "end", "lead"]],
672 \ ["mee", ["meea1", "meea\xE9", "bar"]],
673 \ ["meea2", ["meea1", "meea\xE9", "lead"]],
674 \ ["prabar", ["prebar", "bar", "leadbar"]],
675 \ ["probarbirk", ["prebarbork"]],
676 \ ["middle", []],
677 \ ["leadmiddle", ["leadmiddleend", "leadmiddlebar"]],
678 \ ["middleend", []],
679 \ ["endlead", ["end lead", "lead", "end end"]],
680 \ ["leadprobar", ["leadprebar", "lead prebar", "leadbar"]],
681 \ ])
682
683 call LoadAffAndDic(g:test_data_aff7, g:test_data_dic7)
Bram Moolenaar3d2a47c2019-11-07 20:48:42 +0100684 call RunGoodBad("meea1 meezero meea\xE9 bar prebar barmeat prebarmeat leadprebar lead tail leadtail leadmiddletail",
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200685 \ "bad: mee meea2 prabar probarmaat middle leadmiddle middletail taillead leadprobar",
Bram Moolenaar3d2a47c2019-11-07 20:48:42 +0100686 \ ["bar", "barmeat", "lead", "meea1", "meea\xE9", "meezero", "prebar", "prebarmeat", "tail"],
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200687 \ [
688 \ ["bad", ["bar", "lead", "tail"]],
689 \ ["mee", ["meea1", "meea\xE9", "bar"]],
690 \ ["meea2", ["meea1", "meea\xE9", "lead"]],
691 \ ["prabar", ["prebar", "bar", "leadbar"]],
692 \ ["probarmaat", ["prebarmeat"]],
693 \ ["middle", []],
694 \ ["leadmiddle", ["leadmiddlebar"]],
695 \ ["middletail", []],
696 \ ["taillead", ["tail lead", "tail"]],
697 \ ["leadprobar", ["leadprebar", "lead prebar", "leadbar"]],
698 \ ])
699endfunc
700
701func Test_zz_NOSLITSUGS()
702 call LoadAffAndDic(g:test_data_aff8, g:test_data_dic8)
703 call RunGoodBad("foo bar faabar", "bad: foobar barfoo",
704 \ ["bar", "faabar", "foo"],
705 \ [
706 \ ["bad", ["bar", "foo"]],
707 \ ["foobar", ["faabar", "foo bar", "bar"]],
708 \ ["barfoo", ["bar foo", "bar", "foo"]],
709 \ ])
710endfunc
711
712" Numbers
713func Test_zz_Numbers()
714 call LoadAffAndDic(g:test_data_aff9, g:test_data_dic9)
715 call RunGoodBad("0b1011 0777 1234 0x01ff", "",
716 \ ["bar", "foo"],
717 \ [
718 \ ])
719endfunc
720
Bram Moolenaar37ff4cf2019-11-17 20:10:20 +0100721" Affix flags
722func Test_zz_affix_flags()
723 call LoadAffAndDic(g:test_data_aff10, g:test_data_dic10)
724 call RunGoodBad("drink drinkable drinkables drinktable drinkabletable",
725 \ "bad: drinks drinkstable drinkablestable",
726 \ ["drink", "drinkable", "drinkables", "table"],
727 \ [['bad', []],
728 \ ['drinks', ['drink']],
729 \ ['drinkstable', ['drinktable', 'drinkable', 'drink table']],
730 \ ['drinkablestable', ['drinkabletable', 'drinkables table', 'drinkable table']],
731 \ ])
732endfunc
733
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200734function FirstSpellWord()
735 call feedkeys("/^start:\n", 'tx')
736 normal ]smm
737 let [str, a] = spellbadword()
738 return str
739endfunc
740
741function SecondSpellWord()
742 normal `m]s
743 let [str, a] = spellbadword()
744 return str
745endfunc
746
747"Test with SAL instead of SOFO items; test automatic reloading
748func Test_zz_sal_and_addition()
749 set enc=latin1
750 set spellfile=
Bram Moolenaar1a0f2002017-07-28 15:38:10 +0200751 call writefile(g:test_data_dic1, "Xtest.dic")
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200752 call writefile(g:test_data_aff_sal, "Xtest.aff")
753 mkspell! Xtest Xtest
754 set spl=Xtest.latin1.spl spell
755 call assert_equal('kbltykk', soundfold('goobledygoook'))
756 call assert_equal('kprnfn', soundfold('kóopërÿnôven'))
757 call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale'))
758
759 "also use an addition file
760 call writefile(["/regions=usgbnz", "elequint/2", "elekwint/3"], "Xtest.latin1.add")
761 mkspell! Xtest.latin1.add.spl Xtest.latin1.add
762
763 bwipe!
764 call setline(1, ["start: elequint test elekwint test elekwent asdf"])
765
766 set spellfile=Xtest.latin1.add
767 call assert_equal("elekwent", FirstSpellWord())
768
769 set spl=Xtest_us.latin1.spl
770 call assert_equal("elequint", FirstSpellWord())
771 call assert_equal("elekwint", SecondSpellWord())
772
773 set spl=Xtest_gb.latin1.spl
774 call assert_equal("elekwint", FirstSpellWord())
775 call assert_equal("elekwent", SecondSpellWord())
776
777 set spl=Xtest_nz.latin1.spl
778 call assert_equal("elequint", FirstSpellWord())
779 call assert_equal("elekwent", SecondSpellWord())
780
781 set spl=Xtest_ca.latin1.spl
782 call assert_equal("elequint", FirstSpellWord())
783 call assert_equal("elekwint", SecondSpellWord())
784endfunc
785
Bram Moolenaar862f1e12019-04-10 22:33:41 +0200786func Test_spellfile_value()
787 set spellfile=Xdir/Xtest.latin1.add
788 set spellfile=Xdir/Xtest.utf-8.add,Xtest_other.add
789endfunc
790
Bram Moolenaaree03b942017-10-27 00:57:05 +0200791func Test_region_error()
792 messages clear
793 call writefile(["/regions=usgbnz", "elequint/0"], "Xtest.latin1.add")
794 mkspell! Xtest.latin1.add.spl Xtest.latin1.add
795 call assert_match('Invalid region nr in Xtest.latin1.add line 2: 0', execute('messages'))
796 call delete('Xtest.latin1.add')
797 call delete('Xtest.latin1.add.spl')
798endfunc
799
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200800" Check using z= in new buffer (crash fixed by patch 7.4a.028).
801func Test_zeq_crash()
802 new
803 set maxmem=512 spell
804 call feedkeys('iasdz=:\"', 'tx')
805
806 bwipe!
807endfunc
808
Bram Moolenaar152e79e2020-06-10 15:32:08 +0200809" Check that z= works even when 'nospell' is set. This test uses one of the
810" tests in Test_spellsuggest_option_number() just to verify that z= basically
811" works and that "E756: Spell checking is not enabled" is not generated.
812func Test_zeq_nospell()
813 new
814 set nospell spellsuggest=1,best
815 call setline(1, 'A baord')
816 try
817 norm $1z=
818 call assert_equal('A board', getline(1))
819 catch
820 call assert_report("Caught exception: " . v:exception)
821 endtry
822 set spell& spellsuggest&
823 bwipe!
824endfunc
825
826" Check that "E756: Spell checking is not possible" is reported when z= is
827" executed and 'spelllang' is empty.
828func Test_zeq_no_spelllang()
829 new
830 set spelllang= spellsuggest=1,best
831 call setline(1, 'A baord')
832 call assert_fails('normal $1z=', 'E756:')
833 set spelllang& spellsuggest&
834 bwipe!
835endfunc
836
Bram Moolenaar5bcc5a12019-08-06 22:48:02 +0200837" Check handling a word longer than MAXWLEN.
838func Test_spell_long_word()
839 set enc=utf-8
840 new
841 call setline(1, "d\xCC\xB4\xCC\xBD\xCD\x88\xCD\x94a\xCC\xB5\xCD\x84\xCD\x84\xCC\xA8\xCD\x9Cr\xCC\xB5\xCC\x8E\xCD\x85\xCD\x85k\xCC\xB6\xCC\x89\xCC\x9D \xCC\xB6\xCC\x83\xCC\x8F\xCC\xA4\xCD\x8Ef\xCC\xB7\xCC\x81\xCC\x80\xCC\xA9\xCC\xB0\xCC\xAC\xCC\xA2\xCD\x95\xCD\x87\xCD\x8D\xCC\x9E\xCD\x99\xCC\xAD\xCC\xAB\xCC\x97\xCC\xBBo\xCC\xB6\xCC\x84\xCC\x95\xCC\x8C\xCC\x8B\xCD\x9B\xCD\x9C\xCC\xAFr\xCC\xB7\xCC\x94\xCD\x83\xCD\x97\xCC\x8C\xCC\x82\xCD\x82\xCD\x80\xCD\x91\xCC\x80\xCC\xBE\xCC\x82\xCC\x8F\xCC\xA3\xCD\x85\xCC\xAE\xCD\x8D\xCD\x99\xCC\xBC\xCC\xAB\xCC\xA7\xCD\x88c\xCC\xB7\xCD\x83\xCC\x84\xCD\x92\xCC\x86\xCC\x83\xCC\x88\xCC\x92\xCC\x94\xCC\xBE\xCC\x9D\xCC\xAF\xCC\x98\xCC\x9D\xCC\xBB\xCD\x8E\xCC\xBB\xCC\xB3\xCC\xA3\xCD\x8E\xCD\x99\xCC\xA5\xCC\xAD\xCC\x99\xCC\xB9\xCC\xAE\xCC\xA5\xCC\x9E\xCD\x88\xCC\xAE\xCC\x9E\xCC\xA9\xCC\x97\xCC\xBC\xCC\x99\xCC\xA5\xCD\x87\xCC\x97\xCD\x8E\xCD\x94\xCC\x99\xCC\x9D\xCC\x96\xCD\x94\xCC\xAB\xCC\xA7\xCC\xA5\xCC\x98\xCC\xBB\xCC\xAF\xCC\xABe\xCC\xB7\xCC\x8E\xCC\x82\xCD\x86\xCD\x9B\xCC\x94\xCD\x83\xCC\x85\xCD\x8A\xCD\x8C\xCC\x8B\xCD\x92\xCD\x91\xCC\x8F\xCC\x81\xCD\x95\xCC\xA2\xCC\xB9\xCC\xB2\xCD\x9C\xCC\xB1\xCC\xA6\xCC\xB3\xCC\xAF\xCC\xAE\xCC\x9C\xCD\x99s\xCC\xB8\xCC\x8C\xCC\x8E\xCC\x87\xCD\x81\xCD\x82\xCC\x86\xCD\x8C\xCD\x8C\xCC\x8B\xCC\x84\xCC\x8C\xCD\x84\xCD\x9B\xCD\x86\xCC\x93\xCD\x90\xCC\x85\xCC\x94\xCD\x98\xCD\x84\xCD\x92\xCD\x8B\xCC\x90\xCC\x83\xCC\x8F\xCD\x84\xCD\x81\xCD\x9B\xCC\x90\xCD\x81\xCC\x8F\xCC\xBD\xCC\x88\xCC\xBF\xCC\x88\xCC\x84\xCC\x8E\xCD\x99\xCD\x94\xCC\x99\xCD\x99\xCC\xB0\xCC\xA8\xCC\xA3\xCC\xA8\xCC\x96\xCC\x99\xCC\xAE\xCC\xBC\xCC\x99\xCD\x9A\xCC\xB2\xCC\xB1\xCC\x9F\xCC\xBB\xCC\xA6\xCD\x85\xCC\xAA\xCD\x89\xCC\x9D\xCC\x99\xCD\x96\xCC\xB1\xCC\xB1\xCC\x99\xCC\xA6\xCC\xA5\xCD\x95\xCC\xB2\xCC\xA0\xCD\x99 within")
842 set spell spelllang=en
843 redraw
844 redraw!
845 bwipe!
846 set nospell
847endfunc
848
Bram Moolenaar06f15412022-01-29 10:51:59 +0000849func Test_spellsuggest_too_deep()
850 " This was incrementing "depth" over MAXWLEN.
851 new
852 norm s000G00ý000000000000
853 sil norm ..vzG................vvzG0 v z=
854 bwipe!
855endfunc
856
Bram Moolenaar5e59ea52022-07-01 22:26:20 +0100857func Test_spell_good_word_invalid()
858 " This was adding a word with a 0x02 byte, which causes havoc.
859 enew
860 norm o0
861 sil! norm rzzWs00/
862 2
863 sil! norm VzGprzzW
864 sil! norm z=
865
866 bwipe!
867 " clear the internal word list
868 set enc=latin1
869 set enc=utf-8
870endfunc
871
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200872func LoadAffAndDic(aff_contents, dic_contents)
873 set enc=latin1
874 set spellfile=
875 call writefile(a:aff_contents, "Xtest.aff")
876 call writefile(a:dic_contents, "Xtest.dic")
877 " Generate a .spl file from a .dic and .aff file.
878 mkspell! Xtest Xtest
879 " use that spell file
880 set spl=Xtest.latin1.spl spell
881endfunc
882
883func ListWords()
884 spelldump
885 %yank
886 quit
887 return split(@", "\n")
888endfunc
889
890func TestGoodBadBase()
891 exe '1;/^good:'
892 normal 0f:]s
893 let prevbad = ''
894 let result = []
895 while 1
896 let [bad, a] = spellbadword()
897 if bad == '' || bad == prevbad || bad == 'badend'
898 break
899 endif
900 let prevbad = bad
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200901 let lst = bad->spellsuggest(3)
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200902 normal mm
903
904 call add(result, [bad, lst])
905 normal `m]s
906 endwhile
907 return result
908endfunc
909
910func RunGoodBad(good, bad, expected_words, expected_bad_words)
911 bwipe!
912 call setline(1, ["good: ", a:good, a:bad, " badend "])
913 let words = ListWords()
914 call assert_equal(a:expected_words, words[1:-1])
915 let bad_words = TestGoodBadBase()
916 call assert_equal(a:expected_bad_words, bad_words)
917 bwipe!
918endfunc
919
Bram Moolenaar7751d1d2019-10-18 20:37:08 +0200920func Test_spell_screendump()
921 CheckScreendump
922
923 let lines =<< trim END
924 call setline(1, [
925 \ "This is some text without any spell errors. Everything",
926 \ "should just be black, nothing wrong here.",
927 \ "",
928 \ "This line has a sepll error. and missing caps.",
929 \ "And and this is the the duplication.",
930 \ "with missing caps here.",
931 \ ])
932 set spell spelllang=en_nz
933 END
934 call writefile(lines, 'XtestSpell')
935 let buf = RunVimInTerminal('-S XtestSpell', {'rows': 8})
936 call VerifyScreenDump(buf, 'Test_spell_1', {})
937
938 " clean up
939 call StopVimInTerminal(buf)
940 call delete('XtestSpell')
941endfunc
942
Bram Moolenaard2c061d2017-06-22 21:42:49 +0200943let g:test_data_aff1 = [
944 \"SET ISO8859-1",
945 \"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ",
946 \"",
947 \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
948 \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
949 \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
950 \"",
951 \"SOFOFROM abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xBF",
952 \"SOFOTO ebctefghejklnnepkrstevvkesebctefghejklnnepkrstevvkeseeeeeeeceeeeeeeedneeeeeeeeeeepseeeeeeeeceeeeeeeedneeeeeeeeeeep?",
953 \"",
954 \"MIDWORD\t'-",
955 \"",
956 \"KEP =",
957 \"RAR ?",
958 \"BAD !",
959 \"",
960 \"PFX I N 1",
961 \"PFX I 0 in .",
962 \"",
963 \"PFX O Y 1",
964 \"PFX O 0 out .",
965 \"",
966 \"SFX S Y 2",
967 \"SFX S 0 s [^s]",
968 \"SFX S 0 es s",
969 \"",
970 \"SFX N N 3",
971 \"SFX N 0 en [^n]",
972 \"SFX N 0 nen n",
973 \"SFX N 0 n .",
974 \"",
975 \"REP 3",
976 \"REP g ch",
977 \"REP ch g",
978 \"REP svp s.v.p.",
979 \"",
980 \"MAP 9",
981 \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
982 \"MAP e\xE8\xE9\xEA\xEB",
983 \"MAP i\xEC\xED\xEE\xEF",
984 \"MAP o\xF2\xF3\xF4\xF5\xF6",
985 \"MAP u\xF9\xFA\xFB\xFC",
986 \"MAP n\xF1",
987 \"MAP c\xE7",
988 \"MAP y\xFF\xFD",
989 \"MAP s\xDF",
990 \ ]
991let g:test_data_dic1 = [
992 \"123456",
993 \"test/NO",
994 \"# comment",
995 \"wrong",
996 \"Comment",
997 \"OK",
998 \"uk",
999 \"put/ISO",
1000 \"the end",
1001 \"deol",
1002 \"d\xE9\xF4r",
1003 \ ]
1004let g:test_data_aff2 = [
1005 \"SET ISO8859-1",
1006 \"",
1007 \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
1008 \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
1009 \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
1010 \"",
1011 \"PFXPOSTPONE",
1012 \"",
1013 \"MIDWORD\t'-",
1014 \"",
1015 \"KEP =",
1016 \"RAR ?",
1017 \"BAD !",
1018 \"",
1019 \"PFX I N 1",
1020 \"PFX I 0 in .",
1021 \"",
1022 \"PFX O Y 1",
1023 \"PFX O 0 out [a-z]",
1024 \"",
1025 \"SFX S Y 2",
1026 \"SFX S 0 s [^s]",
1027 \"SFX S 0 es s",
1028 \"",
1029 \"SFX N N 3",
1030 \"SFX N 0 en [^n]",
1031 \"SFX N 0 nen n",
1032 \"SFX N 0 n .",
1033 \"",
1034 \"REP 3",
1035 \"REP g ch",
1036 \"REP ch g",
1037 \"REP svp s.v.p.",
1038 \"",
1039 \"MAP 9",
1040 \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
1041 \"MAP e\xE8\xE9\xEA\xEB",
1042 \"MAP i\xEC\xED\xEE\xEF",
1043 \"MAP o\xF2\xF3\xF4\xF5\xF6",
1044 \"MAP u\xF9\xFA\xFB\xFC",
1045 \"MAP n\xF1",
1046 \"MAP c\xE7",
1047 \"MAP y\xFF\xFD",
1048 \"MAP s\xDF",
1049 \ ]
1050let g:test_data_aff3 = [
1051 \"SET ISO8859-1",
1052 \"",
1053 \"COMPOUNDMIN 3",
1054 \"COMPOUNDRULE m*",
1055 \"NEEDCOMPOUND x",
1056 \ ]
1057let g:test_data_dic3 = [
1058 \"1234",
1059 \"foo/m",
1060 \"bar/mx",
1061 \"m\xEF/m",
1062 \"la/mx",
1063 \ ]
1064let g:test_data_aff4 = [
1065 \"SET ISO8859-1",
1066 \"",
1067 \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
1068 \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
1069 \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
1070 \"",
1071 \"COMPOUNDRULE m+",
1072 \"COMPOUNDRULE sm*e",
1073 \"COMPOUNDRULE sm+",
1074 \"COMPOUNDMIN 3",
1075 \"COMPOUNDWORDMAX 3",
1076 \"COMPOUNDFORBIDFLAG t",
1077 \"",
1078 \"COMPOUNDSYLMAX 5",
1079 \"SYLLABLE a\xE1e\xE9i\xEDo\xF3\xF6\xF5u\xFA\xFC\xFBy/aa/au/ea/ee/ei/ie/oa/oe/oo/ou/uu/ui",
1080 \"",
1081 \"MAP 9",
1082 \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
1083 \"MAP e\xE8\xE9\xEA\xEB",
1084 \"MAP i\xEC\xED\xEE\xEF",
1085 \"MAP o\xF2\xF3\xF4\xF5\xF6",
1086 \"MAP u\xF9\xFA\xFB\xFC",
1087 \"MAP n\xF1",
1088 \"MAP c\xE7",
1089 \"MAP y\xFF\xFD",
1090 \"MAP s\xDF",
1091 \"",
1092 \"NEEDAFFIX x",
1093 \"",
1094 \"PFXPOSTPONE",
1095 \"",
1096 \"MIDWORD '-",
1097 \"",
1098 \"SFX q N 1",
1099 \"SFX q 0 -ok .",
1100 \"",
1101 \"SFX a Y 2",
1102 \"SFX a 0 s .",
1103 \"SFX a 0 ize/t .",
1104 \"",
1105 \"PFX p N 1",
1106 \"PFX p 0 pre .",
1107 \"",
1108 \"PFX P N 1",
1109 \"PFX P 0 nou .",
1110 \ ]
1111let g:test_data_dic4 = [
1112 \"1234",
1113 \"word/mP",
1114 \"util/am",
1115 \"pro/xq",
1116 \"tomato/m",
1117 \"bork/mp",
1118 \"start/s",
1119 \"end/e",
1120 \ ]
1121let g:test_data_aff5 = [
1122 \"SET ISO8859-1",
1123 \"",
1124 \"FLAG long",
1125 \"",
1126 \"NEEDAFFIX !!",
1127 \"",
1128 \"COMPOUNDRULE ssmm*ee",
1129 \"",
1130 \"NEEDCOMPOUND xx",
1131 \"COMPOUNDPERMITFLAG pp",
1132 \"",
1133 \"SFX 13 Y 1",
1134 \"SFX 13 0 bork .",
1135 \"",
1136 \"SFX a1 Y 1",
1137 \"SFX a1 0 a1 .",
1138 \"",
1139 \"SFX a\xE9 Y 1",
1140 \"SFX a\xE9 0 a\xE9 .",
1141 \"",
1142 \"PFX zz Y 1",
1143 \"PFX zz 0 pre/pp .",
1144 \"",
1145 \"PFX yy Y 1",
1146 \"PFX yy 0 nou .",
1147 \ ]
1148let g:test_data_dic5 = [
1149 \"1234",
1150 \"foo/a1a\xE9!!",
1151 \"bar/zz13ee",
1152 \"start/ss",
1153 \"end/eeyy",
1154 \"middle/mmxx",
1155 \ ]
1156let g:test_data_aff6 = [
1157 \"SET ISO8859-1",
1158 \"",
1159 \"FLAG caplong",
1160 \"",
1161 \"NEEDAFFIX A!",
1162 \"",
1163 \"COMPOUNDRULE sMm*Ee",
1164 \"",
1165 \"NEEDCOMPOUND Xx",
1166 \"",
1167 \"COMPOUNDPERMITFLAG p",
1168 \"",
1169 \"SFX N3 Y 1",
1170 \"SFX N3 0 bork .",
1171 \"",
1172 \"SFX A1 Y 1",
1173 \"SFX A1 0 a1 .",
1174 \"",
1175 \"SFX A\xE9 Y 1",
1176 \"SFX A\xE9 0 a\xE9 .",
1177 \"",
1178 \"PFX Zz Y 1",
1179 \"PFX Zz 0 pre/p .",
1180 \ ]
1181let g:test_data_dic6 = [
1182 \"1234",
1183 \"mee/A1A\xE9A!",
1184 \"bar/ZzN3Ee",
1185 \"lead/s",
1186 \"end/Ee",
1187 \"middle/MmXx",
1188 \ ]
1189let g:test_data_aff7 = [
1190 \"SET ISO8859-1",
1191 \"",
1192 \"FLAG num",
1193 \"",
1194 \"NEEDAFFIX 9999",
1195 \"",
1196 \"COMPOUNDRULE 2,77*123",
1197 \"",
1198 \"NEEDCOMPOUND 1",
1199 \"COMPOUNDPERMITFLAG 432",
1200 \"",
1201 \"SFX 61003 Y 1",
1202 \"SFX 61003 0 meat .",
1203 \"",
Bram Moolenaar3d2a47c2019-11-07 20:48:42 +01001204 \"SFX 0 Y 1",
1205 \"SFX 0 0 zero .",
1206 \"",
Bram Moolenaard2c061d2017-06-22 21:42:49 +02001207 \"SFX 391 Y 1",
1208 \"SFX 391 0 a1 .",
1209 \"",
1210 \"SFX 111 Y 1",
1211 \"SFX 111 0 a\xE9 .",
1212 \"",
1213 \"PFX 17 Y 1",
1214 \"PFX 17 0 pre/432 .",
1215 \ ]
1216let g:test_data_dic7 = [
1217 \"1234",
Bram Moolenaar3d2a47c2019-11-07 20:48:42 +01001218 \"mee/0,391,111,9999",
Bram Moolenaard2c061d2017-06-22 21:42:49 +02001219 \"bar/17,61003,123",
1220 \"lead/2",
1221 \"tail/123",
1222 \"middle/77,1",
1223 \ ]
1224let g:test_data_aff8 = [
1225 \"SET ISO8859-1",
1226 \"",
1227 \"NOSPLITSUGS",
1228 \ ]
1229let g:test_data_dic8 = [
1230 \"1234",
1231 \"foo",
1232 \"bar",
1233 \"faabar",
1234 \ ]
1235let g:test_data_aff9 = [
1236 \ ]
1237let g:test_data_dic9 = [
1238 \"1234",
1239 \"foo",
1240 \"bar",
1241 \ ]
Bram Moolenaar37ff4cf2019-11-17 20:10:20 +01001242let g:test_data_aff10 = [
1243 \"COMPOUNDRULE se",
1244 \"COMPOUNDPERMITFLAG p",
1245 \"",
1246 \"SFX A Y 1",
1247 \"SFX A 0 able/Mp .",
1248 \"",
1249 \"SFX M Y 1",
1250 \"SFX M 0 s .",
1251 \ ]
1252let g:test_data_dic10 = [
1253 \"1234",
1254 \"drink/As",
1255 \"table/e",
1256 \ ]
Bram Moolenaard2c061d2017-06-22 21:42:49 +02001257let g:test_data_aff_sal = [
1258 \"SET ISO8859-1",
1259 \"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ",
1260 \"",
1261 \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
1262 \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
1263 \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
1264 \"",
1265 \"MIDWORD\t'-",
1266 \"",
1267 \"KEP =",
1268 \"RAR ?",
1269 \"BAD !",
1270 \"",
1271 \"PFX I N 1",
1272 \"PFX I 0 in .",
1273 \"",
1274 \"PFX O Y 1",
1275 \"PFX O 0 out .",
1276 \"",
1277 \"SFX S Y 2",
1278 \"SFX S 0 s [^s]",
1279 \"SFX S 0 es s",
1280 \"",
1281 \"SFX N N 3",
1282 \"SFX N 0 en [^n]",
1283 \"SFX N 0 nen n",
1284 \"SFX N 0 n .",
1285 \"",
1286 \"REP 3",
1287 \"REP g ch",
1288 \"REP ch g",
1289 \"REP svp s.v.p.",
1290 \"",
1291 \"MAP 9",
1292 \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
1293 \"MAP e\xE8\xE9\xEA\xEB",
1294 \"MAP i\xEC\xED\xEE\xEF",
1295 \"MAP o\xF2\xF3\xF4\xF5\xF6",
1296 \"MAP u\xF9\xFA\xFB\xFC",
1297 \"MAP n\xF1",
1298 \"MAP c\xE7",
1299 \"MAP y\xFF\xFD",
1300 \"MAP s\xDF",
1301 \"",
1302 \"SAL AH(AEIOUY)-^ *H",
1303 \"SAL AR(AEIOUY)-^ *R",
1304 \"SAL A(HR)^ *",
1305 \"SAL A^ *",
1306 \"SAL AH(AEIOUY)- H",
1307 \"SAL AR(AEIOUY)- R",
1308 \"SAL A(HR) _",
1309 \"SAL \xC0^ *",
1310 \"SAL \xC5^ *",
1311 \"SAL BB- _",
1312 \"SAL B B",
1313 \"SAL CQ- _",
1314 \"SAL CIA X",
1315 \"SAL CH X",
1316 \"SAL C(EIY)- S",
1317 \"SAL CK K",
1318 \"SAL COUGH^ KF",
1319 \"SAL CC< C",
1320 \"SAL C K",
1321 \"SAL DG(EIY) K",
1322 \"SAL DD- _",
1323 \"SAL D T",
1324 \"SAL \xC9< E",
1325 \"SAL EH(AEIOUY)-^ *H",
1326 \"SAL ER(AEIOUY)-^ *R",
1327 \"SAL E(HR)^ *",
1328 \"SAL ENOUGH^$ *NF",
1329 \"SAL E^ *",
1330 \"SAL EH(AEIOUY)- H",
1331 \"SAL ER(AEIOUY)- R",
1332 \"SAL E(HR) _",
1333 \"SAL FF- _",
1334 \"SAL F F",
1335 \"SAL GN^ N",
1336 \"SAL GN$ N",
1337 \"SAL GNS$ NS",
1338 \"SAL GNED$ N",
1339 \"SAL GH(AEIOUY)- K",
1340 \"SAL GH _",
1341 \"SAL GG9 K",
1342 \"SAL G K",
1343 \"SAL H H",
1344 \"SAL IH(AEIOUY)-^ *H",
1345 \"SAL IR(AEIOUY)-^ *R",
1346 \"SAL I(HR)^ *",
1347 \"SAL I^ *",
1348 \"SAL ING6 N",
1349 \"SAL IH(AEIOUY)- H",
1350 \"SAL IR(AEIOUY)- R",
1351 \"SAL I(HR) _",
1352 \"SAL J K",
1353 \"SAL KN^ N",
1354 \"SAL KK- _",
1355 \"SAL K K",
1356 \"SAL LAUGH^ LF",
1357 \"SAL LL- _",
1358 \"SAL L L",
1359 \"SAL MB$ M",
1360 \"SAL MM M",
1361 \"SAL M M",
1362 \"SAL NN- _",
1363 \"SAL N N",
1364 \"SAL OH(AEIOUY)-^ *H",
1365 \"SAL OR(AEIOUY)-^ *R",
1366 \"SAL O(HR)^ *",
1367 \"SAL O^ *",
1368 \"SAL OH(AEIOUY)- H",
1369 \"SAL OR(AEIOUY)- R",
1370 \"SAL O(HR) _",
1371 \"SAL PH F",
1372 \"SAL PN^ N",
1373 \"SAL PP- _",
1374 \"SAL P P",
1375 \"SAL Q K",
1376 \"SAL RH^ R",
1377 \"SAL ROUGH^ RF",
1378 \"SAL RR- _",
1379 \"SAL R R",
1380 \"SAL SCH(EOU)- SK",
1381 \"SAL SC(IEY)- S",
1382 \"SAL SH X",
1383 \"SAL SI(AO)- X",
1384 \"SAL SS- _",
1385 \"SAL S S",
1386 \"SAL TI(AO)- X",
1387 \"SAL TH @",
1388 \"SAL TCH-- _",
1389 \"SAL TOUGH^ TF",
1390 \"SAL TT- _",
1391 \"SAL T T",
1392 \"SAL UH(AEIOUY)-^ *H",
1393 \"SAL UR(AEIOUY)-^ *R",
1394 \"SAL U(HR)^ *",
1395 \"SAL U^ *",
1396 \"SAL UH(AEIOUY)- H",
1397 \"SAL UR(AEIOUY)- R",
1398 \"SAL U(HR) _",
1399 \"SAL V^ W",
1400 \"SAL V F",
1401 \"SAL WR^ R",
1402 \"SAL WH^ W",
1403 \"SAL W(AEIOU)- W",
1404 \"SAL X^ S",
1405 \"SAL X KS",
1406 \"SAL Y(AEIOU)- Y",
1407 \"SAL ZZ- _",
1408 \"SAL Z S",
1409 \ ]
Bram Moolenaar0e05de42020-03-25 22:23:46 +01001410
1411" vim: shiftwidth=2 sts=2 expandtab