Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 1 | " Test for URLs in help documents. |
| 2 | " |
| 3 | " Opens a new window with all found URLS followed by return code from curl |
| 4 | " (anything other than 0 means unreachable) |
| 5 | " |
| 6 | " Written by Christian Brabandt. |
| 7 | |
| 8 | func Test_check_URLs() |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 9 | "20.10.23, added by Restorer |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 10 | if has("win32") |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 11 | let s:outdev = 'nul' |
| 12 | else |
| 13 | let s:outdev = '/dev/null' |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 14 | endif |
Christian Brabandt | 1c5728e | 2024-05-11 11:12:40 +0200 | [diff] [blame] | 15 | " Restorer: For Windows users. If "curl" or "wget" is installed on the system |
| 16 | " but not in %PATH%, add the full path to them to %PATH% environment variable. |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 17 | if executable('curl') |
| 18 | " Note: does not follow redirects! |
Christian Brabandt | 1c5728e | 2024-05-11 11:12:40 +0200 | [diff] [blame] | 19 | let s:command1 = 'curl --silent --max-time 5 --fail --output ' ..s:outdev.. ' --head ' |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 20 | let s:command2 = "" |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 21 | elseif executable('wget') |
| 22 | " Note: only allow a couple of redirects |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 23 | let s:command1 = 'wget --quiet -S --spider --max-redirect=2 --timeout=5 --tries=2 -O ' ..s:outdev.. ' ' |
| 24 | let s:command2 = "" |
| 25 | elseif has("win32") "20.10.23, added by Restorer |
| 26 | if executable('powershell') |
| 27 | if 2 == system('powershell -nologo -noprofile "$psversiontable.psversion.major"') |
| 28 | echoerr 'To work in OS Windows requires the program "PowerShell" version 3.0 or higher' |
| 29 | return |
| 30 | endif |
| 31 | let s:command1 = |
| 32 | \ "powershell -nologo -noprofile \"{[Net.ServicePointManager]::SecurityProtocol = 'Tls12, Tls11, Tls, Ssl3'};try{(Invoke-WebRequest -MaximumRedirection 2 -TimeoutSec 5 -Uri " |
| 33 | let s:command2 = ').StatusCode}catch{exit [int]$Error[0].Exception.Status}"' |
| 34 | endif |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 35 | else |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 36 | echoerr 'Only works when "curl" or "wget", or "powershell" is available' |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 37 | return |
| 38 | endif |
| 39 | |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 40 | " Do the testing. |
| 41 | set report =999 |
| 42 | set nomore shm +=s |
| 43 | |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 44 | let pat='\(https\?\|ftp\)://[^\t* ]\+' |
| 45 | exe 'helpgrep' pat |
| 46 | helpclose |
| 47 | |
| 48 | let urls = map(getqflist(), 'v:val.text') |
| 49 | " do not use submatch(1)! |
| 50 | let urls = map(urls, {key, val -> matchstr(val, pat)}) |
| 51 | " remove examples like user@host (invalid urls) |
| 52 | let urls = filter(urls, 'v:val !~ "@"') |
| 53 | " Remove example URLs which are invalid |
| 54 | let urls = filter(urls, {key, val -> val !~ '\<\(\(my\|some\)\?host\|machine\|hostname\|file\)\>'}) |
| 55 | new |
| 56 | put =urls |
| 57 | " remove some more invalid items |
| 58 | " empty lines |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 59 | "20.10.23, Restorer: '_' is a little faster, see `:h global` |
| 60 | v/./d _ |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 61 | " remove # anchors |
| 62 | %s/#.*$//e |
| 63 | " remove trailing stuff (parenthesis, dot, comma, quotes), but only for HTTP |
| 64 | " links |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 65 | g/^h/s#[.),'"`/>][:.,]\?$## |
| 66 | g#^[hf]t\?tp:/\(/\?\.*\)$#d _ |
| 67 | silent! g/ftp://,$/d _ |
| 68 | silent! g/=$/d _ |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 69 | let a = getline(1,'$') |
| 70 | let a = uniq(sort(a)) |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 71 | %d _ |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 72 | call setline(1, a) |
| 73 | |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 74 | %s/.*/\=TestURL(submatch(0))/ |
| 75 | |
| 76 | " highlight the failures |
| 77 | /.* \([0-9]*[1-9]\|[0-9]\{2,}\)$ |
| 78 | endfunc |
| 79 | |
| 80 | func TestURL(url) |
| 81 | " Relies on the return code to determine whether a page is valid |
| 82 | echom printf("Testing URL: %d/%d %s", line('.'), line('$'), a:url) |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 83 | call system(s:command1 .. shellescape(a:url) .. s:command2) |
Bram Moolenaar | f38c86e | 2017-11-28 14:19:07 +0100 | [diff] [blame] | 84 | return printf("%s %d", a:url, v:shell_error) |
| 85 | endfunc |
| 86 | |
| 87 | call Test_check_URLs() |
Restorer | b23c1fc | 2023-11-04 08:57:09 +0000 | [diff] [blame] | 88 | |
| 89 | " vim: sw=2 sts=2 et |