spellfile.vim 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. " Vim script to download a missing spell file
  2. if !exists('g:spellfile_URL')
  3. " Always use https:// because it's secure. The certificate is for nluug.nl,
  4. " thus we can't use the alias ftp.vim.org here.
  5. let g:spellfile_URL = 'https://ftp.nluug.nl/pub/vim/runtime/spell'
  6. endif
  7. let s:spellfile_URL = '' " Start with nothing so that s:donedict is reset.
  8. " This function is used for the spellfile plugin.
  9. function! spellfile#LoadFile(lang)
  10. " Check for sandbox/modeline. #11359
  11. try
  12. :!
  13. catch /\<E12\>/
  14. throw 'Cannot download spellfile in sandbox/modeline. Try ":set spell" from the cmdline.'
  15. endtry
  16. " If the netrw plugin isn't loaded we silently skip everything.
  17. if !exists(":Nread")
  18. if &verbose
  19. echomsg 'spellfile#LoadFile(): Nread command is not available.'
  20. endif
  21. return
  22. endif
  23. let lang = tolower(a:lang)
  24. " If the URL changes we try all files again.
  25. if s:spellfile_URL != g:spellfile_URL
  26. let s:donedict = {}
  27. let s:spellfile_URL = g:spellfile_URL
  28. endif
  29. " I will say this only once!
  30. if has_key(s:donedict, lang . &enc)
  31. if &verbose
  32. echomsg 'spellfile#LoadFile(): Tried this language/encoding before.'
  33. endif
  34. return
  35. endif
  36. let s:donedict[lang . &enc] = 1
  37. " Find spell directories we can write in.
  38. let [dirlist, dirchoices] = spellfile#GetDirChoices()
  39. if len(dirlist) == 0
  40. let dir_to_create = spellfile#WritableSpellDir()
  41. if &verbose || dir_to_create != ''
  42. echomsg 'spellfile#LoadFile(): No (writable) spell directory found.'
  43. endif
  44. if dir_to_create != ''
  45. call mkdir(dir_to_create, "p")
  46. " Now it should show up in the list.
  47. let [dirlist, dirchoices] = spellfile#GetDirChoices()
  48. endif
  49. if len(dirlist) == 0
  50. echomsg 'Failed to create: '.dir_to_create
  51. return
  52. else
  53. echomsg 'Created '.dir_to_create
  54. endif
  55. endif
  56. let msg = 'No spell file for "' . a:lang . '" in ' . &enc
  57. let msg .= "\nDownload it?"
  58. if confirm(msg, "&Yes\n&No", 2) == 1
  59. let enc = &encoding
  60. if enc == 'iso-8859-15'
  61. let enc = 'latin1'
  62. endif
  63. let fname = a:lang . '.' . enc . '.spl'
  64. " Split the window, read the file into a new buffer.
  65. " Remember the buffer number, we check it below.
  66. new
  67. let newbufnr = winbufnr(0)
  68. setlocal bin fenc=
  69. echo 'Downloading ' . fname . '...'
  70. call spellfile#Nread(fname)
  71. if getline(2) !~ 'VIMspell'
  72. " Didn't work, perhaps there is an ASCII one.
  73. " Careful: Nread() may have opened a new window for the error message,
  74. " we need to go back to our own buffer and window.
  75. if newbufnr != winbufnr(0)
  76. let winnr = bufwinnr(newbufnr)
  77. if winnr == -1
  78. " Our buffer has vanished!? Open a new window.
  79. echomsg "download buffer disappeared, opening a new one"
  80. new
  81. setlocal bin fenc=
  82. else
  83. exe winnr . "wincmd w"
  84. endif
  85. endif
  86. if newbufnr == winbufnr(0)
  87. " We are back to the old buffer, remove any (half-finished) download.
  88. keeppatterns g/^/d_
  89. else
  90. let newbufnr = winbufnr(0)
  91. endif
  92. let fname = lang . '.ascii.spl'
  93. echo 'Could not find it, trying ' . fname . '...'
  94. call spellfile#Nread(fname)
  95. if getline(2) !~ 'VIMspell'
  96. echo 'Download failed'
  97. exe newbufnr . "bwipe!"
  98. return
  99. endif
  100. endif
  101. " Delete the empty first line and mark the file unmodified.
  102. 1d_
  103. set nomod
  104. if len(dirlist) == 1
  105. let dirchoice = 0
  106. else
  107. let msg = "In which directory do you want to write the file:"
  108. for i in range(len(dirlist))
  109. let msg .= "\n" . (i + 1) . '. ' . dirlist[i]
  110. endfor
  111. let dirchoice = confirm(msg, dirchoices) - 2
  112. endif
  113. if dirchoice >= 0
  114. if exists('*fnameescape')
  115. let dirname = fnameescape(dirlist[dirchoice])
  116. else
  117. let dirname = escape(dirlist[dirchoice], ' ')
  118. endif
  119. setlocal fenc=
  120. exe "write " . dirname . '/' . fname
  121. " Also download the .sug file.
  122. keeppatterns g/^/d_
  123. let fname = substitute(fname, '\.spl$', '.sug', '')
  124. echo 'Downloading ' . fname . '...'
  125. call spellfile#Nread(fname)
  126. if getline(2) =~ 'VIMsug'
  127. 1d_
  128. exe "write " . dirname . '/' . fname
  129. set nomod
  130. else
  131. echo 'Download failed'
  132. " Go back to our own buffer/window, Nread() may have taken us to
  133. " another window.
  134. if newbufnr != winbufnr(0)
  135. let winnr = bufwinnr(newbufnr)
  136. if winnr != -1
  137. exe winnr . "wincmd w"
  138. endif
  139. endif
  140. if newbufnr == winbufnr(0)
  141. set nomod
  142. endif
  143. endif
  144. endif
  145. " Wipe out the buffer we used.
  146. exe newbufnr . "bwipe"
  147. endif
  148. endfunc
  149. " Read "fname" from the server.
  150. function! spellfile#Nread(fname)
  151. " We do our own error handling, don't want a window for it.
  152. if exists("g:netrw_use_errorwindow")
  153. let save_ew = g:netrw_use_errorwindow
  154. endif
  155. let g:netrw_use_errorwindow=0
  156. if g:spellfile_URL =~ '^ftp://'
  157. " for an ftp server use a default login and password to avoid a prompt
  158. let machine = substitute(g:spellfile_URL, 'ftp://\([^/]*\).*', '\1', '')
  159. let dir = substitute(g:spellfile_URL, 'ftp://[^/]*/\(.*\)', '\1', '')
  160. exe 'Nread "' . machine . ' anonymous vim7user ' . dir . '/' . a:fname . '"'
  161. else
  162. exe 'Nread ' g:spellfile_URL . '/' . a:fname
  163. endif
  164. if exists("save_ew")
  165. let g:netrw_use_errorwindow = save_ew
  166. else
  167. unlet g:netrw_use_errorwindow
  168. endif
  169. endfunc
  170. " Get a list of writable spell directories and choices for confirm().
  171. function! spellfile#GetDirChoices()
  172. let dirlist = []
  173. let dirchoices = '&Cancel'
  174. for dir in split(globpath(&rtp, 'spell'), "\n")
  175. if filewritable(dir) == 2
  176. call add(dirlist, dir)
  177. let dirchoices .= "\n&" . len(dirlist)
  178. endif
  179. endfor
  180. return [dirlist, dirchoices]
  181. endfunc
  182. function! spellfile#WritableSpellDir()
  183. " Always use the $XDG_DATA_HOME/…/site directory
  184. return stdpath('data').'/site/spell'
  185. endfunction