├── README ├── doc └── LanguageTool.txt └── plugin └── LanguageTool.vim /README: -------------------------------------------------------------------------------- 1 | This is a mirror of http://www.vim.org/scripts/script.php?script_id=3223 2 | 3 | This plugin integrates the LanguageTool grammar checker into Vim. 4 | Current version of LanguageTool can check grammar in many languages 5 | See the list of supported languages: http://www.languagetool.org/languages/ 6 | or http://www.languagetool.org/ or more information about LanguageTool. 7 | 8 | The script defines 2 commands: 9 | 10 | * Use :LanguageToolCheck to check grammar in current buffer. 11 | This will check for grammar mistakes in text of current buffer 12 | and highlight the errors. It also opens a new scratch window with the 13 | list of grammar errors with further explanations for each error. 14 | Pressing in scratch buffer will jump to that error. The 15 | location list for the buffer being checked is also populated. 16 | So you can use location commands such as :lopen to open the location 17 | list window, :lne to jump to the next error, etc. 18 | 19 | * Use :LanguageToolClear to remove highlighting of grammar mistakes, 20 | close the scratch window containing the list of errors, clear and 21 | close the location list. 22 | 23 | See screenshots of grammar checking in English and French at: 24 | http://dominique.pelle.free.fr/pic/LanguageToolVimPlugin_en.png 25 | http://dominique.pelle.free.fr/pic/LanguageToolVimPlugin_fr.png 26 | 27 | Demo: 28 | http://shelr.tv/records/4fba8ef99660803e4f00001f 29 | 30 | See :help LanguageTool for more details. 31 | 32 | License: 33 | The VIM LICENSE applies to LanguageTool.vim plugin 34 | (see ":help copyright" except use "LanguageTool.vim" instead of Vim"). 35 | -------------------------------------------------------------------------------- /doc/LanguageTool.txt: -------------------------------------------------------------------------------- 1 | *LanguageTool.txt* A grammar checker in Vim for English, French, German, etc. 2 | *LanguageTool* 3 | 4 | Author: Dominique Pellé 5 | Last Change: 20 Feb 2014 6 | 7 | For Vim version 7.0 and above 8 | 9 | ============================================================================ 10 | 11 | 1. Overview |languagetool-overview| 12 | 2. Screenshots & Demo |languagetool-screenshots| 13 | 3. Download |languagetool-download| 14 | 4. Installation |languagetool-installation| 15 | 5. Configuration |languagetool-configuration| 16 | 6. Features |languagetool-features| 17 | 7. Bugs |languagetool-bugs| 18 | 8. License |languagetool-license| 19 | 20 | ============================================================================ 21 | 22 | 1. Overview *languagetool-overview* 23 | 24 | This plugin integrates LanguageTool into Vim. LanguageTool is an Open Source 25 | style and grammar checker for English, French, German, etc. See 26 | http://www.languagetool.org/languages/ for a complete list of supported 27 | languages. 28 | 29 | LanguageTool detects grammar mistakes that a spelling checker cannot detect 30 | such as "it work" instead of "it works". Since version 1.8, LanguageTool 31 | can also detect spelling mistakes using Hunspell dictionaries bundled with 32 | LanguageTool for several languages or using morfologik for other languages. 33 | Vim builtin spelling checker can also of course be used along with 34 | LanguageTool. One advantage of the spelling checker of LanguageTool over 35 | Vim spelling checker, is that it uses the native Hunspell dictionary directly, 36 | so it works even with the latest Hunspell dictionaries containing features 37 | not supported by Vim. For example, the latest French Hunspell dictionaries 38 | from http://www.dicollect.org are not supported by Vim but they work well 39 | with LanguageTool. On the other hand, the Vim native spelling checker is 40 | faster and better integrated with Vim. 41 | 42 | See http://www.languagetool.org/ for more information about LanguageTool. 43 | 44 | ============================================================================ 45 | 46 | 2. Screenshots & Demo *languagetool-screenshots* 47 | 48 | If you don't have time to read help files, these screenshots will give you 49 | an idea of what the LanguageTool plugin does: 50 | 51 | http://dominique.pelle.free.fr/pic/LanguageToolVimPlugin_en.png 52 | http://dominique.pelle.free.fr/pic/LanguageToolVimPlugin_fr.png 53 | 54 | A screencast demo is also available at: 55 | 56 | http://shelr.tv/records/4fba8ef99660803e4f00001f 57 | 58 | ============================================================================ 59 | 60 | 3. Download *languagetool-download* 61 | 62 | You can download the latest version of this plugin from: 63 | 64 | http://www.vim.org/scripts/script.php?script_id=3223 65 | 66 | LanguageTool can be downloaded from: 67 | 68 | http://www.languagetool.org/ 69 | 70 | ============================================================================ 71 | 72 | 4. Installation *languagetool-installation* 73 | 74 | 4.1 Installing the plugin 75 | 76 | Unzip file LanguageTool.zip plugin from in your personal |vimfiles| directory 77 | (~/.vim under Unix or %HOMEPATH%\vimfiles under Windows): > 78 | 79 | $ mkdir ~/.vim 80 | $ cd ~/.vim 81 | $ unzip /path-to/LanguageTool.zip 82 | $ vim -c 'helptags ~/.vim/doc' 83 | 84 | The zip file contains the following files: > 85 | 86 | plugin/LanguageTool.vim 87 | doc/LanguageTool.vim 88 | 89 | You have to enable plugins by adding these two lines in your |.vimrc| file: > 90 | 91 | set nocompatible 92 | filetype plugin on 93 | 94 | 4.2 Installing LanguageTool 95 | 96 | To use this plugin, you need to install the Java LanguageTool program. You 97 | can choose to: 98 | 99 | * download stand-alone version of LanguageTool (LanguageTool-*.zip) from: 100 | http://www.languagetool.org/ using the orange button labelled 101 | "Download LanguageTool for stand-alone use". The standalone version of 102 | Vim not only does grammar checking but also contains Hunspell dictionaries 103 | for spell checking. 104 | * or download a nightly build LanguageTool-.*-snapshot.zip from 105 | http://www.languagetool.org/download/snapshots/. It contains a more 106 | recent version than the stable version but it is not as well tested. 107 | * or checkout and build the latest LanguageTool from sources in git. 108 | 109 | Recent versions of LanguageTool require Java-7. 110 | 111 | 4.2.1 Download the stand-alone version of LanguageTool 112 | 113 | Download the stand-alone version of LanguageTool (LanguageTool-*.zip) 114 | from http://www.languagetool.org/, click on "LanguageTool stand-alone 115 | for your desktop" to download it. Unzip it: > 116 | 117 | $ unzip LanguageTool-2.4.1.zip 118 | 119 | This should extract the file LanguageTool-2.4.1/languagetool-commandline.jar 120 | among several other files. 121 | 122 | 4.2.2 Build LanguageTool from sources in git 123 | 124 | If you prefer to build LanguageTool yourself from sources, you first need 125 | to install the pre-requisite packages. On Ubuntu, you need to install the 126 | following packages: > 127 | 128 | $ sudo apt-get install openjdk-7-jdk mvn git 129 | 130 | LanguageTool can then be downloaded and built with Maven as follows: > 131 | 132 | $ git clone https://github.com/languagetool-org/languagetool.git 133 | $ cd languagetool 134 | $ mvn clean package 135 | 136 | After the build, the command line version of LanguageTool can be found in: > 137 | 138 | ./languagetool-standalone/target/LanguageTool-2.5-SNAPSHOT/LanguageTool-2.5-SNAPSHOT/languagetool-commandline.jar 139 | 140 | 4.3 Configuring the location of the jar file 141 | 142 | After installing LanguageTool, you must specify the location of the file 143 | languagetool-commandline.jar in your $HOME/.vimrc file. Example: > 144 | 145 | let g:languagetool_jar='$HOME/languagetool/languagetool-standalone/target/LanguageTool-2.5-SNAPSHOT/LanguageTool-2.5-SNAPSHOT/languagetool-commandline.jar' 146 | 147 | See section |languagetool-configuration| for more optional settings. 148 | 149 | ============================================================================ 150 | 151 | 5. Configuration *languagetool-configuration* 152 | 153 | LanguageTool plugin uses character encoding from the 'fenc' option or from 154 | the 'enc' option if 'fenc' is empty. 155 | 156 | Several global variables can be set in your |vimrc| to configure the behavior 157 | of the LanguageTool plugin. 158 | 159 | g:languagetool_jar *g:languagetool_jar* 160 | 161 | This variable specifies the location of the LanguageTool java grammar 162 | checker program. Default is empty. 163 | 164 | Example: > 165 | 166 | :let g:languagetool_jar='$HOME/languagetool/languagetool-standalone/target/LanguageTool-2.5-SNAPSHOT/LanguageTool-2.5-SNAPSHOT/languagetool-commandline.jar' 167 | 168 | g:languagetool_lang *g:languagetool_lang* 169 | 170 | The language code to use for the language tool checker. If undefined, 171 | plugin tries to guess the language of the Vim spelling checker 172 | 'spelllang' or v:lang. If neither works, plugin defaults to 173 | English US (en-US). Starting with LanguageTool-1.8, regional variants 174 | of some languages can be specified. For languages with variants 175 | (currently English and German), it is necessary to specify the 176 | variant in order for LanguageTool to signal spelling errors. 177 | In other words, with :set spelllang=en LanguageTool only 178 | signals grammar mistakes whereas with :set spellllang=en_us 179 | LanguageTool signals spelling mistakes and grammar mistakes. 180 | The valid language codes are: > 181 | 182 | ast Asturian 183 | be Belarusian 184 | br Breton 185 | ca Catalan 186 | cs Czech 187 | da Danish 188 | de German 189 | de-AT German (Austria) 190 | de-CH German (Switzerland) 191 | de-DE German (Germany) 192 | el Greek 193 | en English 194 | en-AU English (Australia) 195 | en-CA English (Canada) 196 | en-GB English (Great Britain) 197 | en-NZ English (New Zealand) 198 | en-US English (US) 199 | en-ZA English (South Africa) 200 | eo Esperanto 201 | es Spanish 202 | fr French 203 | gl Galician 204 | is Icelandic 205 | it Italian 206 | km Khmer 207 | lt Lithuanian 208 | ml Malayalam 209 | nl Dutch 210 | pl Polish 211 | pt Portuguese 212 | ro Romanian 213 | ru Russian 214 | sk Slovak 215 | sl Slovenian 216 | sv Swedish 217 | tl Tagalog 218 | uk Ukrainian 219 | zh Chinese 220 | 221 | g:languagetool_disable_rules *g:languagetool_disable_rules* 222 | 223 | This variable specifies checker rules which are disabled. Each disabled 224 | rule must be comma separated. 225 | Default value set by plugin is: WHITESPACE_RULE,EN_QUOTES 226 | 227 | g:languagetool_win_height *g:languagetool_win_height* 228 | 229 | This variable specifies the height of the scratch window which contains 230 | all grammatical mistakes with some explanations. You can use a negative 231 | value to disable opening the scratch window. You can also make it empty '' 232 | to let Vim pick a default size. 233 | Default is: 14 234 | 235 | You can also customize the following syntax highlighting groups: > 236 | 237 | LanguageToolGrammarError 238 | LanguageToolSpellingError 239 | LanguageToolCmd 240 | LanguageToolLabel 241 | LanguageToolErrorCount 242 | 243 | ============================================================================ 244 | 245 | 6. Features *languagetool-features* 246 | 247 | The LanguageTool plugin defines 2 commands |:LanguageToolCheck| and 248 | |:LanguageToolClean|. 249 | 250 | :LanguageToolCheck *:LanguageToolCheck* 251 | 252 | Use the |:LanguageToolCheck| command to check the grammar in the current 253 | buffer. This will highlight errors in the buffer. It will also open a new 254 | scratch window with the list of grammar mistakes with further explanations 255 | for each error. It also populates the location-list for the window. 256 | 257 | The |:LanguageToolCheck| command accepts a range. You can for example check 258 | grammar between lines 100 and 200 in buffer with :100,200LanguageToolCheck, 259 | check grammar in the visual selection with :<',>'LanguageToolCheck, etc. 260 | The default range is 1,$ (whole buffer). 261 | 262 | :LanguageToolClear *:LanguageToolClear* 263 | 264 | Use the |:LanguageToolClear| command to clear highlighting of grammar 265 | mistakes, close the scratch window containing the list of errors, clear 266 | and close the location-list. 267 | 268 | The two commands are also available from the menu in gvim: > 269 | 270 | Plugin -> LanguageTool -> Check 271 | -> Clear 272 | 273 | Using the error scratch window~ 274 | 275 | Pressing on an error in the error scratch buffer will jump to that 276 | error. 277 | 278 | Using the Location-list~ 279 | 280 | The |location-list| is populated when running |:LanguageToolCheck|. So you can 281 | use location-list Vim commands such as |:lopen| to open the location-list 282 | window, |:lne| to jump to the next error, etc. 283 | 284 | The error scratch window may seem redundant with the location-list, but the 285 | scratch window is more flexible to present errors in a nice way. If you do 286 | not wish to popup the error scratch window, but use the location-list only, 287 | you can disable it by setting |g:languagetool_win_height| to a negative value. 288 | 289 | ============================================================================ 290 | 291 | 7. Bugs *languagetool-bugs* 292 | 293 | Column number reported by LanguageTool indicating the location of the error 294 | is sometimes incorrect. There is already an opened ticket about this bug: 295 | 296 | http://sourceforge.net/tracker/?func=detail&aid=3054895&group_id=110216&atid=655717 297 | 298 | The script currently works around it by doing pattern matching with 299 | information context but it's not a perfect workaround: it can cause 300 | spurious highlighting of errors in rare cases. This bug is fixed in 301 | LanguageTool-1.8. 302 | 303 | Please report bugs or suggestions to . 304 | Alternatively, you can also discuss improvements to this plugin in Wiki 305 | by clicking on the "Vim wiki" link at the top of the script page: 306 | 307 | http://www.vim.org/scripts/script.php?script_id=3223 308 | 309 | ============================================================================ 310 | 311 | 8. License *languagetool-license* 312 | 313 | The VIM LICENSE applies to the LanguageTool.vim plugin (see |copyright| 314 | except use "LanguageTool.vim" instead of "Vim"). 315 | 316 | LanguageTool is freely available under LGPL. 317 | 318 | ============================================================================ 319 | vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl: 320 | -------------------------------------------------------------------------------- /plugin/LanguageTool.vim: -------------------------------------------------------------------------------- 1 | " LanguageTool: Grammar checker in Vim for English, French, German, etc. 2 | " Maintainer: Dominique Pellé 3 | " Screenshots: http://dominique.pelle.free.fr/pic/LanguageToolVimPlugin_en.png 4 | " http://dominique.pelle.free.fr/pic/LanguageToolVimPlugin_fr.png 5 | " Last Change: 2014/02/20 6 | " Version: 1.28 7 | " 8 | " Long Description: {{{1 9 | " 10 | " This plugin integrates the LanguageTool grammar checker into Vim. 11 | " Current version of LanguageTool can check grammar in many languages: 12 | " ast, be, br, ca, da, de, el, en, eo, es, fr, gl, is, it, km, lt, ml, nl, 13 | " pl, pt, ro, ru, sk, sl, sv, tl, uk, zh. 14 | " 15 | " See doc/LanguageTool.txt for more details about how to use the 16 | " LanguageTool plugin. 17 | " 18 | " See http://www.languagetool.org/ for more information about LanguageTool. 19 | " 20 | " License: {{{1 21 | " 22 | " The VIM LICENSE applies to LanguageTool.vim plugin 23 | " (see ":help copyright" except use "LanguageTool.vim" instead of "Vim"). 24 | " 25 | " Plugin set up {{{1 26 | if &cp || exists("g:loaded_languagetool") 27 | finish 28 | endif 29 | let g:loaded_languagetool = "1" 30 | 31 | " Guess language from 'a:lang' (either 'spelllang' or 'v:lang') 32 | function s:FindLanguage(lang) "{{{1 33 | " This replaces things like en_gb en-GB as expected by LanguageTool, 34 | " only for languages that support variants in LanguageTool. 35 | let l:language = substitute(substitute(a:lang, 36 | \ '\(\a\{2,3}\)\(_\a\a\)\?.*', 37 | \ '\=tolower(submatch(1)) . toupper(submatch(2))', ''), 38 | \ '_', '-', '') 39 | 40 | " All supported languages (with variants) from version LanguageTool-1.8. 41 | let l:supportedLanguages = { 42 | \ 'ast' : 1, 43 | \ 'be' : 1, 44 | \ 'br' : 1, 45 | \ 'ca' : 1, 46 | \ 'cs' : 1, 47 | \ 'da' : 1, 48 | \ 'de' : 1, 49 | \ 'de-AT' : 1, 50 | \ 'de-CH' : 1, 51 | \ 'de-DE' : 1, 52 | \ 'el' : 1, 53 | \ 'en' : 1, 54 | \ 'en-AU' : 1, 55 | \ 'en-CA' : 1, 56 | \ 'en-GB' : 1, 57 | \ 'en-NZ' : 1, 58 | \ 'en-US' : 1, 59 | \ 'en-ZA' : 1, 60 | \ 'eo' : 1, 61 | \ 'es' : 1, 62 | \ 'fr' : 1, 63 | \ 'gl' : 1, 64 | \ 'is' : 1, 65 | \ 'it' : 1, 66 | \ 'km' : 1, 67 | \ 'lt' : 1, 68 | \ 'ml' : 1, 69 | \ 'nl' : 1, 70 | \ 'pl' : 1, 71 | \ 'pt' : 1, 72 | \ 'ro' : 1, 73 | \ 'ru' : 1, 74 | \ 'sk' : 1, 75 | \ 'sl' : 1, 76 | \ 'sv' : 1, 77 | \ 'tl' : 1, 78 | \ 'uk' : 1, 79 | \ 'zh' : 1 80 | \} 81 | 82 | if has_key(l:supportedLanguages, l:language) 83 | return l:language 84 | endif 85 | 86 | " Removing the region (if any) and trying again. 87 | let l:language = substitute(l:language, '-.*', '', '') 88 | return has_key(l:supportedLanguages, l:language) ? l:language : '' 89 | endfunction 90 | 91 | " Return a regular expression used to highlight a grammatical error 92 | " at line a:line in text. The error starts at character a:start in 93 | " context a:context and its length in context is a:len. 94 | function s:LanguageToolHighlightRegex(line, context, start, len) "{{{1 95 | let l:start_idx = byteidx(a:context, a:start) 96 | let l:end_idx = byteidx(a:context, a:start + a:len) - 1 97 | let l:start_ctx_idx = byteidx(a:context, a:start + a:len) 98 | let l:end_ctx_idx = byteidx(a:context, a:start + a:len + 5) - 1 99 | 100 | " The substitute allows to match errors which span multiple lines. 101 | " The part after \ze gives a bit of context to avoid spurious 102 | " highlighting when the text of the error is present multiple 103 | " times in the line. 104 | return '\V' 105 | \ . '\%' . a:line . 'l' 106 | \ . substitute(escape(a:context[l:start_idx : l:end_idx], "'\\"), ' ', '\\_\\s', 'g') 107 | \ . '\ze' 108 | \ . substitute(escape(a:context[l:start_ctx_idx : l:end_ctx_idx], "'\\"), ' ', '\\_\\s', 'g') 109 | endfunction 110 | 111 | " Unescape XML special characters in a:text. 112 | function s:XmlUnescape(text) "{{{1 113 | " Change XML escape char such as " into " 114 | " Substitution of & must be done last or else something 115 | " like &quot; would get first transformed into " 116 | " and then wrongly transformed into " (correct is ") 117 | let l:escaped = substitute(a:text, '"', '"', 'g') 118 | let l:escaped = substitute(l:escaped, ''', "'", 'g') 119 | let l:escaped = substitute(l:escaped, '>', '>', 'g') 120 | let l:escaped = substitute(l:escaped, '<', '<', 'g') 121 | return substitute(l:escaped, '&', '\&', 'g') 122 | endfunction 123 | 124 | " Parse a xml attribute such as: ruleId="FOO" in line a:line. 125 | " where ruleId is the key a:key, and FOO is the returned value corresponding 126 | " to that key. 127 | function s:ParseKeyValue(key, line) "{{{1 128 | return s:XmlUnescape(matchstr(a:line, '\<' . a:key . '="\zs[^"]*\ze"')) 129 | endfunction 130 | 131 | " Set up configuration. 132 | " Returns 0 if success, < 0 in case of error. 133 | function s:LanguageToolSetUp() "{{{1 134 | let s:languagetool_disable_rules = exists("g:languagetool_disable_rules") 135 | \ ? g:languagetool_disable_rules 136 | \ : 'WHITESPACE_RULE,EN_QUOTES' 137 | let s:languagetool_win_height = exists("g:languagetool_win_height") 138 | \ ? g:languagetool_win_height 139 | \ : 14 140 | let s:languagetool_encoding = &fenc ? &fenc : &enc 141 | 142 | " Setting up language... 143 | if exists("g:languagetool_lang") 144 | let s:languagetool_lang = g:languagetool_lang 145 | else 146 | " Trying to guess language from 'spelllang' or 'v:lang'. 147 | let s:languagetool_lang = s:FindLanguage(&spelllang) 148 | if s:languagetool_lang == '' 149 | let s:languagetool_lang = s:FindLanguage(v:lang) 150 | if s:languagetool_lang == '' 151 | echoerr 'Failed to guess language from spelllang=[' 152 | \ . &spelllang . '] or from v:lang=[' . v:lang . ']. ' 153 | \ . 'Defauling to English (en-US). ' 154 | \ . 'See ":help LanguageTool" regarding setting g:languagetool_lang.' 155 | let s:languagetool_lang = 'en-US' 156 | endif 157 | endif 158 | endif 159 | 160 | let s:languagetool_jar = exists("g:languagetool_jar") 161 | \ ? g:languagetool_jar 162 | \ : $HOME . '/languagetool-2.4.1/languagetool-commandline.jar' 163 | 164 | if !filereadable(s:languagetool_jar) 165 | " Hmmm, can't find the jar file. Try again with expand() in case user 166 | " set it up as: let g:languagetool_jar = '$HOME/.../languagetool-commandline.jar' 167 | let l:languagetool_jar = expand(s:languagetool_jar) 168 | if !filereadable(expand(l:languagetool_jar)) 169 | echomsg "LanguageTool cannot be found at: " . s:languagetool_jar 170 | echomsg "You need to install LanguageTool and/or set up g:languagetool_jar" 171 | echomsg "to indicate the location of the languagetool-commandline.jar file." 172 | return -1 173 | endif 174 | let s:languagetool_jar = l:languagetool_jar 175 | endif 176 | return 0 177 | endfunction 178 | 179 | " Jump to a grammar mistake (called when pressing 180 | " on a particular error in scratch buffer). 181 | function JumpToCurrentError() "{{{1 182 | let l:save_cursor = getpos('.') 183 | norm! $ 184 | if search('^Error:\s\+', 'beW') > 0 185 | let l:error_idx = expand('') 186 | let l:error = s:errors[l:error_idx - 1] 187 | let l:line = l:error['fromy'] 188 | let l:col = l:error['fromx'] 189 | let l:rule = l:error['ruleId'] 190 | call setpos('.', l:save_cursor) 191 | exe s:languagetool_text_win . 'wincmd w' 192 | exe 'norm! ' . l:line . 'G0' 193 | 194 | " Finding the column is done using pattern matching with information 195 | " in error context. 196 | let l:context = l:error['replacements'][byteidx(l:error['replacements'], l:error['context']) 197 | \ :byteidx(l:error['replacements'], l:error['context'] + l:error['contextoffset']) - 1] 198 | let l:re = s:LanguageToolHighlightRegex(l:error['fromy'], l:error['replacements'], 199 | \ l:error['context'], l:error['contextoffset']) 200 | echon 'Jump to error ' . l:error_idx . '/' . len(s:errors) 201 | \ . ' (' . l:rule . ') ...' . l:context . '... @ ' 202 | \ . l:line . 'L ' . l:col . 'C' 203 | call search(l:re) 204 | norm! zz 205 | else 206 | call setpos('.', l:save_cursor) 207 | endif 208 | endfunction 209 | 210 | " This function performs grammar checking of text in the current buffer. 211 | " It highlights grammar mistakes in current buffer and opens a scratch 212 | " window with all errors found. It also populates the location-list of 213 | " the window with all errors. 214 | " a:line1 and a:line2 parameters are the first and last line number of 215 | " the range of line to check. 216 | " Returns 0 if success, < 0 in case of error. 217 | function s:LanguageToolCheck(line1, line2) "{{{1 218 | let l:save_cursor = getpos('.') 219 | if s:LanguageToolSetUp() < 0 220 | return -1 221 | endif 222 | call s:LanguageToolClear() 223 | 224 | sil %y 225 | botright new 226 | let s:languagetool_error_buffer = bufnr('%') 227 | let s:languagetool_error_win = winnr() 228 | sil put! 229 | 230 | " LanguageTool somehow gives incorrect line/column numbers when 231 | " reading from stdin so we need to use a temporary file to get 232 | " correct results. 233 | let l:tmpfilename = tempname() 234 | let l:tmperror = tempname() 235 | 236 | let l:range = a:line1 . ',' . a:line2 237 | silent exe l:range . 'w!' . l:tmpfilename 238 | 239 | let l:languagetool_cmd = 'java' 240 | \ . ' -jar ' . s:languagetool_jar 241 | \ . ' -c ' . s:languagetool_encoding 242 | \ . ' -d ' . s:languagetool_disable_rules 243 | \ . ' -l ' . s:languagetool_lang 244 | \ . ' --api ' . l:tmpfilename 245 | \ . ' 2> ' . l:tmperror 246 | 247 | sil exe '%!' . l:languagetool_cmd 248 | call delete(l:tmpfilename) 249 | 250 | if v:shell_error 251 | echoerr 'Command [' . l:languagetool_cmd . '] failed with error: ' 252 | \ . v:shell_error 253 | if filereadable(l:tmperror) 254 | echoerr string(readfile(l:tmperror)) 255 | endif 256 | call delete(l:tmperror) 257 | call s:LanguageToolClear() 258 | return -1 259 | endif 260 | call delete(l:tmperror) 261 | 262 | " Loop on all errors in XML output of LanguageTool and 263 | " collect information about all errors in list s:errors 264 | let s:errors = [] 265 | while search('^ 0 266 | let l:l = getline('.') 267 | " The fromx and tox given by LanguageTool are not reliable. 268 | " They are even sometimes negative! 269 | 270 | let l:error= {} 271 | for l:k in [ 'fromy', 'fromx', 'tox', 'toy', 272 | \ 'ruleId', 'subId', 'msg', 'replacements', 273 | \ 'context', 'contextoffset', 'errorlength', 'url' ] 274 | let l:error[l:k] = s:ParseKeyValue(l:k, l:l) 275 | endfor 276 | 277 | " Make line/column number start at 1 rather than 0. 278 | " Make also line number absolute as in buffer. 279 | let l:error['fromy'] += a:line1 280 | let l:error['fromx'] += 1 281 | let l:error['toy'] += a:line1 282 | let l:error['tox'] += 1 283 | 284 | call add(s:errors, l:error) 285 | endwhile 286 | 287 | if s:languagetool_win_height >= 0 288 | " Reformat the output of LanguageTool (XML is not human friendly) and 289 | " set up syntax highlighting in the buffer which shows all errors. 290 | sil %d 291 | call append(0, '# ' . l:languagetool_cmd) 292 | set bt=nofile 293 | setlocal nospell 294 | syn clear 295 | syn match LanguageToolCmd '\%1l.*' 296 | syn match LanguageToolLabel '^\(Pos\|Rule\|Context\|Message\|Correction\):' 297 | syn match LanguageToolLabelMoreInfo '^More info:.*' contains=LanguageToolUrl 298 | syn match LanguageToolErrorCount '^Error:\s\+\d\+.\d\+' 299 | syn match LanguageToolUrl '^More info:\s*\zs.*' contained 300 | let l:i = 0 301 | for l:error in s:errors 302 | call append('$', 'Error: ' 303 | \ . (l:i + 1) . '/' . len(s:errors) 304 | \ . ' (' . l:error['ruleId'] . ':' . l:error['subId'] . ')' 305 | \ . ' @ ' . l:error['fromy'] . 'L ' . l:error['fromx'] . 'C') 306 | call append('$', 'Message: ' . l:error['msg']) 307 | call append('$', 'Context: ' . l:error['context']) 308 | 309 | if l:error['ruleId'] =~ 'HUNSPELL_RULE\|HUNSPELL_NO_SUGGEST_RULE\|MORFOLOGIK_RULE_.*\|GERMAN_SPELLER_RULE' 310 | exe "syn match LanguageToolSpellingError '" 311 | \ . '\%' . line('$') . 'l\%9c' 312 | \ . '.\{' . (4 + l:error['contextoffset']) . '}\zs' 313 | \ . '.\{' . (l:error['errorlength']) . "}'" 314 | else 315 | exe "syn match LanguageToolGrammarError '" 316 | \ . '\%' . line('$') . 'l\%9c' 317 | \ . '.\{' . (4 + l:error['contextoffset']) . '}\zs' 318 | \ . '.\{' . (l:error['errorlength']) . "}'" 319 | endif 320 | if !empty(l:error['replacements']) 321 | call append('$', 'Correction: ' . l:error['replacements']) 322 | endif 323 | if !empty(l:error['url']) 324 | call append('$', 'More info: ' . l:error['url']) 325 | endif 326 | call append('$', '') 327 | let l:i += 1 328 | endfor 329 | exe "norm! z" . s:languagetool_win_height . "\" 330 | 0 331 | map :call JumpToCurrentError() 332 | redraw 333 | echon 'Press on error in scratch buffer to jump its location' 334 | exe "norm! \\" 335 | else 336 | " Negative s:languagetool_win_height -> no scratch window. 337 | bd! 338 | unlet! s:languagetool_error_buffer 339 | endif 340 | let s:languagetool_text_win = winnr() 341 | 342 | " Also highlight errors in original buffer and populate location list. 343 | setlocal errorformat=%f:%l:%c:%m 344 | for l:error in s:errors 345 | let l:re = s:LanguageToolHighlightRegex(l:error['fromy'], 346 | \ l:error['context'], 347 | \ l:error['contextoffset'], 348 | \ l:error['errorlength']) 349 | if l:error['ruleId'] =~ 'HUNSPELL_RULE\|HUNSPELL_NO_SUGGEST_RULE\|MORFOLOGIK_RULE_.*\|GERMAN_SPELLER_RULE' 350 | exe "syn match LanguageToolSpellingError '" . l:re . "'" 351 | else 352 | exe "syn match LanguageToolGrammarError '" . l:re . "'" 353 | endif 354 | laddexpr expand('%') . ':' 355 | \ . l:error['fromy'] . ':' . l:error['fromx'] . ':' 356 | \ . l:error['ruleId'] . ' ' . l:error['msg'] 357 | endfor 358 | return 0 359 | endfunction 360 | 361 | " This function clears syntax highlighting created by LanguageTool plugin 362 | " and removes the scratch window containing grammar errors. 363 | function s:LanguageToolClear() "{{{1 364 | if exists('s:languagetool_error_buffer') 365 | if bufexists(s:languagetool_error_buffer) 366 | sil! exe "bd! " . s:languagetool_error_buffer 367 | endif 368 | endif 369 | if exists('s:languagetool_text_win') 370 | let l:win = winnr() 371 | exe s:languagetool_text_win . 'wincmd w' 372 | syn clear LanguageToolGrammarError 373 | syn clear LanguageToolSpellingError 374 | lexpr '' 375 | lclose 376 | exe l:win . 'wincmd w' 377 | endif 378 | unlet! s:languagetool_error_buffer 379 | unlet! s:languagetool_error_win 380 | unlet! s:languagetool_text_win 381 | endfunction 382 | 383 | hi def link LanguageToolCmd Comment 384 | hi def link LanguageToolLabel Label 385 | hi def link LanguageToolLabelMoreInfo Label 386 | hi def link LanguageToolGrammarError Error 387 | hi def link LanguageToolSpellingError WarningMsg 388 | hi def link LanguageToolErrorCount Title 389 | hi def link LanguageToolUrl Underlined 390 | 391 | " Section: Menu items {{{1 392 | if has("gui_running") && has("menu") && &go =~ 'm' 393 | amenu &Plugin.LanguageTool.Chec&k :LanguageToolCheck 394 | amenu &Plugin.LanguageTool.Clea&r :LanguageToolClear 395 | endif 396 | 397 | " Defines commands {{{1 398 | com! -nargs=0 LanguageToolClear :call s:LanguageToolClear() 399 | com! -nargs=0 -range=% LanguageToolCheck :call s:LanguageToolCheck(, 400 | \ ) 401 | " vim: fdm=marker 402 | --------------------------------------------------------------------------------