mirror of
https://github.com/sheerun/vim-polyglot.git
synced 2025-11-08 11:33:52 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a15d48ed4 | ||
|
|
24f0581a96 | ||
|
|
33c9484671 | ||
|
|
55287efdf7 | ||
|
|
d757bfd643 | ||
|
|
8ec73a3a89 | ||
|
|
b2ee28374b | ||
|
|
68b2748af1 | ||
|
|
14dc82fc4e | ||
|
|
e86e0ad36e | ||
|
|
45ab4d80dd | ||
|
|
9cd6e8533b | ||
|
|
43ecbfae50 | ||
|
|
f77702c090 | ||
|
|
e558a218c6 | ||
|
|
16774887a3 | ||
|
|
e7dc03dc01 | ||
|
|
aee260a301 | ||
|
|
6b540d7db0 | ||
|
|
35ea4d2b90 | ||
|
|
967486dd71 | ||
|
|
e8454d66ab | ||
|
|
a60e299a3c | ||
|
|
b8a5504021 | ||
|
|
cea0d08a06 | ||
|
|
43085dc02f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
/tmp
|
/tmp
|
||||||
|
!*ctags*
|
||||||
|
|||||||
34
README.md
34
README.md
@@ -10,7 +10,7 @@ A collection of language packs for Vim.
|
|||||||
> One to rule them all, one to find them, one to bring them all and in the darkness bind them.
|
> One to rule them all, one to find them, one to bring them all and in the darkness bind them.
|
||||||
|
|
||||||
- It **won't affect your startup time**, as scripts are loaded only on demand\*.
|
- It **won't affect your startup time**, as scripts are loaded only on demand\*.
|
||||||
- It **installs and updates 120+ times faster** than the <!--Package Count-->147<!--/Package Count--> packages it consists of.
|
- It **installs and updates 120+ times faster** than the <!--Package Count-->149<!--/Package Count--> packages it consists of.
|
||||||
- Solid syntax and indentation support (other features skipped). Only the best language packs.
|
- Solid syntax and indentation support (other features skipped). Only the best language packs.
|
||||||
- All unnecessary files are ignored (like enormous documentation from php support).
|
- All unnecessary files are ignored (like enormous documentation from php support).
|
||||||
- No support for esoteric languages, only most popular ones (modern too, like `slim`).
|
- No support for esoteric languages, only most popular ones (modern too, like `slim`).
|
||||||
@@ -47,12 +47,13 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
<!--Language Packs-->
|
<!--Language Packs-->
|
||||||
- [acpiasl](https://github.com/martinlroth/vim-acpi-asl) (syntax)
|
- [acpiasl](https://github.com/martinlroth/vim-acpi-asl) (syntax)
|
||||||
- [ansible](https://github.com/pearofducks/ansible-vim) (syntax, indent, ftplugin)
|
- [ansible](https://github.com/pearofducks/ansible-vim) (syntax, indent, ftplugin)
|
||||||
- [apiblueprint](https://github.com/sheerun/apiblueprint.vim) (syntax)
|
- [apiblueprint](https://github.com/sheerun/apiblueprint.vim) (syntax, ctags)
|
||||||
- [applescript](https://github.com/mityu/vim-applescript) (syntax, indent)
|
- [applescript](https://github.com/mityu/vim-applescript) (syntax, indent)
|
||||||
- [arduino](https://github.com/sudar/vim-arduino-syntax) (syntax, indent)
|
- [arduino](https://github.com/sudar/vim-arduino-syntax) (syntax, indent)
|
||||||
- [asciidoc](https://github.com/asciidoc/vim-asciidoc) (syntax)
|
- [asciidoc](https://github.com/asciidoc/vim-asciidoc) (syntax)
|
||||||
- [autohotkey](https://github.com/hnamikaw/vim-autohotkey) (indent)
|
- [autohotkey](https://github.com/hnamikaw/vim-autohotkey) (indent)
|
||||||
- [blade](https://github.com/jwalton512/vim-blade) (syntax, indent, ftplugin)
|
- [blade](https://github.com/jwalton512/vim-blade) (syntax, indent, ftplugin)
|
||||||
|
- [brewfile](https://github.com/bfontaine/Brewfile.vim) (syntax)
|
||||||
- [c++11](https://github.com/octol/vim-cpp-enhanced-highlight) (syntax)
|
- [c++11](https://github.com/octol/vim-cpp-enhanced-highlight) (syntax)
|
||||||
- [c/c++](https://github.com/vim-jp/vim-cpp) (syntax)
|
- [c/c++](https://github.com/vim-jp/vim-cpp) (syntax)
|
||||||
- [caddyfile](https://github.com/isobit/vim-caddyfile) (syntax, indent, ftplugin)
|
- [caddyfile](https://github.com/isobit/vim-caddyfile) (syntax, indent, ftplugin)
|
||||||
@@ -72,14 +73,15 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [dlang](https://github.com/JesseKPhillips/d.vim) (syntax, indent)
|
- [dlang](https://github.com/JesseKPhillips/d.vim) (syntax, indent)
|
||||||
- [dockerfile](https://github.com/ekalinin/Dockerfile.vim) (syntax, indent, ftplugin)
|
- [dockerfile](https://github.com/ekalinin/Dockerfile.vim) (syntax, indent, ftplugin)
|
||||||
- [elixir](https://github.com/elixir-lang/vim-elixir) (syntax, indent, compiler, autoload, ftplugin)
|
- [elixir](https://github.com/elixir-lang/vim-elixir) (syntax, indent, compiler, autoload, ftplugin)
|
||||||
- [elm](https://github.com/ElmCast/elm-vim) (syntax, indent, autoload, ftplugin)
|
- [elm](https://github.com/andys8/vim-elm-syntax) (syntax, indent)
|
||||||
- [emberscript](https://github.com/yalesov/vim-ember-script) (syntax, indent, ftplugin)
|
- [emberscript](https://github.com/yalesov/vim-ember-script) (syntax, indent, ftplugin)
|
||||||
- [emblem](https://github.com/yalesov/vim-emblem) (syntax, indent, ftplugin)
|
- [emblem](https://github.com/yalesov/vim-emblem) (syntax, indent, ftplugin)
|
||||||
- [erlang](https://github.com/vim-erlang/vim-erlang-runtime) (syntax, indent)
|
- [erlang](https://github.com/vim-erlang/vim-erlang-runtime) (syntax, indent)
|
||||||
- [ferm](https://github.com/vim-scripts/ferm.vim) (syntax)
|
- [ferm](https://github.com/vim-scripts/ferm.vim) (syntax)
|
||||||
- [fish](https://github.com/georgewitteman/vim-fish) (syntax, indent, compiler, autoload, ftplugin)
|
- [fish](https://github.com/georgewitteman/vim-fish) (syntax, indent, compiler, autoload, ftplugin)
|
||||||
- [flatbuffers](https://github.com/dcharbon/vim-flatbuffers) (syntax)
|
- [flatbuffers](https://github.com/dcharbon/vim-flatbuffers) (syntax)
|
||||||
- [fsharp](https://github.com/fsharp/vim-fsharp) (syntax, indent)
|
- [fsharp](https://github.com/ionide/Ionide-vim) (syntax, indent)
|
||||||
|
- [gdscript](https://github.com/calviken/vim-gdscript3) (syntax, indent, ftplugin)
|
||||||
- [git](https://github.com/tpope/vim-git) (syntax, indent, ftplugin)
|
- [git](https://github.com/tpope/vim-git) (syntax, indent, ftplugin)
|
||||||
- [glsl](https://github.com/tikhomirov/vim-glsl) (syntax, indent)
|
- [glsl](https://github.com/tikhomirov/vim-glsl) (syntax, indent)
|
||||||
- [gmpl](https://github.com/maelvalais/gmpl.vim) (syntax)
|
- [gmpl](https://github.com/maelvalais/gmpl.vim) (syntax)
|
||||||
@@ -87,8 +89,6 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [go](https://github.com/fatih/vim-go) (syntax, compiler, indent)
|
- [go](https://github.com/fatih/vim-go) (syntax, compiler, indent)
|
||||||
- [gradle](https://github.com/tfnico/vim-gradle) (compiler)
|
- [gradle](https://github.com/tfnico/vim-gradle) (compiler)
|
||||||
- [graphql](https://github.com/jparise/vim-graphql) (syntax, indent, autoload, ftplugin, after)
|
- [graphql](https://github.com/jparise/vim-graphql) (syntax, indent, autoload, ftplugin, after)
|
||||||
- [groovy-indent](https://github.com/vim-scripts/groovyindent-unix) (indent)
|
|
||||||
- [groovy](https://github.com/vim-scripts/groovy.vim) (syntax)
|
|
||||||
- [haml](https://github.com/sheerun/vim-haml) (syntax, indent, compiler, ftplugin)
|
- [haml](https://github.com/sheerun/vim-haml) (syntax, indent, compiler, ftplugin)
|
||||||
- [handlebars](https://github.com/mustache/vim-mustache-handlebars) (syntax, indent, ftplugin)
|
- [handlebars](https://github.com/mustache/vim-mustache-handlebars) (syntax, indent, ftplugin)
|
||||||
- [haproxy](https://github.com/CH-DanReif/haproxy.vim) (syntax)
|
- [haproxy](https://github.com/CH-DanReif/haproxy.vim) (syntax)
|
||||||
@@ -101,7 +101,6 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [i3](https://github.com/mboughaba/i3config.vim) (syntax, ftplugin)
|
- [i3](https://github.com/mboughaba/i3config.vim) (syntax, ftplugin)
|
||||||
- [idris](https://github.com/idris-hackers/idris-vim) (syntax, indent, ftplugin)
|
- [idris](https://github.com/idris-hackers/idris-vim) (syntax, indent, ftplugin)
|
||||||
- [ion](https://github.com/vmchale/ion-vim) (syntax, ftplugin)
|
- [ion](https://github.com/vmchale/ion-vim) (syntax, ftplugin)
|
||||||
- [jasmine](https://github.com/glanotte/vim-jasmine) (syntax)
|
|
||||||
- [javascript](https://github.com/pangloss/vim-javascript) (syntax, indent, compiler, ftplugin, extras)
|
- [javascript](https://github.com/pangloss/vim-javascript) (syntax, indent, compiler, ftplugin, extras)
|
||||||
- [jenkins](https://github.com/martinda/Jenkinsfile-vim-syntax) (syntax, indent)
|
- [jenkins](https://github.com/martinda/Jenkinsfile-vim-syntax) (syntax, indent)
|
||||||
- [jinja](https://github.com/lepture/vim-jinja) (syntax, indent)
|
- [jinja](https://github.com/lepture/vim-jinja) (syntax, indent)
|
||||||
@@ -111,7 +110,7 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [jsx](https://github.com/MaxMEllon/vim-jsx-pretty) (autoload, after)
|
- [jsx](https://github.com/MaxMEllon/vim-jsx-pretty) (autoload, after)
|
||||||
- [julia](https://github.com/JuliaEditorSupport/julia-vim) (syntax, indent, autoload, ftplugin)
|
- [julia](https://github.com/JuliaEditorSupport/julia-vim) (syntax, indent, autoload, ftplugin)
|
||||||
- [kotlin](https://github.com/udalov/kotlin-vim) (syntax, indent, ftplugin)
|
- [kotlin](https://github.com/udalov/kotlin-vim) (syntax, indent, ftplugin)
|
||||||
- [latex](https://github.com/LaTeX-Box-Team/LaTeX-Box) (syntax, indent, ftplugin)
|
- [latex](https://github.com/lervag/vimtex) (indent, compiler, autoload, ftplugin, syntax)
|
||||||
- [less](https://github.com/groenewege/vim-less) (syntax, indent, ftplugin)
|
- [less](https://github.com/groenewege/vim-less) (syntax, indent, ftplugin)
|
||||||
- [lilypond](https://github.com/anowlcalledjosh/vim-lilypond) (syntax, indent, compiler, ftplugin)
|
- [lilypond](https://github.com/anowlcalledjosh/vim-lilypond) (syntax, indent, compiler, ftplugin)
|
||||||
- [livescript](https://github.com/gkz/vim-ls) (syntax, indent, compiler, ftplugin)
|
- [livescript](https://github.com/gkz/vim-ls) (syntax, indent, compiler, ftplugin)
|
||||||
@@ -136,10 +135,10 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [php](https://github.com/StanAngeloff/php.vim) (syntax)
|
- [php](https://github.com/StanAngeloff/php.vim) (syntax)
|
||||||
- [plantuml](https://github.com/aklt/plantuml-syntax) (syntax, indent, ftplugin)
|
- [plantuml](https://github.com/aklt/plantuml-syntax) (syntax, indent, ftplugin)
|
||||||
- [pony](https://github.com/jakwings/vim-pony) (syntax, indent, autoload, ftplugin)
|
- [pony](https://github.com/jakwings/vim-pony) (syntax, indent, autoload, ftplugin)
|
||||||
- [powershell](https://github.com/PProvost/vim-ps1) (syntax, indent, ftplugin)
|
- [powershell](https://github.com/PProvost/vim-ps1) (syntax, indent, compiler, ftplugin)
|
||||||
- [protobuf](https://github.com/uarun/vim-protobuf) (syntax, indent)
|
- [protobuf](https://github.com/uarun/vim-protobuf) (syntax, indent)
|
||||||
- [pug](https://github.com/digitaltoad/vim-pug) (syntax, indent, ftplugin)
|
- [pug](https://github.com/digitaltoad/vim-pug) (syntax, indent, ftplugin)
|
||||||
- [puppet](https://github.com/rodjek/vim-puppet) (syntax, indent, autoload, ftplugin)
|
- [puppet](https://github.com/rodjek/vim-puppet) (syntax, indent, autoload, ftplugin, ctags)
|
||||||
- [purescript](https://github.com/purescript-contrib/purescript-vim) (syntax, indent, ftplugin)
|
- [purescript](https://github.com/purescript-contrib/purescript-vim) (syntax, indent, ftplugin)
|
||||||
- [python-compiler](https://github.com/aliev/vim-compiler-python) (compiler, autoload)
|
- [python-compiler](https://github.com/aliev/vim-compiler-python) (compiler, autoload)
|
||||||
- [python-indent](https://github.com/Vimjas/vim-python-pep8-indent) (indent)
|
- [python-indent](https://github.com/Vimjas/vim-python-pep8-indent) (indent)
|
||||||
@@ -150,23 +149,25 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [racket](https://github.com/wlangstroth/vim-racket) (syntax, indent, ftplugin)
|
- [racket](https://github.com/wlangstroth/vim-racket) (syntax, indent, ftplugin)
|
||||||
- [ragel](https://github.com/jneen/ragel.vim) (syntax)
|
- [ragel](https://github.com/jneen/ragel.vim) (syntax)
|
||||||
- [raml](https://github.com/IN3D/vim-raml) (syntax, ftplugin)
|
- [raml](https://github.com/IN3D/vim-raml) (syntax, ftplugin)
|
||||||
|
- [razor](https://github.com/adamclerk/vim-razor) (syntax, indent, ftplugin)
|
||||||
- [reason](https://github.com/reasonml-editor/vim-reason-plus) (syntax, indent)
|
- [reason](https://github.com/reasonml-editor/vim-reason-plus) (syntax, indent)
|
||||||
- [rspec](https://github.com/sheerun/rspec.vim) (syntax)
|
- [rego](https://github.com/tsandall/vim-rego) (syntax)
|
||||||
|
- [rspec](https://github.com/keith/rspec.vim) (syntax)
|
||||||
- [rst](https://github.com/marshallward/vim-restructuredtext) (syntax, indent, autoload, ftplugin)
|
- [rst](https://github.com/marshallward/vim-restructuredtext) (syntax, indent, autoload, ftplugin)
|
||||||
- [ruby](https://github.com/vim-ruby/vim-ruby) (syntax, indent, compiler, autoload, ftplugin)
|
- [ruby](https://github.com/vim-ruby/vim-ruby) (syntax, indent, compiler, autoload, ftplugin)
|
||||||
- [rust](https://github.com/rust-lang/rust.vim) (syntax, indent, compiler, autoload, ftplugin)
|
- [rust](https://github.com/rust-lang/rust.vim) (syntax, indent, compiler, autoload, ftplugin, ctags)
|
||||||
- [sbt](https://github.com/derekwyatt/vim-sbt) (syntax)
|
- [sbt](https://github.com/derekwyatt/vim-sbt) (syntax)
|
||||||
- [scala](https://github.com/derekwyatt/vim-scala) (syntax, indent, compiler, ftplugin)
|
- [scala](https://github.com/derekwyatt/vim-scala) (syntax, indent, compiler, ftplugin, ctags)
|
||||||
- [scss](https://github.com/cakebaker/scss-syntax.vim) (syntax, indent, ftplugin)
|
- [scss](https://github.com/cakebaker/scss-syntax.vim) (syntax, indent, ftplugin)
|
||||||
- [slim](https://github.com/slim-template/vim-slim) (syntax, indent, ftplugin)
|
- [slim](https://github.com/slim-template/vim-slim) (syntax, indent, ftplugin)
|
||||||
- [slime](https://github.com/slime-lang/vim-slime-syntax) (syntax, indent)
|
- [slime](https://github.com/slime-lang/vim-slime-syntax) (syntax, indent)
|
||||||
- [smt2](https://github.com/bohlender/vim-smt2) (syntax, autoload, ftplugin)
|
- [smt2](https://github.com/bohlender/vim-smt2) (syntax, autoload, ftplugin)
|
||||||
- [solidity](https://github.com/tomlion/vim-solidity) (syntax, indent, ftplugin)
|
- [solidity](https://github.com/tomlion/vim-solidity) (syntax, indent, ftplugin)
|
||||||
- [stylus](https://github.com/wavded/vim-stylus) (syntax, indent, ftplugin)
|
- [stylus](https://github.com/wavded/vim-stylus) (syntax, indent, ftplugin)
|
||||||
- [svelte](https://github.com/evanleck/vim-svelte) (syntax, indent)
|
- [svelte](https://github.com/evanleck/vim-svelte) (syntax, indent, ftplugin)
|
||||||
- [svg-indent](https://github.com/jasonshell/vim-svg-indent) (indent)
|
- [svg-indent](https://github.com/jasonshell/vim-svg-indent) (indent)
|
||||||
- [svg](https://github.com/vim-scripts/svg.vim) (syntax)
|
- [svg](https://github.com/vim-scripts/svg.vim) (syntax)
|
||||||
- [swift](https://github.com/keith/swift.vim) (syntax, indent, ftplugin)
|
- [swift](https://github.com/keith/swift.vim) (syntax, indent, compiler, ftplugin, ctags)
|
||||||
- [sxhkd](https://github.com/baskerville/vim-sxhkdrc) (syntax)
|
- [sxhkd](https://github.com/baskerville/vim-sxhkdrc) (syntax)
|
||||||
- [systemd](https://github.com/wgwoods/vim-systemd-syntax) (syntax, ftplugin)
|
- [systemd](https://github.com/wgwoods/vim-systemd-syntax) (syntax, ftplugin)
|
||||||
- [terraform](https://github.com/hashivim/vim-terraform) (syntax, indent, autoload, ftplugin)
|
- [terraform](https://github.com/hashivim/vim-terraform) (syntax, indent, autoload, ftplugin)
|
||||||
@@ -177,7 +178,7 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [toml](https://github.com/cespare/vim-toml) (syntax, ftplugin)
|
- [toml](https://github.com/cespare/vim-toml) (syntax, ftplugin)
|
||||||
- [tptp](https://github.com/c-cube/vim-tptp) (syntax)
|
- [tptp](https://github.com/c-cube/vim-tptp) (syntax)
|
||||||
- [twig](https://github.com/lumiliet/vim-twig) (syntax, indent, ftplugin)
|
- [twig](https://github.com/lumiliet/vim-twig) (syntax, indent, ftplugin)
|
||||||
- [typescript](https://github.com/HerringtonDarkholme/yats.vim) (syntax, indent, compiler, ftplugin)
|
- [typescript](https://github.com/HerringtonDarkholme/yats.vim) (syntax, indent, compiler, ftplugin, ctags)
|
||||||
- [v](https://github.com/ollykel/v-vim) (syntax, indent, ftplugin)
|
- [v](https://github.com/ollykel/v-vim) (syntax, indent, ftplugin)
|
||||||
- [vala](https://github.com/arrufat/vala.vim) (syntax, indent, ftplugin)
|
- [vala](https://github.com/arrufat/vala.vim) (syntax, indent, ftplugin)
|
||||||
- [vbnet](https://github.com/vim-scripts/vbnet.vim) (syntax)
|
- [vbnet](https://github.com/vim-scripts/vbnet.vim) (syntax)
|
||||||
@@ -192,6 +193,7 @@ If you need full functionality of any plugin, please use it directly with your p
|
|||||||
- [yard](https://github.com/sheerun/vim-yardoc) (syntax)
|
- [yard](https://github.com/sheerun/vim-yardoc) (syntax)
|
||||||
- [zephir](https://github.com/xwsoul/vim-zephir) (syntax)
|
- [zephir](https://github.com/xwsoul/vim-zephir) (syntax)
|
||||||
- [zig](https://github.com/ziglang/zig.vim) (syntax, autoload, ftplugin)
|
- [zig](https://github.com/ziglang/zig.vim) (syntax, autoload, ftplugin)
|
||||||
|
- [zinit](https://github.com/zinit-zsh/zplugin-vim-syntax) (syntax)
|
||||||
<!--/Language Packs-->
|
<!--/Language Packs-->
|
||||||
|
|
||||||
## Updating
|
## Updating
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ if exists("loaded_matchup")
|
|||||||
let b:match_skip = 's:comment\|string'
|
let b:match_skip = 's:comment\|string'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let b:original_commentstring = &l:commentstring
|
let b:jsx_pretty_old_cms = &l:commentstring
|
||||||
|
|
||||||
augroup jsx_comment
|
augroup jsx_comment
|
||||||
autocmd! CursorMoved <buffer>
|
autocmd! CursorMoved <buffer>
|
||||||
autocmd CursorMoved <buffer> call jsx_pretty#comment#update_commentstring(b:original_commentstring)
|
autocmd CursorMoved <buffer> call jsx_pretty#comment#update_commentstring(b:jsx_pretty_old_cms)
|
||||||
augroup end
|
augroup end
|
||||||
|
|
||||||
setlocal suffixesadd+=.jsx
|
setlocal suffixesadd+=.jsx
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ function! s:is_section_delim(line, func_delim) abort
|
|||||||
return 0
|
return 0
|
||||||
endif
|
endif
|
||||||
let kind = sec[0]
|
let kind = sec[0]
|
||||||
return kind == s:KIND_BLOCK_PREC || kind == s:KIND_BLOCK_FOLLOW || kind == func_delim
|
return kind == s:KIND_BLOCK_PREC || kind == s:KIND_BLOCK_FOLLOW || kind == a:func_delim
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:next_section(stop_func_begin) abort
|
function! s:next_section(stop_func_begin) abort
|
||||||
@@ -85,11 +85,16 @@ function! s:prev_section(stop_func_begin) abort
|
|||||||
endwhile
|
endwhile
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
nnoremap <buffer><Plug>(llvm-next-section-begin) :<C-u>call <SID>next_section(1)<CR>
|
||||||
|
nnoremap <buffer><Plug>(llvm-prev-section-begin) :<C-u>call <SID>prev_section(1)<CR>
|
||||||
|
nnoremap <buffer><Plug>(llvm-next-section-end) :<C-u>call <SID>next_section(0)<CR>
|
||||||
|
nnoremap <buffer><Plug>(llvm-prev-section-end) :<C-u>call <SID>prev_section(0)<CR>
|
||||||
|
|
||||||
if !g:llvm_ext_no_mapping
|
if !g:llvm_ext_no_mapping
|
||||||
nnoremap <buffer><silent>]] :<C-u>call <SID>next_section(1)<CR>
|
nmap <buffer><silent>]] <Plug>(llvm-next-section-begin)
|
||||||
nnoremap <buffer><silent>[[ :<C-u>call <SID>prev_section(1)<CR>
|
nmap <buffer><silent>[[ <Plug>(llvm-prev-section-begin)
|
||||||
nnoremap <buffer><silent>][ :<C-u>call <SID>next_section(0)<CR>
|
nmap <buffer><silent>][ <Plug>(llvm-next-section-end)
|
||||||
nnoremap <buffer><silent>[] :<C-u>call <SID>prev_section(0)<CR>
|
nmap <buffer><silent>[] <Plug>(llvm-prev-section-end)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
function! s:function_range_at(linum) abort
|
function! s:function_range_at(linum) abort
|
||||||
@@ -222,9 +227,12 @@ function! s:move_to_following_block() abort
|
|||||||
endtry
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
nnoremap <buffer><Plug>(llvm-move-block-prev) :<C-u>call <SID>move_to_pred_block()<CR>
|
||||||
|
nnoremap <buffer><Plug>(llvm-move-block-next) :<C-u>call <SID>move_to_following_block()<CR>
|
||||||
|
|
||||||
if !g:llvm_ext_no_mapping
|
if !g:llvm_ext_no_mapping
|
||||||
nnoremap <buffer><silent>[b :<C-u>call <SID>move_to_pred_block()<CR>
|
nmap <buffer><silent>[b <Plug>(llvm-move-block-prev)
|
||||||
nnoremap <buffer><silent>]b :<C-u>call <SID>move_to_following_block()<CR>
|
nmap <buffer><silent>]b <Plug>(llvm-move-block-next)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
function! s:get_func_identifiers(line) abort
|
function! s:get_func_identifiers(line) abort
|
||||||
@@ -438,8 +446,10 @@ function! s:goto_definition() abort
|
|||||||
echom "No definition for '" . ident . "' found"
|
echom "No definition for '" . ident . "' found"
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
nnoremap <buffer><Plug>(llvm-goto-definition) :<C-u>call <SID>goto_definition()<CR>
|
||||||
|
|
||||||
if !g:llvm_ext_no_mapping
|
if !g:llvm_ext_no_mapping
|
||||||
nnoremap <buffer><silent>K :<C-u>call <SID>goto_definition()<CR>
|
nmap <buffer><silent>K <Plug>(llvm-goto-definition)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
function! s:run_lli(...) abort
|
function! s:run_lli(...) abort
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'markdown') == -1
|
|
||||||
|
|
||||||
" vim: ts=4 sw=4:
|
|
||||||
" folding for Markdown headers, both styles (atx- and setex-)
|
|
||||||
" http://daringfireball.net/projects/markdown/syntax#header
|
|
||||||
"
|
|
||||||
" this code can be placed in file
|
|
||||||
" $HOME/.vim/after/ftplugin/markdown.vim
|
|
||||||
"
|
|
||||||
" original version from Steve Losh's gist: https://gist.github.com/1038710
|
|
||||||
|
|
||||||
function! s:is_mkdCode(lnum)
|
|
||||||
let name = synIDattr(synID(a:lnum, 1, 0), 'name')
|
|
||||||
return (name =~ '^mkd\%(Code$\|Snippet\)' || name != '' && name !~ '^\%(mkd\|html\)')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
if get(g:, "vim_markdown_folding_style_pythonic", 0)
|
|
||||||
function! Foldexpr_markdown(lnum)
|
|
||||||
let l1 = getline(a:lnum)
|
|
||||||
"~~~~~ keep track of fenced code blocks ~~~~~
|
|
||||||
"If we hit a code block fence
|
|
||||||
if l1 =~ '````*' || l1 =~ '\~\~\~\~*'
|
|
||||||
" toggle the variable that says if we're in a code block
|
|
||||||
if b:fenced_block == 0
|
|
||||||
let b:fenced_block = 1
|
|
||||||
elseif b:fenced_block == 1
|
|
||||||
let b:fenced_block = 0
|
|
||||||
endif
|
|
||||||
" else, if we're caring about front matter
|
|
||||||
elseif g:vim_markdown_frontmatter == 1
|
|
||||||
" if we're in front matter and not on line 1
|
|
||||||
if b:front_matter == 1 && a:lnum > 2
|
|
||||||
let l0 = getline(a:lnum-1)
|
|
||||||
" if the previous line fenced front matter
|
|
||||||
if l0 == '---'
|
|
||||||
" we must not be in front matter
|
|
||||||
let b:front_matter = 0
|
|
||||||
endif
|
|
||||||
" else, if we're on line one
|
|
||||||
elseif a:lnum == 1
|
|
||||||
" if we hit a front matter fence
|
|
||||||
if l1 == '---'
|
|
||||||
" we're in the front matter
|
|
||||||
let b:front_matter = 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
" if we're in a code block or front matter
|
|
||||||
if b:fenced_block == 1 || b:front_matter == 1
|
|
||||||
if a:lnum == 1
|
|
||||||
" fold any 'preamble'
|
|
||||||
return '>1'
|
|
||||||
else
|
|
||||||
" keep previous foldlevel
|
|
||||||
return '='
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l2 = getline(a:lnum+1)
|
|
||||||
" if the next line starts with two or more '='
|
|
||||||
" and is not code
|
|
||||||
if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1)
|
|
||||||
" next line is underlined (level 1)
|
|
||||||
return '>0'
|
|
||||||
" else, if the nex line starts with two or more '-'
|
|
||||||
" and is not code
|
|
||||||
elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1)
|
|
||||||
" next line is underlined (level 2)
|
|
||||||
return '>1'
|
|
||||||
endif
|
|
||||||
|
|
||||||
"if we're on a non-code line starting with a pound sign
|
|
||||||
if l1 =~ '^#' && !s:is_mkdCode(a:lnum)
|
|
||||||
" set the fold level to the number of hashes -1
|
|
||||||
" return '>'.(matchend(l1, '^#\+') - 1)
|
|
||||||
" set the fold level to the number of hashes
|
|
||||||
return '>'.(matchend(l1, '^#\+'))
|
|
||||||
" else, if we're on line 1
|
|
||||||
elseif a:lnum == 1
|
|
||||||
" fold any 'preamble'
|
|
||||||
return '>1'
|
|
||||||
else
|
|
||||||
" keep previous foldlevel
|
|
||||||
return '='
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! Foldtext_markdown()
|
|
||||||
let line = getline(v:foldstart)
|
|
||||||
let has_numbers = &number || &relativenumber
|
|
||||||
let nucolwidth = &fdc + has_numbers * &numberwidth
|
|
||||||
let windowwidth = winwidth(0) - nucolwidth - 6
|
|
||||||
let foldedlinecount = v:foldend - v:foldstart
|
|
||||||
let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount))
|
|
||||||
let line = substitute(line, '\%("""\|''''''\)', '', '')
|
|
||||||
let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + 1
|
|
||||||
return line . ' ' . repeat("-", fillcharcount) . ' ' . foldedlinecount
|
|
||||||
endfunction
|
|
||||||
else " vim_markdown_folding_style_pythonic == 0
|
|
||||||
function! Foldexpr_markdown(lnum)
|
|
||||||
if (a:lnum == 1)
|
|
||||||
let l0 = ''
|
|
||||||
else
|
|
||||||
let l0 = getline(a:lnum-1)
|
|
||||||
endif
|
|
||||||
|
|
||||||
" keep track of fenced code blocks
|
|
||||||
if l0 =~ '````*' || l0 =~ '\~\~\~\~*'
|
|
||||||
if b:fenced_block == 0
|
|
||||||
let b:fenced_block = 1
|
|
||||||
elseif b:fenced_block == 1
|
|
||||||
let b:fenced_block = 0
|
|
||||||
endif
|
|
||||||
elseif g:vim_markdown_frontmatter == 1
|
|
||||||
if b:front_matter == 1
|
|
||||||
if l0 == '---'
|
|
||||||
let b:front_matter = 0
|
|
||||||
endif
|
|
||||||
elseif a:lnum == 2
|
|
||||||
if l0 == '---'
|
|
||||||
let b:front_matter = 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if b:fenced_block == 1 || b:front_matter == 1
|
|
||||||
" keep previous foldlevel
|
|
||||||
return '='
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l2 = getline(a:lnum+1)
|
|
||||||
if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1)
|
|
||||||
" next line is underlined (level 1)
|
|
||||||
return '>1'
|
|
||||||
elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1)
|
|
||||||
" next line is underlined (level 2)
|
|
||||||
if s:vim_markdown_folding_level >= 2
|
|
||||||
return '>1'
|
|
||||||
else
|
|
||||||
return '>2'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l1 = getline(a:lnum)
|
|
||||||
if l1 =~ '^#' && !s:is_mkdCode(a:lnum)
|
|
||||||
" fold level according to option
|
|
||||||
if s:vim_markdown_folding_level == 1 || matchend(l1, '^#\+') > s:vim_markdown_folding_level
|
|
||||||
if a:lnum == line('$')
|
|
||||||
return matchend(l1, '^#\+') - 1
|
|
||||||
else
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
" headers are not folded
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if l0 =~ '^#' && !s:is_mkdCode(a:lnum-1)
|
|
||||||
" previous line starts with hashes
|
|
||||||
return '>'.matchend(l0, '^#\+')
|
|
||||||
else
|
|
||||||
" keep previous foldlevel
|
|
||||||
return '='
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
let b:fenced_block = 0
|
|
||||||
let b:front_matter = 0
|
|
||||||
let s:vim_markdown_folding_level = get(g:, "vim_markdown_folding_level", 1)
|
|
||||||
|
|
||||||
function! s:MarkdownSetupFolding()
|
|
||||||
if !get(g:, "vim_markdown_folding_disabled", 0)
|
|
||||||
if get(g:, "vim_markdown_folding_style_pythonic", 0)
|
|
||||||
if get(g:, "vim_markdown_override_foldtext", 1)
|
|
||||||
setlocal foldtext=Foldtext_markdown()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
setlocal foldexpr=Foldexpr_markdown(v:lnum)
|
|
||||||
setlocal foldmethod=expr
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:MarkdownSetupFoldLevel()
|
|
||||||
if get(g:, "vim_markdown_folding_style_pythonic", 0)
|
|
||||||
" set default foldlevel
|
|
||||||
execute "setlocal foldlevel=".s:vim_markdown_folding_level
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:MarkdownSetupFoldLevel()
|
|
||||||
call s:MarkdownSetupFolding()
|
|
||||||
|
|
||||||
augroup Mkd
|
|
||||||
" These autocmds need to be kept in sync with the autocmds calling
|
|
||||||
" s:MarkdownRefreshSyntax in ftplugin/markdown.vim.
|
|
||||||
autocmd BufWinEnter,BufWritePost <buffer> call s:MarkdownSetupFolding()
|
|
||||||
autocmd InsertEnter,InsertLeave <buffer> call s:MarkdownSetupFolding()
|
|
||||||
autocmd CursorHold,CursorHoldI <buffer> call s:MarkdownSetupFolding()
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
endif
|
|
||||||
20
after/ftplugin/tex.vim
Normal file
20
after/ftplugin/tex.vim
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
if !get(g:, 'vimtex_enabled', 1)
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists('b:did_ftplugin_vimtex')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let b:did_ftplugin_vimtex = 1
|
||||||
|
|
||||||
|
call vimtex#check_plugin_clash()
|
||||||
|
|
||||||
|
endif
|
||||||
@@ -20,11 +20,11 @@ if exists("loaded_matchup")
|
|||||||
let b:match_skip = 's:comment\|string'
|
let b:match_skip = 's:comment\|string'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let b:original_commentstring = &l:commentstring
|
let b:jsx_pretty_old_cms = &l:commentstring
|
||||||
|
|
||||||
augroup jsx_comment
|
augroup jsx_comment
|
||||||
autocmd! CursorMoved <buffer>
|
autocmd! CursorMoved <buffer>
|
||||||
autocmd CursorMoved <buffer> call jsx_pretty#comment#update_commentstring(b:original_commentstring)
|
autocmd CursorMoved <buffer> call jsx_pretty#comment#update_commentstring(b:jsx_pretty_old_cms)
|
||||||
augroup end
|
augroup end
|
||||||
|
|
||||||
setlocal suffixesadd+=.tsx
|
setlocal suffixesadd+=.tsx
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
||||||
|
|
||||||
source <sfile>:h/typescript.vim
|
source <sfile>:h/tsx.vim
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ if exists('s:did_indent')
|
|||||||
let b:did_indent = s:did_indent
|
let b:did_indent = s:did_indent
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
runtime! indent/typescript.vim
|
||||||
|
|
||||||
setlocal indentexpr=GetJsxIndent()
|
setlocal indentexpr=GetJsxIndent()
|
||||||
setlocal indentkeys=0.,0{,0},0),0],0?,0\*,0\,,!^F,:,<:>,o,O,e,<>>,=*/
|
setlocal indentkeys=0.,0{,0},0),0],0?,0\*,0\,,!^F,:,<:>,o,O,e,<>>,=*/
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
||||||
|
|
||||||
source <sfile>:h/typescript.vim
|
source <sfile>:h/tsx.vim
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,5 +1,28 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
||||||
|
|
||||||
|
" Copyright (c) 2016-2020 Jon Parise <jon@indelible.org>
|
||||||
|
"
|
||||||
|
" Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
" of this software and associated documentation files (the "Software"), to
|
||||||
|
" deal in the Software without restriction, including without limitation the
|
||||||
|
" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
" sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
" furnished to do so, subject to the following conditions:
|
||||||
|
"
|
||||||
|
" The above copyright notice and this permission notice shall be included in
|
||||||
|
" all copies or substantial portions of the Software.
|
||||||
|
"
|
||||||
|
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
" IN THE SOFTWARE.
|
||||||
|
"
|
||||||
|
" Language: GraphQL
|
||||||
|
" Maintainer: Jon Parise <jon@indelible.org>
|
||||||
|
|
||||||
if exists('b:current_syntax')
|
if exists('b:current_syntax')
|
||||||
let s:current_syntax = b:current_syntax
|
let s:current_syntax = b:current_syntax
|
||||||
unlet b:current_syntax
|
unlet b:current_syntax
|
||||||
@@ -11,17 +34,31 @@ endif
|
|||||||
|
|
||||||
let s:tags = '\%(' . join(graphql#javascript_tags(), '\|') . '\)'
|
let s:tags = '\%(' . join(graphql#javascript_tags(), '\|') . '\)'
|
||||||
|
|
||||||
exec 'syntax region graphqlTemplateString start=+' . s:tags . '\@20<=`+ skip=+\\`+ end=+`+ contains=@GraphQLSyntax,jsTemplateExpression,jsSpecial extend'
|
if graphql#has_syntax_group('jsTemplateExpression')
|
||||||
exec 'syntax match graphqlTaggedTemplate +' . s:tags . '\ze`+ nextgroup=graphqlTemplateString'
|
" pangloss/vim-javascript
|
||||||
|
exec 'syntax region graphqlTemplateString start=+' . s:tags . '\@20<=`+ skip=+\\\\\|\\`+ end=+`+ contains=@GraphQLSyntax,jsTemplateExpression,jsSpecial extend'
|
||||||
|
exec 'syntax match graphqlTaggedTemplate +' . s:tags . '\ze`+ nextgroup=graphqlTemplateString'
|
||||||
|
syntax region graphqlTemplateExpression start=+${+ end=+}+ contained contains=jsTemplateExpression containedin=graphqlFold keepend
|
||||||
|
|
||||||
" Support expression interpolation ((${...})) inside template strings.
|
hi def link graphqlTemplateString jsTemplateString
|
||||||
syntax region graphqlTemplateExpression start=+${+ end=+}+ contained contains=jsTemplateExpression containedin=graphqlFold keepend
|
hi def link graphqlTaggedTemplate jsTaggedTemplate
|
||||||
|
hi def link graphqlTemplateExpression jsTemplateExpression
|
||||||
|
|
||||||
hi def link graphqlTemplateString jsTemplateString
|
syn cluster jsExpression add=graphqlTaggedTemplate
|
||||||
hi def link graphqlTaggedTemplate jsTaggedTemplate
|
syn cluster graphqlTaggedTemplate add=graphqlTemplateString
|
||||||
hi def link graphqlTemplateExpression jsTemplateExpression
|
elseif graphql#has_syntax_group('javaScriptStringT')
|
||||||
|
" runtime/syntax/javascript.vim
|
||||||
|
exec 'syntax region graphqlTemplateString start=+' . s:tags . '\@20<=`+ skip=+\\\\\|\\`+ end=+`+ contains=@GraphQLSyntax,javaScriptSpecial,javaScriptEmbed,@htmlPreproc extend'
|
||||||
|
exec 'syntax match graphqlTaggedTemplate +' . s:tags . '\ze`+ nextgroup=graphqlTemplateString'
|
||||||
|
syntax region graphqlTemplateExpression start=+${+ end=+}+ contained contains=@javaScriptEmbededExpr containedin=graphqlFold keepend
|
||||||
|
|
||||||
syn cluster jsExpression add=graphqlTaggedTemplate
|
hi def link graphqlTemplateString javaScriptStringT
|
||||||
syn cluster graphqlTaggedTemplate add=graphqlTemplateString
|
hi def link graphqlTaggedTemplate javaScriptEmbed
|
||||||
|
hi def link graphqlTemplateExpression javaScriptEmbed
|
||||||
|
|
||||||
|
syn cluster htmlJavaScript add=graphqlTaggedTemplate
|
||||||
|
syn cluster javaScriptEmbededExpr add=graphqlTaggedTemplate
|
||||||
|
syn cluster graphqlTaggedTemplate add=graphqlTemplateString
|
||||||
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
5
after/syntax/javascriptreact/graphql.vim
Normal file
5
after/syntax/javascriptreact/graphql.vim
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
||||||
|
|
||||||
|
runtime! after/syntax/javascript/graphql.vim
|
||||||
|
|
||||||
|
endif
|
||||||
@@ -20,7 +20,7 @@ syntax region jsxTag
|
|||||||
\ matchgroup=NONE
|
\ matchgroup=NONE
|
||||||
\ end=+\%(/\_s*>\)\@=+
|
\ end=+\%(/\_s*>\)\@=+
|
||||||
\ contained
|
\ contained
|
||||||
\ contains=jsxOpenTag,jsxAttrib,jsxEscapeJs,jsxSpreadOperator,jsComment,@javascriptComments,javaScriptLineComment,javaScriptComment,typescriptLineComment,typescriptComment
|
\ contains=jsxOpenTag,jsxAttrib,jsxExpressionBlock,jsxSpreadOperator,jsComment,@javascriptComments,javaScriptLineComment,javaScriptComment,typescriptLineComment,typescriptComment
|
||||||
\ keepend
|
\ keepend
|
||||||
\ extend
|
\ extend
|
||||||
\ skipwhite
|
\ skipwhite
|
||||||
@@ -39,7 +39,7 @@ syntax region jsxElement
|
|||||||
\ start=+<\_s*\%(>\|\${\|\z(\<[-:._$A-Za-z0-9]\+\>\)\)+
|
\ start=+<\_s*\%(>\|\${\|\z(\<[-:._$A-Za-z0-9]\+\>\)\)+
|
||||||
\ end=+/\_s*>+
|
\ end=+/\_s*>+
|
||||||
\ end=+<\_s*/\_s*\z1\_s*>+
|
\ end=+<\_s*/\_s*\z1\_s*>+
|
||||||
\ contains=jsxElement,jsxTag,jsxEscapeJs,jsxComment,jsxCloseTag,@Spell
|
\ contains=jsxElement,jsxTag,jsxExpressionBlock,jsxComment,jsxCloseTag,@Spell
|
||||||
\ keepend
|
\ keepend
|
||||||
\ extend
|
\ extend
|
||||||
\ contained
|
\ contained
|
||||||
@@ -66,13 +66,13 @@ exe 'syntax region jsxOpenTag
|
|||||||
|
|
||||||
" <tag key={this.props.key}>
|
" <tag key={this.props.key}>
|
||||||
" ~~~~~~~~~~~~~~~~
|
" ~~~~~~~~~~~~~~~~
|
||||||
syntax region jsxEscapeJs
|
syntax region jsxExpressionBlock
|
||||||
\ matchgroup=jsxBraces
|
\ matchgroup=jsxBraces
|
||||||
\ start=+{+
|
\ start=+{+
|
||||||
\ end=+}+
|
\ end=+}+
|
||||||
\ contained
|
\ contained
|
||||||
\ extend
|
\ extend
|
||||||
\ contains=@jsExpression,jsSpreadExpression,@javascriptExpression,javascriptSpreadOp,@javaScriptEmbededExpr,@typescriptExpression,typescriptObjectSpread
|
\ contains=@jsExpression,jsSpreadExpression,@javascriptExpression,javascriptSpreadOp,@javaScriptEmbededExpr,@typescriptExpression,typescriptObjectSpread,jsComment,@javascriptComments,javaScriptLineComment,javaScriptComment,typescriptLineComment,typescriptComment
|
||||||
|
|
||||||
" <foo.bar>
|
" <foo.bar>
|
||||||
" ~
|
" ~
|
||||||
@@ -84,7 +84,7 @@ syntax match jsxNamespace +:+ contained
|
|||||||
|
|
||||||
" <tag id="sample">
|
" <tag id="sample">
|
||||||
" ~
|
" ~
|
||||||
syntax match jsxEqual +=+ contained skipwhite skipempty nextgroup=jsxString,jsxEscapeJs,jsxRegion
|
syntax match jsxEqual +=+ contained skipwhite skipempty nextgroup=jsxString,jsxExpressionBlock,jsxRegion
|
||||||
|
|
||||||
" <tag />
|
" <tag />
|
||||||
" ~~
|
" ~~
|
||||||
@@ -154,10 +154,10 @@ if s:enable_tagged_jsx
|
|||||||
\ end=+`+
|
\ end=+`+
|
||||||
\ extend
|
\ extend
|
||||||
\ contained
|
\ contained
|
||||||
\ contains=jsxElement,jsxEscapeJs
|
\ contains=jsxElement,jsxExpressionBlock
|
||||||
\ transparent
|
\ transparent
|
||||||
|
|
||||||
syntax region jsxEscapeJs
|
syntax region jsxExpressionBlock
|
||||||
\ matchgroup=jsxBraces
|
\ matchgroup=jsxBraces
|
||||||
\ start=+\${+
|
\ start=+\${+
|
||||||
\ end=+}+
|
\ end=+}+
|
||||||
@@ -171,14 +171,14 @@ if s:enable_tagged_jsx
|
|||||||
\ matchgroup=NONE
|
\ matchgroup=NONE
|
||||||
\ end=+}\@1<=+
|
\ end=+}\@1<=+
|
||||||
\ contained
|
\ contained
|
||||||
\ contains=jsxEscapeJs
|
\ contains=jsxExpressionBlock
|
||||||
\ skipwhite
|
\ skipwhite
|
||||||
\ skipempty
|
\ skipempty
|
||||||
\ nextgroup=jsxAttrib,jsxSpreadOperator
|
\ nextgroup=jsxAttrib,jsxSpreadOperator
|
||||||
|
|
||||||
syntax keyword jsxAttribKeyword class contained
|
syntax keyword jsxAttribKeyword class contained
|
||||||
|
|
||||||
syntax match jsxSpreadOperator +\.\.\.+ contained nextgroup=jsxEscapeJs skipwhite
|
syntax match jsxSpreadOperator +\.\.\.+ contained nextgroup=jsxExpressionBlock skipwhite
|
||||||
|
|
||||||
syntax match jsxCloseTag +<//>+ contained
|
syntax match jsxCloseTag +<//>+ contained
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,13 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'mathematica') =
|
|||||||
|
|
||||||
"Vim conceal file
|
"Vim conceal file
|
||||||
" Language: Mathematica
|
" Language: Mathematica
|
||||||
" Maintainer: Voldikss <dyzplus@gmail.com>
|
" Maintainer: R. Menon <rsmenon@icloud.com>
|
||||||
" Last Change: 2019 Jan 23 by Voldikss
|
" Last Change: Feb 25, 2013
|
||||||
" Source: https://github.com/voldikss/vim-mma/after/syntax/mma.vim
|
|
||||||
" Credits:
|
|
||||||
" Rsmenon: https://github.com/rsmenon
|
|
||||||
|
|
||||||
if (exists('g:mma_candy') && g:mma_candy == 0) || !has('conceal') || &enc != 'utf-8'
|
if (exists('g:mma_candy') && g:mma_candy == 0) || !has('conceal') || &enc != 'utf-8'
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
"These are fairly safe and straightforward conceals
|
"These are fairly safe and straightforward conceals
|
||||||
if exists('g:mma_candy') && g:mma_candy > 0
|
if exists('g:mma_candy') && g:mma_candy > 0
|
||||||
"Rules
|
"Rules
|
||||||
|
|||||||
@@ -9,26 +9,183 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'rspec') == -1
|
|||||||
runtime! syntax/ruby.vim
|
runtime! syntax/ruby.vim
|
||||||
unlet! b:current_syntax
|
unlet! b:current_syntax
|
||||||
|
|
||||||
syntax keyword rspecGroupMethods context describe example it its let it_should_behave_like shared_examples_for subject it_behaves_like pending specify When Then Given Invariant feature scenario given
|
setlocal commentstring=#\ %s
|
||||||
highlight link rspecGroupMethods Type
|
|
||||||
|
|
||||||
syntax keyword rspecBeforeAndAfter after after_suite_parts append_after append_before before before_suite_parts prepend_after prepend_before around
|
syntax keyword rspecGroupMethods
|
||||||
highlight link rspecBeforeAndAfter Statement
|
\ aggregate_failures
|
||||||
|
\ context
|
||||||
|
\ describe
|
||||||
|
\ example
|
||||||
|
\ feature
|
||||||
|
\ fcontext
|
||||||
|
\ fdescribe
|
||||||
|
\ fexample
|
||||||
|
\ fit
|
||||||
|
\ focus
|
||||||
|
\ fspecify
|
||||||
|
\ Given
|
||||||
|
\ given\!
|
||||||
|
\ include_context
|
||||||
|
\ include_examples
|
||||||
|
\ Invariant
|
||||||
|
\ it
|
||||||
|
\ it_behaves_like
|
||||||
|
\ it_should_behave_like
|
||||||
|
\ its
|
||||||
|
\ let
|
||||||
|
\ let\!
|
||||||
|
\ pending
|
||||||
|
\ scenario
|
||||||
|
\ shared_examples
|
||||||
|
\ shared_examples_for
|
||||||
|
\ skip
|
||||||
|
\ specify
|
||||||
|
\ subject
|
||||||
|
\ Then
|
||||||
|
\ When
|
||||||
|
|
||||||
syntax keyword rspecMocks double mock stub stub_chain
|
syntax keyword rspecBeforeAndAfter
|
||||||
highlight link rspecMocks Constant
|
\ after
|
||||||
|
\ after_suite_parts
|
||||||
|
\ append_after
|
||||||
|
\ append_before
|
||||||
|
\ around
|
||||||
|
\ before
|
||||||
|
\ before_suite_parts
|
||||||
|
\ prepend_after
|
||||||
|
\ prepend_before
|
||||||
|
|
||||||
syntax keyword rspecMockMethods and_raise and_return and_throw and_yield build_child called_max_times expected_args invoke matches
|
syntax keyword rspecMocks
|
||||||
highlight link rspecMockMethods Function
|
\ double
|
||||||
|
\ instance_double
|
||||||
|
\ instance_spy
|
||||||
|
\ mock
|
||||||
|
\ spy
|
||||||
|
\ stub
|
||||||
|
\ stub_chain
|
||||||
|
\ stub_const
|
||||||
|
|
||||||
syntax keyword rspecKeywords should should_not should_not_receive should_receive
|
syntax keyword rspecMockMethods
|
||||||
highlight link rspecKeywords Constant
|
\ and_call_original
|
||||||
|
\ and_raise
|
||||||
|
\ and_return
|
||||||
|
\ and_throw
|
||||||
|
\ and_yield
|
||||||
|
\ build_child
|
||||||
|
\ called_max_times
|
||||||
|
\ expected_args
|
||||||
|
\ invoke
|
||||||
|
\ matches
|
||||||
|
|
||||||
|
syntax keyword rspecKeywords
|
||||||
|
\ should
|
||||||
|
\ should_not
|
||||||
|
\ should_not_receive
|
||||||
|
\ should_receive
|
||||||
|
|
||||||
|
syntax keyword rspecMatchers
|
||||||
|
\ all
|
||||||
|
\ allow
|
||||||
|
\ allow_any_instance_of
|
||||||
|
\ assigns
|
||||||
|
\ be
|
||||||
|
\ change
|
||||||
|
\ described_class
|
||||||
|
\ eq
|
||||||
|
\ eql
|
||||||
|
\ equal
|
||||||
|
\ errors_on
|
||||||
|
\ exist
|
||||||
|
\ expect
|
||||||
|
\ expect_any_instance_of
|
||||||
|
\ have
|
||||||
|
\ have_at_least
|
||||||
|
\ have_at_most
|
||||||
|
\ have_exactly
|
||||||
|
\ include
|
||||||
|
\ is_expected
|
||||||
|
\ match
|
||||||
|
\ match_array
|
||||||
|
\ matcher
|
||||||
|
\ not_to
|
||||||
|
\ raise_error
|
||||||
|
\ raise_exception
|
||||||
|
\ receive
|
||||||
|
\ receive_messages
|
||||||
|
\ receive_message_chain
|
||||||
|
\ respond_to
|
||||||
|
\ satisfy
|
||||||
|
\ throw_symbol
|
||||||
|
\ to
|
||||||
|
\ to_not
|
||||||
|
\ when
|
||||||
|
\ wrap_expectation
|
||||||
|
|
||||||
|
" rspec-mongoid exclusive matchers
|
||||||
|
syntax keyword rspecMatchers
|
||||||
|
\ accept_nested_attributes_for
|
||||||
|
\ belong_to
|
||||||
|
\ custom_validate
|
||||||
|
\ embed_many
|
||||||
|
\ embed_one
|
||||||
|
\ validate_associated
|
||||||
|
\ validate_exclusion_of
|
||||||
|
\ validate_format_of
|
||||||
|
\ validate_inclusion_of
|
||||||
|
\ validate_length_of
|
||||||
|
|
||||||
|
" shoulda matchers
|
||||||
|
syntax keyword rspecMatchers
|
||||||
|
\ allow_mass_assignment_of
|
||||||
|
\ allow_value
|
||||||
|
\ ensure_exclusion_of
|
||||||
|
\ ensure_length_of
|
||||||
|
\ have_secure_password
|
||||||
|
\ validate_absence_of
|
||||||
|
\ validate_acceptance_of
|
||||||
|
\ validate_confirmation_of
|
||||||
|
\ validate_numericality_of
|
||||||
|
\ validate_presence_of
|
||||||
|
\ validate_uniqueness_of
|
||||||
|
|
||||||
|
syntax keyword rspecMessageExpectation
|
||||||
|
\ advise
|
||||||
|
\ any_args
|
||||||
|
\ any_number_of_times
|
||||||
|
\ anything
|
||||||
|
\ at_least
|
||||||
|
\ at_most
|
||||||
|
\ exactly
|
||||||
|
\ expected_messages_received
|
||||||
|
\ generate_error
|
||||||
|
\ hash_including
|
||||||
|
\ hash_not_including
|
||||||
|
\ ignoring_args
|
||||||
|
\ instance_of
|
||||||
|
\ matches_at_least_count
|
||||||
|
\ matches_at_most_count
|
||||||
|
\ matches_exact_count
|
||||||
|
\ matches_name_but_not_args
|
||||||
|
\ negative_expectation_for
|
||||||
|
\ never
|
||||||
|
\ no_args
|
||||||
|
\ once
|
||||||
|
\ ordered
|
||||||
|
\ similar_messages
|
||||||
|
\ times
|
||||||
|
\ twice
|
||||||
|
\ verify_messages_received
|
||||||
|
\ with
|
||||||
|
|
||||||
syntax keyword rspecMatchers be change eql equal exist expect have have_at_least have_at_most have_exactly include match matcher raise_error raise_exception respond_to satisfy throw_symbol to to_not not_to when wrap_expectation
|
|
||||||
syntax match rspecMatchers /\<\(be\|have\)_\w\+\>/
|
syntax match rspecMatchers /\<\(be\|have\)_\w\+\>/
|
||||||
highlight link rspecMatchers Function
|
syntax match rspecGroupMethods /\.describe/
|
||||||
|
|
||||||
syntax keyword rspecMessageExpectation advise any_args any_number_of_times anything at_least at_most exactly expected_messages_received generate_error hash_including hash_not_including ignoring_args instance_of matches_at_least_count matches_at_most_count matches_exact_count matches_name_but_not_args negative_expectation_for never no_args once ordered similar_messages times twice verify_messages_received with
|
highlight link rspecGroupMethods Statement
|
||||||
|
highlight link rspecBeforeAndAfter Identifier
|
||||||
|
highlight link rspecMocks Constant
|
||||||
|
highlight link rspecMockMethods Function
|
||||||
|
highlight link rspecKeywords Constant
|
||||||
|
highlight link rspecMatchers Function
|
||||||
highlight link rspecMessageExpectation Function
|
highlight link rspecMessageExpectation Function
|
||||||
|
|
||||||
let b:current_syntax = 'rspec'
|
let b:current_syntax = 'rspec'
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
" adds support for cleverref package
|
" vimtex - LaTeX plugin for Vim
|
||||||
" \Cref, \cref, \cpageref, \labelcref, \labelcpageref
|
"
|
||||||
syn region texRefZone matchgroup=texStatement start="\\Cref{" end="}\|%stopzone\>" contains=@texRefGroup
|
" Maintainer: Karl Yngve Lervåg
|
||||||
syn region texRefZone matchgroup=texStatement start="\\\(label\|\)c\(page\|\)ref{" end="}\|%stopzone\>" contains=@texRefGroup
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
" adds support for listings package
|
call vimtex#syntax#init()
|
||||||
syn region texZone start="\\begin{lstlisting}" end="\\end{lstlisting}\|%stopzone\>"
|
|
||||||
syn match texInputFile "\\lstinputlisting\s*\(\[.*\]\)\={.\{-}}" contains=texStatement,texInputCurlies,texInputFileOpt
|
|
||||||
syn match texZone "\\lstinline\s*\(\[.*\]\)\={.\{-}}"
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,28 +1,63 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
||||||
|
|
||||||
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
" Vim syntax file
|
||||||
|
"
|
||||||
|
" Language: javascript.jsx
|
||||||
|
" Maintainer: MaxMellon <maxmellon1994@gmail.com>
|
||||||
|
" Depends: leafgarland/typescript-vim
|
||||||
|
"
|
||||||
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
if get(g:, 'vim_jsx_pretty_disable_tsx', 0)
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:jsx_cpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
syntax case match
|
||||||
|
|
||||||
" GraphQL Support
|
|
||||||
if exists('b:current_syntax')
|
if exists('b:current_syntax')
|
||||||
let s:current_syntax = b:current_syntax
|
let s:current_syntax = b:current_syntax
|
||||||
unlet b:current_syntax
|
unlet b:current_syntax
|
||||||
endif
|
endif
|
||||||
syn include @GraphQLSyntax syntax/graphql.vim
|
|
||||||
if exists('s:current_syntax')
|
if exists('s:current_syntax')
|
||||||
let b:current_syntax = s:current_syntax
|
let b:current_syntax = s:current_syntax
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let s:tags = '\%(' . join(graphql#javascript_tags(), '\|') . '\)'
|
" refine the typescript line comment
|
||||||
|
syntax region typescriptLineComment start=+//+ end=/$/ contains=@Spell,typescriptCommentTodo,typescriptRef extend keepend
|
||||||
|
|
||||||
exec 'syntax region graphqlTemplateString start=+' . s:tags . '\@20<=`+ skip=+\\`+ end=+`+ contains=@GraphQLSyntax,typescriptTemplateSubstitution extend'
|
for syntax_name in ['tsxRegion', 'tsxFragment']
|
||||||
exec 'syntax match graphqlTaggedTemplate +' . s:tags . '\ze`+ nextgroup=graphqlTemplateString'
|
if hlexists(syntax_name)
|
||||||
|
exe 'syntax clear ' . syntax_name
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
" Support expression interpolation ((${...})) inside template strings.
|
if !hlexists('typescriptTypeCast')
|
||||||
syntax region graphqlTemplateExpression start=+${+ end=+}+ contained contains=typescriptTemplateSubstitution containedin=graphqlFold keepend
|
" add a typescriptBlock group for typescript
|
||||||
|
syntax region typescriptBlock
|
||||||
|
\ matchgroup=typescriptBraces
|
||||||
|
\ start="{"
|
||||||
|
\ end="}"
|
||||||
|
\ contained
|
||||||
|
\ extend
|
||||||
|
\ contains=@typescriptExpression,typescriptBlock
|
||||||
|
\ fold
|
||||||
|
hi def link typescriptTypeBrackets typescriptOpSymbols
|
||||||
|
endif
|
||||||
|
|
||||||
hi def link graphqlTemplateString typescriptTemplate
|
runtime syntax/jsx_pretty.vim
|
||||||
hi def link graphqlTemplateExpression typescriptTemplateSubstitution
|
syntax cluster typescriptExpression add=jsxRegion,typescriptParens
|
||||||
|
" Fix type casting ambiguity with JSX syntax
|
||||||
|
syntax match typescriptTypeBrackets +[<>]+ contained
|
||||||
|
syntax match typescriptTypeCast +<\([_$A-Za-z0-9]\+\)>\%(\s*\%([_$A-Za-z0-9]\+\s*;\?\|(\)\%(\_[^<]*</\1>\)\@!\)\@=+ contains=typescriptTypeBrackets,@typescriptType,typescriptType nextgroup=@typescriptExpression
|
||||||
|
|
||||||
syn cluster typescriptExpression add=graphqlTaggedTemplate
|
let b:current_syntax = 'typescript.tsx'
|
||||||
syn cluster graphqlTaggedTemplate add=graphqlTemplateString
|
|
||||||
|
|
||||||
|
let &cpo = s:jsx_cpo
|
||||||
|
unlet s:jsx_cpo
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
|
||||||
|
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
||||||
" Vim syntax file
|
|
||||||
"
|
|
||||||
" Language: javascript.jsx
|
|
||||||
" Maintainer: MaxMellon <maxmellon1994@gmail.com>
|
|
||||||
" Depends: leafgarland/typescript-vim
|
|
||||||
"
|
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
||||||
|
|
||||||
if get(g:, 'vim_jsx_pretty_disable_tsx', 0)
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
let s:jsx_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
syntax case match
|
|
||||||
|
|
||||||
if exists('b:current_syntax')
|
|
||||||
let s:current_syntax = b:current_syntax
|
|
||||||
unlet b:current_syntax
|
|
||||||
endif
|
|
||||||
|
|
||||||
if exists('s:current_syntax')
|
|
||||||
let b:current_syntax = s:current_syntax
|
|
||||||
endif
|
|
||||||
|
|
||||||
" refine the typescript line comment
|
|
||||||
syntax region typescriptLineComment start=+//+ end=/$/ contains=@Spell,typescriptCommentTodo,typescriptRef extend keepend
|
|
||||||
|
|
||||||
for syntax_name in ['tsxRegion', 'tsxFragment']
|
|
||||||
if hlexists(syntax_name)
|
|
||||||
exe 'syntax clear ' . syntax_name
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
if !hlexists('typescriptTypeCast')
|
|
||||||
" add a typescriptBlock group for typescript
|
|
||||||
syntax region typescriptBlock
|
|
||||||
\ matchgroup=typescriptBraces
|
|
||||||
\ start="{"
|
|
||||||
\ end="}"
|
|
||||||
\ contained
|
|
||||||
\ extend
|
|
||||||
\ contains=@typescriptExpression,typescriptBlock
|
|
||||||
\ fold
|
|
||||||
endif
|
|
||||||
|
|
||||||
syntax cluster typescriptExpression add=jsxRegion,typescriptParens
|
|
||||||
|
|
||||||
runtime syntax/jsx_pretty.vim
|
|
||||||
|
|
||||||
let b:current_syntax = 'typescript.tsx'
|
|
||||||
|
|
||||||
let &cpo = s:jsx_cpo
|
|
||||||
unlet s:jsx_cpo
|
|
||||||
|
|
||||||
endif
|
|
||||||
@@ -1,5 +1,28 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
||||||
|
|
||||||
|
" Copyright (c) 2016-2020 Jon Parise <jon@indelible.org>
|
||||||
|
"
|
||||||
|
" Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
" of this software and associated documentation files (the "Software"), to
|
||||||
|
" deal in the Software without restriction, including without limitation the
|
||||||
|
" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
" sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
" furnished to do so, subject to the following conditions:
|
||||||
|
"
|
||||||
|
" The above copyright notice and this permission notice shall be included in
|
||||||
|
" all copies or substantial portions of the Software.
|
||||||
|
"
|
||||||
|
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
" IN THE SOFTWARE.
|
||||||
|
"
|
||||||
|
" Language: GraphQL
|
||||||
|
" Maintainer: Jon Parise <jon@indelible.org>
|
||||||
|
|
||||||
if exists('b:current_syntax')
|
if exists('b:current_syntax')
|
||||||
let s:current_syntax = b:current_syntax
|
let s:current_syntax = b:current_syntax
|
||||||
unlet b:current_syntax
|
unlet b:current_syntax
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
||||||
|
|
||||||
source <sfile>:h/typescript.vim
|
source <sfile>:h/tsx.vim
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
5
after/syntax/typescriptreact/graphql.vim
Normal file
5
after/syntax/typescriptreact/graphql.vim
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
||||||
|
|
||||||
|
runtime! after/syntax/typescript/graphql.vim
|
||||||
|
|
||||||
|
endif
|
||||||
5
after/syntax/vue/graphql.vim
Normal file
5
after/syntax/vue/graphql.vim
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
||||||
|
|
||||||
|
runtime! after/syntax/javascript/graphql.vim
|
||||||
|
|
||||||
|
endif
|
||||||
@@ -42,8 +42,8 @@ syn keyword yamlConstant NULL Null null NONE None none NIL Nil nil
|
|||||||
syn keyword yamlConstant TRUE True true YES Yes yes ON On on
|
syn keyword yamlConstant TRUE True true YES Yes yes ON On on
|
||||||
syn keyword yamlConstant FALSE False false NO No no OFF Off off
|
syn keyword yamlConstant FALSE False false NO No no OFF Off off
|
||||||
|
|
||||||
syn match yamlKey "^\s*\zs[^ \t\"]\+\ze\s*:"
|
syn match yamlKey "^\s*\zs[^ \t\"\'#]\+\ze\s*:"
|
||||||
syn match yamlKey "^\s*-\s*\zs[^ \t\"\']\+\ze\s*:"
|
syn match yamlKey "^\s*-\s*\zs[^ \t\"\'#]\+\ze\s*:"
|
||||||
syn match yamlAnchor "&\S\+"
|
syn match yamlAnchor "&\S\+"
|
||||||
syn match yamlAlias "*\S\+"
|
syn match yamlAlias "*\S\+"
|
||||||
|
|
||||||
|
|||||||
126
after/syntax/zsh.vim
Normal file
126
after/syntax/zsh.vim
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'zinit') == -1
|
||||||
|
|
||||||
|
" Copyright (c) 2019 Sebastian Gniazdowski
|
||||||
|
"
|
||||||
|
" Syntax highlighting for Zinit commands in any file of type `zsh'.
|
||||||
|
" It adds definitions for the Zinit syntax to the ones from the
|
||||||
|
" existing zsh.vim definitions-file.
|
||||||
|
|
||||||
|
" Main Zinit command.
|
||||||
|
" Should be the only TOP rule for the whole syntax.
|
||||||
|
syntax match ZinitCommand /\<zinit\>\s/me=e-1
|
||||||
|
\ skipwhite
|
||||||
|
\ nextgroup=ZinitSubCommands,ZinitPluginSubCommands,ZinitSnippetSubCommands
|
||||||
|
\ contains=ZinitSubCommands,ZinitPluginSubCommands,ZinitSnippetSubCommands
|
||||||
|
|
||||||
|
" TODO: add options for e.g. light
|
||||||
|
syntax match ZinitSubCommands /\s\<\%(ice\|compinit\|env-whitelist\|cdreplay\|cdclear\|update\)\>\s/ms=s+1,me=e-1
|
||||||
|
\ contained
|
||||||
|
|
||||||
|
syntax match ZinitPluginSubCommands /\s\<\%(light\|load\)\>\s/ms=s+1,me=e-1
|
||||||
|
\ skipwhite nextgroup=ZinitPlugin1,ZinitPlugin2,ZinitPlugin3
|
||||||
|
\ contains=ZinitPlugin1,ZinitPlugin2,ZinitPlugin3
|
||||||
|
|
||||||
|
syntax match ZinitSnippetSubCommands /\s\<\%(snippet\)\>\s/ms=s+1,me=e-1
|
||||||
|
\ skipwhite
|
||||||
|
\ nextgroup=ZinitSnippetShorthands1,ZinitSnippetShorthands2
|
||||||
|
\ contains=ZinitSnippetShorthands1,ZinitSnippetShorthands2
|
||||||
|
|
||||||
|
" "user/plugin"
|
||||||
|
syntax match ZinitPlugin1 /\s["]\%([!-_]*\%(\/[!-_]\+\)\+\|[!-_]\+\)["]/ms=s+1,hs=s+2,he=e-1
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
" 'user/plugin'
|
||||||
|
syntax match ZinitPlugin2 /\s[']\%([!-_]*\%(\/[!-_]\+\)\+\|[!-_]\+\)[']/ms=s+1,hs=s+2,he=e-1
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
" user/plugin
|
||||||
|
syntax match ZinitPlugin3 /\s\%([!-_]*\%(\/[!-_]\+\)\+\|[!-_]\+\)/ms=s+1,me=e+2
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
" OMZ:: or PZT::
|
||||||
|
" TODO: 'OMZ:: or 'PZT::
|
||||||
|
syntax match ZinitSnippetShorthands1 /\s\<\%(\%(OMZ\|PZT\)\>::\|\)/hs=s+1,he=e-2
|
||||||
|
\ contained
|
||||||
|
\ skipwhite
|
||||||
|
\ nextgroup=ZinitSnippetUrl1,ZinitSnippetUrl2
|
||||||
|
\ contains=ZinitSnippetUrl1,ZinitSnippetUrl2
|
||||||
|
|
||||||
|
" "OMZ:: or "PZT::
|
||||||
|
syntax match ZinitSnippetShorthands2 /\s["]\%(\%(OMZ\|PZT\)\>::\|\)/hs=s+2,he=e-2
|
||||||
|
\ contained
|
||||||
|
\ skipwhite
|
||||||
|
\ nextgroup=ZinitSnippetUrl3,ZinitSnippetUrl4
|
||||||
|
\ contains=ZinitSnippetUrl3,ZinitSnippetUrl4
|
||||||
|
|
||||||
|
syntax match ZinitSnippetUrl3 /\<\%(http:\/\/\|https:\/\/\|ftp:\/\/\|\$HOME\|\/\)[!-_]\+\%(\/[!-_]\+\)*\/\?["]/he=e-1
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
" TODO: Fix ZinitTrailingWhiteSpace not matching
|
||||||
|
syntax match ZinitSnippetUrl4 /\%(\%(OMZ\|PZT\)::\)[!-_]\+\%(\/[!-_]\+\)*\/\?["]/hs=s+5,he=e-1
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
" http://… or https://… or ftp://… or $HOME/… or /…
|
||||||
|
" TODO: Fix $HOME/… and /… not matching
|
||||||
|
syntax match ZinitSnippetUrl1 /\<\%(http:\/\/\|https:\/\/\|ftp:\/\/\|\$HOME\|\/\)[!-_]\+\%(\/[!-_]\+\)*\/\?/
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
" TODO: Fix ZinitTrailingWhiteSpace not matching
|
||||||
|
syntax match ZinitSnippetUrl2 /\<\%(\%(OMZ\|PZT\)::\)[!-_]\+\%(\/[!-_]\+\)*\/\?/hs=s+5
|
||||||
|
\ contained
|
||||||
|
\ nextgroup=ZinitTrailingWhiteSpace
|
||||||
|
\ contains=ZinitTrailingWhiteSpace
|
||||||
|
|
||||||
|
syntax match ZinitTrailingWhiteSpace /[[:space:]]\+$/ contained
|
||||||
|
|
||||||
|
" TODO: differentiate the no-value ices
|
||||||
|
" TODO: use contained
|
||||||
|
syntax match ZinitIceSubCommand /\sice\s/ms=s+1,me=e-1 nextgroup=ZinitIceModifiers
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(svn\|proto\|from\|teleid\|bindmap\|cloneopts\|id-as\|depth\|if\|wait\|load\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(unload\|blockf\|on-update-of\|subscribe\|pick\|bpick\|src\|as\|ver\|silent\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(lucid\|notify\|mv\|cp\|atinit\|atclone\|atload\|atpull\|nocd\|run-atpull\|has\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(cloneonly\|make\|service\|trackbinds\|multisrc\|compile\|nocompile\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(nocompletions\|reset-prompt\|wrap-track\|reset\|aliases\|sh\|bash\|ksh\|csh\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(\\!sh\|!sh\|\\!bash\|!bash\|\\!ksh\|!ksh\|\\!csh\|!csh\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(blockf\|silent\|lucid\|trackbinds\|cloneonly\|nocd\|run-atpull\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(\|sh\|\!sh\|bash\|\!bash\|ksh\|\!ksh\|csh\|\!csh\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(nocompletions\|svn\|aliases\|trigger-load\)\>/ms=s+1
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(light-mode\|is-snippet\|countdown\|ps-on-unload\|ps-on-update\)\>/ms=s+1
|
||||||
|
|
||||||
|
" Include also ices added by the existing annexes
|
||||||
|
syntax match ZinitIceModifiers /\s\<\%(test\|zman\|submod\|dl\|patch\|fbin\|sbin\|fsrc\|ferc\|fmod\|gem\|node\|rustup\|cargo\)\>/ms=s+1
|
||||||
|
|
||||||
|
" Additional Zsh and Zinit functions
|
||||||
|
syntax match ZshAndZinitFunctions /\<\%(compdef\|compinit\|zpcdreplay\|zpcdclear\|zpcompinit\|zpcompdef\)\>/
|
||||||
|
|
||||||
|
" Link
|
||||||
|
highlight def link ZshAndZinitFunctions Keyword
|
||||||
|
highlight def link ZinitCommand Statement
|
||||||
|
highlight def link ZinitSubCommands Title
|
||||||
|
highlight def link ZinitPluginSubCommands Title
|
||||||
|
highlight def link ZinitSnippetSubCommands Title
|
||||||
|
highlight def link ZinitIceModifiers Type
|
||||||
|
highlight def link ZinitSnippetShorthands1 Keyword
|
||||||
|
highlight def link ZinitSnippetShorthands2 Keyword
|
||||||
|
highlight def link ZinitPlugin1 Macro
|
||||||
|
highlight def link ZinitPlugin2 Macro
|
||||||
|
highlight def link ZinitPlugin3 Macro
|
||||||
|
highlight def link ZinitSnippetUrl1 Macro
|
||||||
|
highlight def link ZinitSnippetUrl2 Macro
|
||||||
|
highlight def link ZinitSnippetUrl3 Macro
|
||||||
|
highlight def link ZinitSnippetUrl4 Macro
|
||||||
|
highlight def link ZinitTrailingWhiteSpace Error
|
||||||
|
|
||||||
|
endif
|
||||||
@@ -13,6 +13,9 @@ function! s:L2U_Setup()
|
|||||||
if !has_key(b:, "l2u_enabled")
|
if !has_key(b:, "l2u_enabled")
|
||||||
let b:l2u_enabled = 0
|
let b:l2u_enabled = 0
|
||||||
endif
|
endif
|
||||||
|
if !has_key(b:, "l2u_autodetect_enable")
|
||||||
|
let b:l2u_autodetect_enable = 1
|
||||||
|
endif
|
||||||
|
|
||||||
" Did we install the L2U tab mappings?
|
" Did we install the L2U tab mappings?
|
||||||
if !has_key(b:, "l2u_tab_set")
|
if !has_key(b:, "l2u_tab_set")
|
||||||
@@ -92,34 +95,39 @@ endfunction
|
|||||||
" Each time the filetype changes, we may need to enable or
|
" Each time the filetype changes, we may need to enable or
|
||||||
" disable the LaTeX-to-Unicode functionality
|
" disable the LaTeX-to-Unicode functionality
|
||||||
function! LaTeXtoUnicode#Refresh()
|
function! LaTeXtoUnicode#Refresh()
|
||||||
|
|
||||||
call s:L2U_Setup()
|
call s:L2U_Setup()
|
||||||
|
|
||||||
|
" skip if manually overridden
|
||||||
|
if !b:l2u_autodetect_enable
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
|
||||||
" by default, LaTeX-to-Unicode is only active on julia files
|
" by default, LaTeX-to-Unicode is only active on julia files
|
||||||
let file_types = s:L2U_file_type_regex(get(g:, "latex_to_unicode_file_types", "julia"))
|
let file_types = s:L2U_file_type_regex(get(g:, "latex_to_unicode_file_types", "julia"))
|
||||||
let file_types_blacklist = s:L2U_file_type_regex(get(g:, "latex_to_unicode_file_types_blacklist", "$^"))
|
let file_types_blacklist = s:L2U_file_type_regex(get(g:, "latex_to_unicode_file_types_blacklist", "$^"))
|
||||||
|
|
||||||
if match(&filetype, file_types) < 0 || match(&filetype, file_types_blacklist) >= 0
|
if match(&filetype, file_types) < 0 || match(&filetype, file_types_blacklist) >= 0
|
||||||
if b:l2u_enabled
|
if b:l2u_enabled
|
||||||
call LaTeXtoUnicode#Disable()
|
call LaTeXtoUnicode#Disable(1)
|
||||||
else
|
else
|
||||||
return
|
return ''
|
||||||
endif
|
endif
|
||||||
elseif !b:l2u_enabled
|
elseif !b:l2u_enabled
|
||||||
call LaTeXtoUnicode#Enable()
|
call LaTeXtoUnicode#Enable(1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! LaTeXtoUnicode#Enable()
|
function! LaTeXtoUnicode#Enable(...)
|
||||||
|
let auto_set = a:0 > 0 ? a:1 : 0
|
||||||
|
|
||||||
if b:l2u_enabled
|
if b:l2u_enabled
|
||||||
return
|
return ''
|
||||||
end
|
end
|
||||||
|
|
||||||
call s:L2U_ResetLastCompletionInfo()
|
call s:L2U_ResetLastCompletionInfo()
|
||||||
|
|
||||||
let b:l2u_enabled = 1
|
let b:l2u_enabled = 1
|
||||||
|
let b:l2u_autodetect_enable = auto_set
|
||||||
|
|
||||||
" If we're editing the first file upon opening vim, this will only init the
|
" If we're editing the first file upon opening vim, this will only init the
|
||||||
" command line mode mapping, and the full initialization will be performed by
|
" command line mode mapping, and the full initialization will be performed by
|
||||||
@@ -127,18 +135,18 @@ function! LaTeXtoUnicode#Enable()
|
|||||||
" Otherwise, if we're opening a file from within a running vim session, this
|
" Otherwise, if we're opening a file from within a running vim session, this
|
||||||
" will actually initialize all the LaTeX-to-Unicode substitutions.
|
" will actually initialize all the LaTeX-to-Unicode substitutions.
|
||||||
call LaTeXtoUnicode#Init()
|
call LaTeXtoUnicode#Init()
|
||||||
|
return ''
|
||||||
return
|
|
||||||
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! LaTeXtoUnicode#Disable()
|
function! LaTeXtoUnicode#Disable(...)
|
||||||
|
let auto_set = a:0 > 0 ? a:1 : 0
|
||||||
if !b:l2u_enabled
|
if !b:l2u_enabled
|
||||||
return
|
return ''
|
||||||
endif
|
endif
|
||||||
let b:l2u_enabled = 0
|
let b:l2u_enabled = 0
|
||||||
|
let b:l2u_autodetect_enable = auto_set
|
||||||
call LaTeXtoUnicode#Init()
|
call LaTeXtoUnicode#Init()
|
||||||
return
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Translate old options to their new equivalents
|
" Translate old options to their new equivalents
|
||||||
@@ -246,7 +254,6 @@ function! LaTeXtoUnicode#omnifunc(findstart, base)
|
|||||||
endif
|
endif
|
||||||
let b:l2u_in_fallback = 0
|
let b:l2u_in_fallback = 0
|
||||||
" set info for the callback
|
" set info for the callback
|
||||||
let b:l2u_tab_completing = 1
|
|
||||||
let b:l2u_found_completion = 1
|
let b:l2u_found_completion = 1
|
||||||
" analyse current line
|
" analyse current line
|
||||||
let col1 = col('.')
|
let col1 = col('.')
|
||||||
@@ -375,6 +382,7 @@ function! LaTeXtoUnicode#Tab()
|
|||||||
endif
|
endif
|
||||||
" reset the in_fallback info
|
" reset the in_fallback info
|
||||||
let b:l2u_in_fallback = 0
|
let b:l2u_in_fallback = 0
|
||||||
|
let b:l2u_tab_completing = 1
|
||||||
" temporary change to completeopt to use the `longest` setting, which is
|
" temporary change to completeopt to use the `longest` setting, which is
|
||||||
" probably the only one which makes sense given that the goal of the
|
" probably the only one which makes sense given that the goal of the
|
||||||
" completion is to substitute the final string
|
" completion is to substitute the final string
|
||||||
@@ -383,7 +391,8 @@ function! LaTeXtoUnicode#Tab()
|
|||||||
set completeopt-=noinsert
|
set completeopt-=noinsert
|
||||||
" invoke omnicompletion; failure to perform LaTeX-to-Unicode completion is
|
" invoke omnicompletion; failure to perform LaTeX-to-Unicode completion is
|
||||||
" handled by the CompleteDone autocommand.
|
" handled by the CompleteDone autocommand.
|
||||||
return "\<C-X>\<C-O>"
|
call feedkeys("\<C-X>\<C-O>", 'n')
|
||||||
|
return ""
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" This function is called at every CompleteDone event, and is meant to handle
|
" This function is called at every CompleteDone event, and is meant to handle
|
||||||
@@ -409,7 +418,7 @@ function! LaTeXtoUnicode#FallbackCallback()
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" This is the function that performs the substitution in command-line mode
|
" This is the function that performs the substitution in command-line mode
|
||||||
function! LaTeXtoUnicode#CmdTab(triggeredbytab)
|
function! LaTeXtoUnicode#CmdTab(trigger)
|
||||||
" first stage
|
" first stage
|
||||||
" analyse command line
|
" analyse command line
|
||||||
let col1 = getcmdpos() - 1
|
let col1 = getcmdpos() - 1
|
||||||
@@ -418,10 +427,12 @@ function! LaTeXtoUnicode#CmdTab(triggeredbytab)
|
|||||||
let b:l2u_singlebslash = (match(l[0:col1-1], '\\$') >= 0)
|
let b:l2u_singlebslash = (match(l[0:col1-1], '\\$') >= 0)
|
||||||
" completion not found
|
" completion not found
|
||||||
if col0 == -1
|
if col0 == -1
|
||||||
if a:triggeredbytab
|
if a:trigger == &wildchar
|
||||||
call feedkeys("\<Tab>", 'nt') " fall-back to the default <Tab>
|
call feedkeys(nr2char(a:trigger), 'nt') " fall-back to the default wildchar
|
||||||
|
elseif a:trigger == char2nr("\<S-Tab>")
|
||||||
|
call feedkeys("\<S-Tab>", 'nt') " fall-back to the default <S-Tab>
|
||||||
endif
|
endif
|
||||||
return l
|
return ''
|
||||||
endif
|
endif
|
||||||
let base = l[col0 : col1-1]
|
let base = l[col0 : col1-1]
|
||||||
" search for matches
|
" search for matches
|
||||||
@@ -430,39 +441,28 @@ function! LaTeXtoUnicode#CmdTab(triggeredbytab)
|
|||||||
for k in keys(g:l2u_symbols_dict)
|
for k in keys(g:l2u_symbols_dict)
|
||||||
if k ==# base
|
if k ==# base
|
||||||
let exact_match = 1
|
let exact_match = 1
|
||||||
endif
|
break
|
||||||
if len(k) >= len(base) && k[0 : len(base)-1] ==# base
|
elseif len(k) >= len(base) && k[0 : len(base)-1] ==# base
|
||||||
call add(partmatches, k)
|
call add(partmatches, k)
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
if len(partmatches) == 0
|
if !exact_match && len(partmatches) == 0
|
||||||
if a:triggeredbytab
|
" no matches, call fallbacks
|
||||||
call feedkeys("\<Tab>", 'nt') " fall-back to the default <Tab>
|
if a:trigger == &wildchar
|
||||||
|
call feedkeys(nr2char(a:trigger), 'nt') " fall-back to the default wildchar
|
||||||
|
elseif a:trigger == char2nr("\<S-Tab>")
|
||||||
|
call feedkeys("\<S-Tab>", 'nt') " fall-back to the default <S-Tab>
|
||||||
endif
|
endif
|
||||||
return l
|
elseif exact_match
|
||||||
endif
|
" exact matches are replaced with Unicode
|
||||||
" exact matches are replaced with Unicode
|
|
||||||
if exact_match
|
|
||||||
let unicode = g:l2u_symbols_dict[base]
|
let unicode = g:l2u_symbols_dict[base]
|
||||||
if col0 > 0
|
call feedkeys(repeat("\b", len(base)) . unicode, 'nt')
|
||||||
let pre = l[0 : col0 - 1]
|
|
||||||
else
|
|
||||||
let pre = ''
|
|
||||||
endif
|
|
||||||
let posdiff = col1-col0 - len(unicode)
|
|
||||||
call setcmdpos(col1 - posdiff + 1)
|
|
||||||
return pre . unicode . l[col1 : -1]
|
|
||||||
endif
|
|
||||||
" no exact match: complete with the longest common prefix
|
|
||||||
let common = s:L2U_longest_common_prefix(partmatches)
|
|
||||||
if col0 > 0
|
|
||||||
let pre = l[0 : col0 - 1]
|
|
||||||
else
|
else
|
||||||
let pre = ''
|
" no exact match: complete with the longest common prefix
|
||||||
|
let common = s:L2U_longest_common_prefix(partmatches)
|
||||||
|
call feedkeys(common[len(base):], 'nt')
|
||||||
endif
|
endif
|
||||||
let posdiff = col1-col0 - len(common)
|
return ''
|
||||||
call setcmdpos(col1 - posdiff + 1)
|
|
||||||
return pre . common . l[col1 : -1]
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Setup the L2U tab mapping
|
" Setup the L2U tab mapping
|
||||||
@@ -473,7 +473,8 @@ function! s:L2U_SetTab(wait_insert_enter)
|
|||||||
let b:l2u_cmdtab_keys = [b:l2u_cmdtab_keys]
|
let b:l2u_cmdtab_keys = [b:l2u_cmdtab_keys]
|
||||||
endif
|
endif
|
||||||
for k in b:l2u_cmdtab_keys
|
for k in b:l2u_cmdtab_keys
|
||||||
exec 'cnoremap <buffer> '.k.' <C-\>eLaTeXtoUnicode#CmdTab('.(k ==? '<Tab>').')<CR>'
|
exec 'let trigger = char2nr("'.(k[0] == '<' ? '\' : '').k.'")'
|
||||||
|
exec 'cnoremap <buffer><expr> '.k.' LaTeXtoUnicode#CmdTab('.trigger.')'
|
||||||
endfor
|
endfor
|
||||||
let b:l2u_cmdtab_set = 1
|
let b:l2u_cmdtab_set = 1
|
||||||
endif
|
endif
|
||||||
@@ -637,6 +638,7 @@ function! LaTeXtoUnicode#Init(...)
|
|||||||
call s:L2U_SetTab(wait_insert_enter)
|
call s:L2U_SetTab(wait_insert_enter)
|
||||||
call s:L2U_SetAutoSub(wait_insert_enter)
|
call s:L2U_SetAutoSub(wait_insert_enter)
|
||||||
call s:L2U_SetKeymap()
|
call s:L2U_SetKeymap()
|
||||||
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! LaTeXtoUnicode#Toggle()
|
function! LaTeXtoUnicode#Toggle()
|
||||||
@@ -648,7 +650,7 @@ function! LaTeXtoUnicode#Toggle()
|
|||||||
call LaTeXtoUnicode#Enable()
|
call LaTeXtoUnicode#Enable()
|
||||||
echo "LaTeX-to-Unicode enabled"
|
echo "LaTeX-to-Unicode enabled"
|
||||||
endif
|
endif
|
||||||
return
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'rust') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'rust') == -1
|
||||||
|
|
||||||
function! cargo#Load()
|
function! cargo#Load()
|
||||||
" Utility call to get this script loaded, for debugging
|
" Utility call to get this script loaded, for debugging
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! cargo#cmd(args)
|
function! cargo#cmd(args) abort
|
||||||
" Trim trailing spaces. This is necessary since :terminal command parses
|
" Trim trailing spaces. This is necessary since :terminal command parses
|
||||||
" trailing spaces as an empty argument.
|
" trailing spaces as an empty argument.
|
||||||
let args = substitute(a:args, '\s\+$', '', '')
|
let args = substitute(a:args, '\s\+$', '', '')
|
||||||
if has('terminal')
|
if exists('g:cargo_shell_command_runner')
|
||||||
|
let cmd = g:cargo_shell_command_runner
|
||||||
|
elseif has('terminal')
|
||||||
let cmd = 'terminal'
|
let cmd = 'terminal'
|
||||||
elseif has('nvim')
|
elseif has('nvim')
|
||||||
let cmd = 'noautocmd new | terminal'
|
let cmd = 'noautocmd new | terminal'
|
||||||
@@ -67,6 +69,10 @@ function! cargo#build(args)
|
|||||||
call cargo#cmd("build " . a:args)
|
call cargo#cmd("build " . a:args)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! cargo#check(args)
|
||||||
|
call cargo#cmd("check " . a:args)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! cargo#clean(args)
|
function! cargo#clean(args)
|
||||||
call cargo#cmd("clean " . a:args)
|
call cargo#cmd("clean " . a:args)
|
||||||
endfunction
|
endfunction
|
||||||
@@ -96,6 +102,22 @@ function! cargo#bench(args)
|
|||||||
call cargo#cmd("bench " . a:args)
|
call cargo#cmd("bench " . a:args)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! cargo#update(args)
|
||||||
|
call cargo#cmd("update " . a:args)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! cargo#search(args)
|
||||||
|
call cargo#cmd("search " . a:args)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! cargo#publish(args)
|
||||||
|
call cargo#cmd("publish " . a:args)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! cargo#install(args)
|
||||||
|
call cargo#cmd("install " . a:args)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! cargo#runtarget(args)
|
function! cargo#runtarget(args)
|
||||||
let l:filename = expand('%:p')
|
let l:filename = expand('%:p')
|
||||||
let l:read_manifest = system('cargo read-manifest')
|
let l:read_manifest = system('cargo read-manifest')
|
||||||
|
|||||||
367
autoload/crystal/indent.vim
Normal file
367
autoload/crystal/indent.vim
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'crystal') == -1
|
||||||
|
|
||||||
|
" Variables {{{1
|
||||||
|
" =========
|
||||||
|
|
||||||
|
" Regex of syntax group names that are strings or characters.
|
||||||
|
let g:crystal#indent#syng_string =
|
||||||
|
\ '\<crystal\%(String\|Interpolation\|NoInterpolation\|StringEscape\|CharLiteral\|ASCIICode\)\>'
|
||||||
|
lockvar g:crystal#indent#syng_string
|
||||||
|
|
||||||
|
" Regex of syntax group names that are strings, characters, symbols,
|
||||||
|
" regexps, or comments.
|
||||||
|
let g:crystal#indent#syng_strcom =
|
||||||
|
\ g:crystal#indent#syng_string.'\|' .
|
||||||
|
\ '\<crystal\%(Regexp\|RegexpEscape\|Symbol\|Comment\)\>'
|
||||||
|
lockvar g:crystal#indent#syng_strcom
|
||||||
|
|
||||||
|
" Expression used to check whether we should skip a match with searchpair().
|
||||||
|
let g:crystal#indent#skip_expr =
|
||||||
|
\ 'synIDattr(synID(line("."), col("."), 1), "name") =~# "'.g:crystal#indent#syng_strcom.'"'
|
||||||
|
lockvar g:crystal#indent#skip_expr
|
||||||
|
|
||||||
|
" Regex for the start of a line:
|
||||||
|
" start of line + whitespace + optional opening macro delimiter
|
||||||
|
let g:crystal#indent#sol = '^\s*\zs\%(\\\={%\s*\)\='
|
||||||
|
lockvar g:crystal#indent#sol
|
||||||
|
|
||||||
|
" Regex for the end of a line:
|
||||||
|
" whitespace + optional closing macro delimiter + whitespace +
|
||||||
|
" optional comment + end of line
|
||||||
|
let g:crystal#indent#eol = '\s*\%(%}\)\=\ze\s*\%(#.*\)\=$'
|
||||||
|
lockvar g:crystal#indent#eol
|
||||||
|
|
||||||
|
" Regex that defines blocks.
|
||||||
|
let g:crystal#indent#block_regex =
|
||||||
|
\ '\%(\<do\>\|%\@1<!{\)\s*\%(|[^|]*|\)\='.g:crystal#indent#eol
|
||||||
|
lockvar g:crystal#indent#block_regex
|
||||||
|
|
||||||
|
" Regex that defines the start-match for the 'end' keyword.
|
||||||
|
" NOTE: This *should* properly match the 'do' only at the end of the
|
||||||
|
" line
|
||||||
|
let g:crystal#indent#end_start_regex =
|
||||||
|
\ g:crystal#indent#sol .
|
||||||
|
\ '\%(' .
|
||||||
|
\ '\%(\<\%(private\|protected\)\s\+\)\=' .
|
||||||
|
\ '\%(\<\%(abstract\s\+\)\=\%(class\|struct\)\>\|\<\%(def\|module\|macro\|lib\|enum\)\>\)' .
|
||||||
|
\ '\|' .
|
||||||
|
\ '\<\%(if\|unless\|while\|until\|case\|begin\|for\|union\)\>' .
|
||||||
|
\ '\)' .
|
||||||
|
\ '\|' .
|
||||||
|
\ g:crystal#indent#block_regex
|
||||||
|
lockvar g:crystal#indent#end_start_regex
|
||||||
|
|
||||||
|
" Regex that defines the middle-match for the 'end' keyword.
|
||||||
|
let g:crystal#indent#end_middle_regex =
|
||||||
|
\ g:crystal#indent#sol .
|
||||||
|
\ '\<\%(else\|elsif\|rescue\|ensure\|when\)\>'
|
||||||
|
lockvar g:crystal#indent#end_middle_regex
|
||||||
|
|
||||||
|
" Regex that defines the end-match for the 'end' keyword.
|
||||||
|
let g:crystal#indent#end_end_regex =
|
||||||
|
\ g:crystal#indent#sol .
|
||||||
|
\ '\<end\>'
|
||||||
|
lockvar g:crystal#indent#end_end_regex
|
||||||
|
|
||||||
|
" Regex used for words that add a level of indent.
|
||||||
|
let g:crystal#indent#crystal_indent_keywords =
|
||||||
|
\ g:crystal#indent#end_start_regex .
|
||||||
|
\ '\|' .
|
||||||
|
\ g:crystal#indent#end_middle_regex
|
||||||
|
lockvar g:crystal#indent#crystal_indent_keywords
|
||||||
|
|
||||||
|
" Regex used for words that remove a level of indent.
|
||||||
|
let g:crystal#indent#crystal_deindent_keywords =
|
||||||
|
\ g:crystal#indent#end_middle_regex .
|
||||||
|
\ '\|' .
|
||||||
|
\ g:crystal#indent#end_end_regex
|
||||||
|
lockvar g:crystal#indent#crystal_deindent_keywords
|
||||||
|
|
||||||
|
" Regex that defines a type declaration
|
||||||
|
let g:crystal#indent#crystal_type_declaration =
|
||||||
|
\ '@\=\h\k*\s\+:\s\+\S.*'
|
||||||
|
lockvar g:crystal#indent#crystal_type_declaration
|
||||||
|
|
||||||
|
" Regex that defines continuation lines, not including (, {, or [.
|
||||||
|
let g:crystal#indent#non_bracket_continuation_regex =
|
||||||
|
\ '\%(' .
|
||||||
|
\ '[\\.,:/%+\-=~<>&^]' .
|
||||||
|
\ '\|' .
|
||||||
|
\ '\%(\%(\<do\>\|%\@1<!{\)\s*|[^|]*\)\@<!|' .
|
||||||
|
\ '\|' .
|
||||||
|
\ '\W?' .
|
||||||
|
\ '\|' .
|
||||||
|
\ '\<\%(if\|unless\)\>' .
|
||||||
|
\ '\|' .
|
||||||
|
\ '\%('.g:crystal#indent#crystal_type_declaration.'\h\k*\)\@<!\*' .
|
||||||
|
\ '\)' .
|
||||||
|
\ g:crystal#indent#eol
|
||||||
|
lockvar g:crystal#indent#non_bracket_continuation_regex
|
||||||
|
|
||||||
|
" Regex that defines bracket continuations
|
||||||
|
let g:crystal#indent#bracket_continuation_regex = '%\@1<!\%([({[]\)\s*\%(#.*\)\=$'
|
||||||
|
lockvar g:crystal#indent#bracket_continuation_regex
|
||||||
|
|
||||||
|
" Regex that defines continuation lines.
|
||||||
|
let g:crystal#indent#continuation_regex =
|
||||||
|
\ g:crystal#indent#non_bracket_continuation_regex .
|
||||||
|
\ '\|' .
|
||||||
|
\ g:crystal#indent#bracket_continuation_regex
|
||||||
|
lockvar g:crystal#indent#continuation_regex
|
||||||
|
|
||||||
|
" Regex that defines end of bracket continuation followed by another continuation
|
||||||
|
let g:crystal#indent#bracket_switch_continuation_regex =
|
||||||
|
\ '^\([^(]\+\zs).\+\)\+'.g:crystal#indent#continuation_regex
|
||||||
|
lockvar g:crystal#indent#bracket_switch_continuation_regex
|
||||||
|
|
||||||
|
" Regex that defines continuable keywords
|
||||||
|
let g:crystal#indent#continuable_regex =
|
||||||
|
\ '\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' .
|
||||||
|
\ '\<\%(if\|for\|while\|until\|unless\):\@!\>'
|
||||||
|
lockvar g:crystal#indent#continuable_regex
|
||||||
|
|
||||||
|
" Regex that defines the first part of a splat pattern
|
||||||
|
let g:crystal#indent#splat_regex = '[[,(]\s*\*\s*\%(#.*\)\=$'
|
||||||
|
lockvar g:crystal#indent#splat_regex
|
||||||
|
|
||||||
|
let g:crystal#indent#block_continuation_regex = '^\s*[^])}\t ].*'.g:crystal#indent#block_regex
|
||||||
|
lockvar g:crystal#indent#block_continuation_regex
|
||||||
|
|
||||||
|
" Regex that describes a leading operator (only a method call's dot for now)
|
||||||
|
let g:crystal#indent#leading_operator_regex = '^\s*[.]'
|
||||||
|
lockvar g:crystal#indent#leading_operator_regex
|
||||||
|
|
||||||
|
" Auxiliary Functions {{{1
|
||||||
|
" ===================
|
||||||
|
|
||||||
|
" Check if the character at lnum:col is inside a string, comment, or is ascii.
|
||||||
|
function! crystal#indent#IsInStringOrComment(lnum, col) abort
|
||||||
|
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~# g:crystal#indent#syng_strcom
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Check if the character at lnum:col is inside a string or character.
|
||||||
|
function! crystal#indent#IsInString(lnum, col) abort
|
||||||
|
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~# g:crystal#indent#syng_string
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Check if the character at lnum:col is inside a string or regexp
|
||||||
|
" delimiter
|
||||||
|
function! crystal#indent#IsInStringDelimiter(lnum, col) abort
|
||||||
|
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~# '\<crystal\%(StringDelimiter\|RegexpDelimiter\)\>'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
|
||||||
|
function! crystal#indent#PrevNonBlankNonString(lnum) abort
|
||||||
|
let lnum = prevnonblank(a:lnum)
|
||||||
|
|
||||||
|
while lnum > 0
|
||||||
|
let line = getline(lnum)
|
||||||
|
let start = match(line, '\S')
|
||||||
|
|
||||||
|
if !crystal#indent#IsInStringOrComment(lnum, start + 1)
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
|
||||||
|
let lnum = prevnonblank(lnum - 1)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return lnum
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Find line above 'lnum' that started the continuation 'lnum' may be part of.
|
||||||
|
function! crystal#indent#GetMSL(lnum) abort
|
||||||
|
" Start on the line we're at and use its indent.
|
||||||
|
let msl = a:lnum
|
||||||
|
let msl_body = getline(msl)
|
||||||
|
let lnum = crystal#indent#PrevNonBlankNonString(a:lnum - 1)
|
||||||
|
|
||||||
|
while lnum > 0
|
||||||
|
" If we have a continuation line, or we're in a string, use line as MSL.
|
||||||
|
" Otherwise, terminate search as we have found our MSL already.
|
||||||
|
let line = getline(lnum)
|
||||||
|
|
||||||
|
if crystal#indent#Match(msl, g:crystal#indent#leading_operator_regex)
|
||||||
|
" If the current line starts with a leading operator, keep its indent
|
||||||
|
" and keep looking for an MSL.
|
||||||
|
let msl = lnum
|
||||||
|
elseif crystal#indent#Match(lnum, g:crystal#indent#splat_regex)
|
||||||
|
" If the above line looks like the "*" of a splat, use the current one's
|
||||||
|
" indentation.
|
||||||
|
"
|
||||||
|
" Example:
|
||||||
|
" Hash[*
|
||||||
|
" method_call do
|
||||||
|
" something
|
||||||
|
"
|
||||||
|
return msl
|
||||||
|
elseif crystal#indent#Match(lnum, g:crystal#indent#non_bracket_continuation_regex) &&
|
||||||
|
\ crystal#indent#Match(msl, g:crystal#indent#non_bracket_continuation_regex)
|
||||||
|
" If the current line is a non-bracket continuation and so is the
|
||||||
|
" previous one, keep its indent and continue looking for an MSL.
|
||||||
|
"
|
||||||
|
" Example:
|
||||||
|
" method_call one,
|
||||||
|
" two,
|
||||||
|
" three
|
||||||
|
"
|
||||||
|
let msl = lnum
|
||||||
|
elseif crystal#indent#Match(lnum, g:crystal#indent#non_bracket_continuation_regex) &&
|
||||||
|
\ (
|
||||||
|
\ crystal#indent#Match(msl, g:crystal#indent#bracket_continuation_regex) ||
|
||||||
|
\ crystal#indent#Match(msl, g:crystal#indent#block_continuation_regex)
|
||||||
|
\ )
|
||||||
|
" If the current line is a bracket continuation or a block-starter, but
|
||||||
|
" the previous is a non-bracket one, respect the previous' indentation,
|
||||||
|
" and stop here.
|
||||||
|
"
|
||||||
|
" Example:
|
||||||
|
" method_call one,
|
||||||
|
" two {
|
||||||
|
" three
|
||||||
|
"
|
||||||
|
return lnum
|
||||||
|
elseif crystal#indent#Match(lnum, g:crystal#indent#bracket_continuation_regex) &&
|
||||||
|
\ (
|
||||||
|
\ crystal#indent#Match(msl, g:crystal#indent#bracket_continuation_regex) ||
|
||||||
|
\ crystal#indent#Match(msl, g:crystal#indent#block_continuation_regex)
|
||||||
|
\ )
|
||||||
|
" If both lines are bracket continuations (the current may also be a
|
||||||
|
" block-starter), use the current one's and stop here
|
||||||
|
"
|
||||||
|
" Example:
|
||||||
|
" method_call(
|
||||||
|
" other_method_call(
|
||||||
|
" foo
|
||||||
|
return msl
|
||||||
|
elseif crystal#indent#Match(lnum, g:crystal#indent#block_regex) &&
|
||||||
|
\ !crystal#indent#Match(msl, g:crystal#indent#continuation_regex) &&
|
||||||
|
\ !crystal#indent#Match(msl, g:crystal#indent#block_continuation_regex)
|
||||||
|
" If the previous line is a block-starter and the current one is
|
||||||
|
" mostly ordinary, use the current one as the MSL.
|
||||||
|
"
|
||||||
|
" Example:
|
||||||
|
" method_call do
|
||||||
|
" something
|
||||||
|
" something_else
|
||||||
|
return msl
|
||||||
|
else
|
||||||
|
let col = match(line, g:crystal#indent#continuation_regex) + 1
|
||||||
|
|
||||||
|
if (col > 0 && !crystal#indent#IsInStringOrComment(lnum, col))
|
||||||
|
\ || crystal#indent#IsInString(lnum, strlen(line))
|
||||||
|
let msl = lnum
|
||||||
|
else
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let msl_body = getline(msl)
|
||||||
|
let lnum = crystal#indent#PrevNonBlankNonString(lnum - 1)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return msl
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Check if line 'lnum' has more opening brackets than closing ones.
|
||||||
|
function! crystal#indent#ExtraBrackets(lnum) abort
|
||||||
|
let opening = {'parentheses': [], 'braces': [], 'brackets': []}
|
||||||
|
let closing = {'parentheses': [], 'braces': [], 'brackets': []}
|
||||||
|
|
||||||
|
let line = getline(a:lnum)
|
||||||
|
let pos = match(line, '[][(){}]', 0)
|
||||||
|
|
||||||
|
" Save any encountered opening brackets, and remove them once a matching
|
||||||
|
" closing one has been found. If a closing bracket shows up that doesn't
|
||||||
|
" close anything, save it for later.
|
||||||
|
while pos != -1
|
||||||
|
if !crystal#indent#IsInStringOrComment(a:lnum, pos + 1)
|
||||||
|
if line[pos] ==# '('
|
||||||
|
call add(opening.parentheses, {'type': '(', 'pos': pos})
|
||||||
|
elseif line[pos] ==# ')'
|
||||||
|
if empty(opening.parentheses)
|
||||||
|
call add(closing.parentheses, {'type': ')', 'pos': pos})
|
||||||
|
else
|
||||||
|
let opening.parentheses = opening.parentheses[0:-2]
|
||||||
|
endif
|
||||||
|
elseif line[pos] ==# '{'
|
||||||
|
call add(opening.braces, {'type': '{', 'pos': pos})
|
||||||
|
elseif line[pos] ==# '}'
|
||||||
|
if empty(opening.braces)
|
||||||
|
call add(closing.braces, {'type': '}', 'pos': pos})
|
||||||
|
else
|
||||||
|
let opening.braces = opening.braces[0:-2]
|
||||||
|
endif
|
||||||
|
elseif line[pos] ==# '['
|
||||||
|
call add(opening.brackets, {'type': '[', 'pos': pos})
|
||||||
|
elseif line[pos] ==# ']'
|
||||||
|
if empty(opening.brackets)
|
||||||
|
call add(closing.brackets, {'type': ']', 'pos': pos})
|
||||||
|
else
|
||||||
|
let opening.brackets = opening.brackets[0:-2]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let pos = match(line, '[][(){}]', pos + 1)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" Find the rightmost brackets, since they're the ones that are important in
|
||||||
|
" both opening and closing cases
|
||||||
|
let rightmost_opening = {'type': '(', 'pos': -1}
|
||||||
|
let rightmost_closing = {'type': ')', 'pos': -1}
|
||||||
|
|
||||||
|
for opening in opening.parentheses + opening.braces + opening.brackets
|
||||||
|
if opening.pos > rightmost_opening.pos
|
||||||
|
let rightmost_opening = opening
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
for closing in closing.parentheses + closing.braces + closing.brackets
|
||||||
|
if closing.pos > rightmost_closing.pos
|
||||||
|
let rightmost_closing = closing
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return [rightmost_opening, rightmost_closing]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! crystal#indent#Match(lnum, regex) abort
|
||||||
|
let regex = '\C'.a:regex
|
||||||
|
|
||||||
|
let line = getline(a:lnum)
|
||||||
|
let col = match(line, regex) + 1
|
||||||
|
|
||||||
|
while col &&
|
||||||
|
\ crystal#indent#IsInStringOrComment(a:lnum, col) ||
|
||||||
|
\ crystal#indent#IsInStringDelimiter(a:lnum, col)
|
||||||
|
let col = match(line, regex, col) + 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return col
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Locates the containing class/module/struct/enum/lib's definition line,
|
||||||
|
" ignoring nested classes along the way.
|
||||||
|
function! crystal#indent#FindContainingClass() abort
|
||||||
|
let saved_position = getcurpos()
|
||||||
|
|
||||||
|
while searchpair(
|
||||||
|
\ g:crystal#indent#end_start_regex,
|
||||||
|
\ g:crystal#indent#end_middle_regex,
|
||||||
|
\ g:crystal#indent#end_end_regex,
|
||||||
|
\ 'bWz',
|
||||||
|
\ g:crystal#indent#skip_expr) > 0
|
||||||
|
if expand('<cword>') =~# '\<\%(class\|module\|struct\|enum\|lib\)\>'
|
||||||
|
let found_lnum = line('.')
|
||||||
|
call setpos('.', saved_position)
|
||||||
|
return found_lnum
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call setpos('.', saved_position)
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" vim: sw=2 sts=2 et:
|
||||||
|
|
||||||
|
endif
|
||||||
@@ -7,42 +7,44 @@ let s:V = vital#crystal#new()
|
|||||||
let s:P = s:V.import('Process')
|
let s:P = s:V.import('Process')
|
||||||
let s:C = s:V.import('ColorEcho')
|
let s:C = s:V.import('ColorEcho')
|
||||||
|
|
||||||
|
let s:IS_WINDOWS = has('win32')
|
||||||
|
|
||||||
if exists('*json_decode')
|
if exists('*json_decode')
|
||||||
function! s:decode_json(text) abort
|
function! s:decode_json(text) abort
|
||||||
return json_decode(a:text)
|
return json_decode(a:text)
|
||||||
endfunction
|
endfunction
|
||||||
else
|
else
|
||||||
let s:J = s:V.import('Web.JSON')
|
let s:J = s:V.import('Web.JSON')
|
||||||
function! s:decode_json(text) abort
|
function! s:decode_json(text) abort
|
||||||
return s:J.decode(a:text)
|
return s:J.decode(a:text)
|
||||||
endfunction
|
endfunction
|
||||||
endif
|
endif
|
||||||
|
|
||||||
function! s:echo_error(msg, ...) abort
|
function! s:echo_error(msg, ...) abort
|
||||||
echohl ErrorMsg
|
echohl ErrorMsg
|
||||||
if a:0 == 0
|
if a:0 == 0
|
||||||
echomsg a:msg
|
echomsg a:msg
|
||||||
else
|
else
|
||||||
echomsg call('printf', [a:msg] + a:000)
|
echomsg call('printf', [a:msg] + a:000)
|
||||||
endif
|
endif
|
||||||
echohl None
|
echohl None
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:run_cmd(cmd) abort
|
function! s:run_cmd(cmd) abort
|
||||||
if !executable(g:crystal_compiler_command)
|
if !executable(g:crystal_compiler_command)
|
||||||
throw "vim-crystal: Error: '" . g:crystal_compiler_command . "' command is not found."
|
throw "vim-crystal: Error: '" . g:crystal_compiler_command . "' command is not found."
|
||||||
endif
|
endif
|
||||||
return s:P.system(a:cmd)
|
return s:P.system(a:cmd)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:find_root_by(search_dir, d) abort
|
function! s:find_root_by(search_dir, d) abort
|
||||||
let found_dir = finddir(a:search_dir, a:d . ';')
|
let found_dir = finddir(a:search_dir, a:d . ';')
|
||||||
if found_dir ==# ''
|
if found_dir ==# ''
|
||||||
return ''
|
return ''
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Note: ':h:h' for {root}/{search_dir}/ -> {root}/{search_dir} -> {root}
|
" Note: ':h:h' for {root}/{search_dir}/ -> {root}/{search_dir} -> {root}
|
||||||
return fnamemodify(found_dir, ':p:h:h')
|
return fnamemodify(found_dir, ':p:h:h')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Search the root directory containing a 'spec/' and a 'src/' directories.
|
" Search the root directory containing a 'spec/' and a 'src/' directories.
|
||||||
@@ -51,301 +53,321 @@ endfunction
|
|||||||
" compiler has a 'cr_sources/src/spec/' directory that would otherwise give the root
|
" compiler has a 'cr_sources/src/spec/' directory that would otherwise give the root
|
||||||
" directory as 'cr_source/src/' instead of 'cr_sources/'.
|
" directory as 'cr_source/src/' instead of 'cr_sources/'.
|
||||||
function! s:find_root_by_spec_and_src(d) abort
|
function! s:find_root_by_spec_and_src(d) abort
|
||||||
" Search for 'spec/'
|
" Search for 'spec/'
|
||||||
let root = s:find_root_by('spec', a:d)
|
let root = s:find_root_by('spec', a:d)
|
||||||
" Check that 'src/' is also there
|
" Check that 'src/' is also there
|
||||||
if root !=# '' && isdirectory(root . '/src')
|
if root !=# '' && isdirectory(root . '/src')
|
||||||
return root
|
return root
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Search for 'src/'
|
" Search for 'src/'
|
||||||
let root = s:find_root_by('src', a:d)
|
let root = s:find_root_by('src', a:d)
|
||||||
" Check that 'spec/' is also there
|
" Check that 'spec/' is also there
|
||||||
if root !=# '' && isdirectory(root . '/spec')
|
if root !=# '' && isdirectory(root . '/spec')
|
||||||
return root
|
return root
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Cannot find a directory containing both 'src/' and 'spec/'
|
" Cannot find a directory containing both 'src/' and 'spec/'
|
||||||
return ''
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#entrypoint_for(file_path) abort
|
function! crystal_lang#entrypoint_for(file_path) abort
|
||||||
let parent_dir = fnamemodify(a:file_path, ':p:h')
|
let parent_dir = fnamemodify(a:file_path, ':p:h')
|
||||||
let root_dir = s:find_root_by_spec_and_src(parent_dir)
|
let root_dir = s:find_root_by_spec_and_src(parent_dir)
|
||||||
if root_dir ==# ''
|
if root_dir ==# ''
|
||||||
" No spec directory found. No need to make temporary file
|
" No spec directory found. No need to make temporary file
|
||||||
return a:file_path
|
return a:file_path
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let required_spec_path = get(b:, 'crystal_required_spec_path', get(g:, 'crystal_required_spec_path', ''))
|
let required_spec_path = get(b:, 'crystal_required_spec_path', get(g:, 'crystal_required_spec_path', ''))
|
||||||
if required_spec_path !=# ''
|
if required_spec_path !=# ''
|
||||||
let require_spec_str = './' . required_spec_path
|
let require_spec_str = './' . required_spec_path
|
||||||
else
|
else
|
||||||
let require_spec_str = './spec/**'
|
let require_spec_str = './spec/**'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let temp_name = root_dir . '/__vim-crystal-temporary-entrypoint-' . fnamemodify(a:file_path, ':t')
|
let temp_name = root_dir . '/__vim-crystal-temporary-entrypoint-' . fnamemodify(a:file_path, ':t')
|
||||||
let contents = [
|
let contents = [
|
||||||
\ 'require "spec"',
|
\ 'require "spec"',
|
||||||
\ 'require "' . require_spec_str . '"',
|
\ 'require "' . require_spec_str . '"',
|
||||||
\ printf('require "./%s"', fnamemodify(a:file_path, ':p')[strlen(root_dir)+1 : ])
|
\ printf('require "./%s"', fnamemodify(a:file_path, ':p')[strlen(root_dir)+1 : ])
|
||||||
\ ]
|
\ ]
|
||||||
|
|
||||||
let result = writefile(contents, temp_name)
|
let result = writefile(contents, temp_name)
|
||||||
if result == -1
|
if result == -1
|
||||||
" Note: When writefile() failed
|
" Note: When writefile() failed
|
||||||
return a:file_path
|
return a:file_path
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return temp_name
|
return temp_name
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#tool(name, file, pos, option_str) abort
|
function! crystal_lang#tool(name, file, pos, option_str) abort
|
||||||
let entrypoint = crystal_lang#entrypoint_for(a:file)
|
let entrypoint = crystal_lang#entrypoint_for(a:file)
|
||||||
let cmd = printf(
|
let cmd = printf(
|
||||||
\ '%s tool %s --no-color %s --cursor %s:%d:%d %s',
|
\ '%s tool %s --no-color %s --cursor %s:%d:%d %s',
|
||||||
\ g:crystal_compiler_command,
|
\ g:crystal_compiler_command,
|
||||||
\ a:name,
|
\ a:name,
|
||||||
\ a:option_str,
|
\ a:option_str,
|
||||||
\ a:file,
|
\ a:file,
|
||||||
\ a:pos[1],
|
\ a:pos[1],
|
||||||
\ a:pos[2],
|
\ a:pos[2],
|
||||||
\ entrypoint
|
\ entrypoint
|
||||||
\ )
|
\ )
|
||||||
|
|
||||||
try
|
try
|
||||||
let output = s:run_cmd(cmd)
|
let output = s:run_cmd(cmd)
|
||||||
return {'failed': s:P.get_last_status(), 'output': output}
|
return {'failed': s:P.get_last_status(), 'output': output}
|
||||||
finally
|
finally
|
||||||
" Note:
|
" Note:
|
||||||
" If the entry point is temporary file, delete it finally.
|
" If the entry point is temporary file, delete it finally.
|
||||||
if a:file !=# entrypoint
|
if a:file !=# entrypoint
|
||||||
call delete(entrypoint)
|
call delete(entrypoint)
|
||||||
endif
|
endif
|
||||||
endtry
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" `pos` is assumed a returned value from getpos()
|
" `pos` is assumed a returned value from getpos()
|
||||||
function! crystal_lang#impl(file, pos, option_str) abort
|
function! crystal_lang#impl(file, pos, option_str) abort
|
||||||
return crystal_lang#tool('implementations', a:file, a:pos, a:option_str)
|
return crystal_lang#tool('implementations', a:file, a:pos, a:option_str)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:jump_to_impl(impl) abort
|
function! s:jump_to_impl(impl) abort
|
||||||
execute 'edit' a:impl.filename
|
execute 'edit' a:impl.filename
|
||||||
call cursor(a:impl.line, a:impl.column)
|
call cursor(a:impl.line, a:impl.column)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#jump_to_definition(file, pos) abort
|
function! crystal_lang#jump_to_definition(file, pos) abort
|
||||||
echo 'analyzing definitions under cursor...'
|
echo 'analyzing definitions under cursor...'
|
||||||
|
|
||||||
let cmd_result = crystal_lang#impl(a:file, a:pos, '--format json')
|
let cmd_result = crystal_lang#impl(a:file, a:pos, '--format json')
|
||||||
if cmd_result.failed
|
if cmd_result.failed
|
||||||
return s:echo_error(cmd_result.output)
|
return s:echo_error(cmd_result.output)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let impl = s:decode_json(cmd_result.output)
|
let impl = s:decode_json(cmd_result.output)
|
||||||
if impl.status !=# 'ok'
|
if impl.status !=# 'ok'
|
||||||
return s:echo_error(impl.message)
|
return s:echo_error(impl.message)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if len(impl.implementations) == 1
|
if len(impl.implementations) == 1
|
||||||
call s:jump_to_impl(impl.implementations[0])
|
call s:jump_to_impl(impl.implementations[0])
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let message = "Multiple definitions detected. Choose a number\n\n"
|
let message = "Multiple definitions detected. Choose a number\n\n"
|
||||||
for idx in range(len(impl.implementations))
|
for idx in range(len(impl.implementations))
|
||||||
let i = impl.implementations[idx]
|
let i = impl.implementations[idx]
|
||||||
let message .= printf("[%d] %s:%d:%d\n", idx, i.filename, i.line, i.column)
|
let message .= printf("[%d] %s:%d:%d\n", idx, i.filename, i.line, i.column)
|
||||||
endfor
|
endfor
|
||||||
let message .= "\n"
|
let message .= "\n"
|
||||||
let idx = str2nr(input(message, "\n> "))
|
let idx = str2nr(input(message, "\n> "))
|
||||||
call s:jump_to_impl(impl.implementations[idx])
|
call s:jump_to_impl(impl.implementations[idx])
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#context(file, pos, option_str) abort
|
function! crystal_lang#context(file, pos, option_str) abort
|
||||||
return crystal_lang#tool('context', a:file, a:pos, a:option_str)
|
return crystal_lang#tool('context', a:file, a:pos, a:option_str)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#type_hierarchy(file, option_str) abort
|
function! crystal_lang#type_hierarchy(file, option_str) abort
|
||||||
let cmd = printf(
|
let cmd = printf(
|
||||||
\ '%s tool hierarchy --no-color %s %s',
|
\ '%s tool hierarchy --no-color %s %s',
|
||||||
\ g:crystal_compiler_command,
|
\ g:crystal_compiler_command,
|
||||||
\ a:option_str,
|
\ a:option_str,
|
||||||
\ a:file
|
\ a:file
|
||||||
\ )
|
\ )
|
||||||
|
|
||||||
return s:run_cmd(cmd)
|
return s:run_cmd(cmd)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:find_completion_start() abort
|
function! s:find_completion_start() abort
|
||||||
let c = col('.')
|
let c = col('.')
|
||||||
if c <= 1
|
if c <= 1
|
||||||
return -1
|
return -1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let line = getline('.')[:c-2]
|
let line = getline('.')[:c-2]
|
||||||
return match(line, '\w\+$')
|
return match(line, '\w\+$')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#complete(findstart, base) abort
|
function! crystal_lang#complete(findstart, base) abort
|
||||||
if a:findstart
|
if a:findstart
|
||||||
return s:find_completion_start()
|
return s:find_completion_start()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let cmd_result = crystal_lang#context(expand('%'), getpos('.'), '--format json')
|
let cmd_result = crystal_lang#context(expand('%'), getpos('.'), '--format json')
|
||||||
if cmd_result.failed
|
if cmd_result.failed
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let contexts = s:decode_json(cmd_result.output)
|
let contexts = s:decode_json(cmd_result.output)
|
||||||
if contexts.status !=# 'ok'
|
if contexts.status !=# 'ok'
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let candidates = []
|
let candidates = []
|
||||||
|
|
||||||
for c in contexts.contexts
|
for c in contexts.contexts
|
||||||
for [name, desc] in items(c)
|
for [name, desc] in items(c)
|
||||||
let candidates += [{
|
let candidates += [{
|
||||||
\ 'word': name,
|
\ 'word': name,
|
||||||
\ 'menu': ': ' . desc . ' [var]',
|
\ 'menu': ': ' . desc . ' [var]',
|
||||||
\ }]
|
\ }]
|
||||||
endfor
|
|
||||||
endfor
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
return candidates
|
return candidates
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#get_spec_switched_path(absolute_path) abort
|
function! crystal_lang#get_spec_switched_path(absolute_path) abort
|
||||||
let base = fnamemodify(a:absolute_path, ':t:r')
|
let base = fnamemodify(a:absolute_path, ':t:r')
|
||||||
|
|
||||||
" TODO: Make cleverer
|
" TODO: Make cleverer
|
||||||
if base =~# '_spec$'
|
if base =~# '_spec$'
|
||||||
let parent = fnamemodify(substitute(a:absolute_path, '/spec/', '/src/', ''), ':h')
|
let parent = fnamemodify(substitute(a:absolute_path, '/spec/', '/src/', ''), ':h')
|
||||||
return parent . '/' . matchstr(base, '.\+\ze_spec$') . '.cr'
|
return parent . '/' . matchstr(base, '.\+\ze_spec$') . '.cr'
|
||||||
else
|
else
|
||||||
let parent = fnamemodify(substitute(a:absolute_path, '/src/', '/spec/', ''), ':h')
|
let parent = fnamemodify(substitute(a:absolute_path, '/src/', '/spec/', ''), ':h')
|
||||||
return parent . '/' . base . '_spec.cr'
|
return parent . '/' . base . '_spec.cr'
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#switch_spec_file(...) abort
|
function! crystal_lang#switch_spec_file(...) abort
|
||||||
let path = a:0 == 0 ? expand('%:p') : fnamemodify(a:1, ':p')
|
let path = a:0 == 0 ? expand('%:p') : fnamemodify(a:1, ':p')
|
||||||
if path !~# '.cr$'
|
if path !~# '.cr$'
|
||||||
return s:echo_error('Not crystal source file: ' . path)
|
return s:echo_error('Not crystal source file: ' . path)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
execute 'edit!' crystal_lang#get_spec_switched_path(path)
|
execute 'edit!' crystal_lang#get_spec_switched_path(path)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:run_spec(root, path, ...) abort
|
function! s:run_spec(root, path, ...) abort
|
||||||
" Note:
|
" Note:
|
||||||
" `crystal spec` can't understand absolute path.
|
" `crystal spec` can't understand absolute path.
|
||||||
let cmd = printf(
|
let cmd = printf(
|
||||||
\ '%s spec %s%s',
|
\ '%s spec %s%s',
|
||||||
\ g:crystal_compiler_command,
|
\ g:crystal_compiler_command,
|
||||||
\ a:path,
|
\ a:path,
|
||||||
\ a:0 == 0 ? '' : (':' . a:1)
|
\ a:0 == 0 ? '' : (':' . a:1)
|
||||||
\ )
|
\ )
|
||||||
|
|
||||||
let saved_cwd = getcwd()
|
let saved_cwd = getcwd()
|
||||||
let cd = haslocaldir() ? 'lcd' : 'cd'
|
let cd = haslocaldir() ? 'lcd' : 'cd'
|
||||||
try
|
try
|
||||||
execute cd a:root
|
execute cd a:root
|
||||||
call s:C.echo(s:run_cmd(cmd))
|
call s:C.echo(s:run_cmd(cmd))
|
||||||
finally
|
finally
|
||||||
execute cd saved_cwd
|
execute cd saved_cwd
|
||||||
endtry
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#run_all_spec(...) abort
|
function! crystal_lang#run_all_spec(...) abort
|
||||||
let path = a:0 == 0 ? expand('%:p:h') : a:1
|
let path = a:0 == 0 ? expand('%:p:h') : a:1
|
||||||
let root_path = s:find_root_by_spec_and_src(path)
|
let root_path = s:find_root_by_spec_and_src(path)
|
||||||
if root_path ==# ''
|
if root_path ==# ''
|
||||||
return s:echo_error("'spec' directory is not found")
|
return s:echo_error("'spec' directory is not found")
|
||||||
endif
|
endif
|
||||||
call s:run_spec(root_path, 'spec')
|
call s:run_spec(root_path, 'spec')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#run_current_spec(...) abort
|
function! crystal_lang#run_current_spec(...) abort
|
||||||
" /foo/bar/src/poyo.cr
|
" /foo/bar/src/poyo.cr
|
||||||
let path = a:0 == 0 ? expand('%:p') : fnamemodify(a:1, ':p')
|
let path = a:0 == 0 ? expand('%:p') : fnamemodify(a:1, ':p')
|
||||||
if path !~# '.cr$'
|
if path !~# '.cr$'
|
||||||
return s:echo_error('Not crystal source file: ' . path)
|
return s:echo_error('Not crystal source file: ' . path)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" /foo/bar/src
|
" /foo/bar/src
|
||||||
let source_dir = fnamemodify(path, ':h')
|
let source_dir = fnamemodify(path, ':h')
|
||||||
|
|
||||||
" /foo/bar
|
" /foo/bar
|
||||||
let root_dir = s:find_root_by_spec_and_src(source_dir)
|
let root_dir = s:find_root_by_spec_and_src(source_dir)
|
||||||
if root_dir ==# ''
|
if root_dir ==# ''
|
||||||
return s:echo_error("Root directory with 'src/' and 'spec/' not found")
|
return s:echo_error("Root directory with 'src/' and 'spec/' not found")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" src
|
" src
|
||||||
let rel_path = source_dir[strlen(root_dir)+1 : ]
|
let rel_path = source_dir[strlen(root_dir)+1 : ]
|
||||||
|
|
||||||
if path =~# '_spec.cr$'
|
if path =~# '_spec.cr$'
|
||||||
call s:run_spec(root_dir, path[strlen(root_dir)+1 : ], line('.'))
|
call s:run_spec(root_dir, path[strlen(root_dir)+1 : ], line('.'))
|
||||||
else
|
else
|
||||||
let spec_path = substitute(rel_path, '^src', 'spec', '') . '/' . fnamemodify(path, ':t:r') . '_spec.cr'
|
let spec_path = substitute(rel_path, '^src', 'spec', '') . '/' . fnamemodify(path, ':t:r') . '_spec.cr'
|
||||||
if !filereadable(root_dir . '/' . spec_path)
|
if !filereadable(root_dir . '/' . spec_path)
|
||||||
return s:echo_error('Error: Could not find a spec source corresponding to ' . path)
|
return s:echo_error('Error: Could not find a spec source corresponding to ' . path)
|
||||||
endif
|
|
||||||
call s:run_spec(root_dir, spec_path)
|
|
||||||
endif
|
endif
|
||||||
|
call s:run_spec(root_dir, spec_path)
|
||||||
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#format_string(code, ...) abort
|
function! crystal_lang#format_string(code, ...) abort
|
||||||
let cmd = printf(
|
if s:IS_WINDOWS
|
||||||
\ '%s tool format --no-color %s -',
|
let redirect = '2> nul'
|
||||||
\ g:crystal_compiler_command,
|
else
|
||||||
\ get(a:, 1, '')
|
let redirect = '2>/dev/null'
|
||||||
\ )
|
endif
|
||||||
let output = s:P.system(cmd, a:code)
|
let cmd = printf(
|
||||||
if s:P.get_last_status()
|
\ '%s tool format --no-color %s - %s',
|
||||||
throw 'vim-crystal: Error on formatting: ' . output
|
\ g:crystal_compiler_command,
|
||||||
endif
|
\ get(a:, 1, ''),
|
||||||
return output
|
\ redirect,
|
||||||
|
\ )
|
||||||
|
let output = s:P.system(cmd, a:code)
|
||||||
|
if s:P.get_last_status()
|
||||||
|
throw 'vim-crystal: Error on formatting with command: ' . cmd
|
||||||
|
endif
|
||||||
|
return output
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" crystal_lang#format(option_str [, on_save])
|
" crystal_lang#format(option_str [, on_save])
|
||||||
function! crystal_lang#format(option_str, ...) abort
|
function! crystal_lang#format(option_str, ...) abort
|
||||||
if !executable(g:crystal_compiler_command)
|
let on_save = a:0 > 0 ? a:1 : 0
|
||||||
" Finish command silently
|
|
||||||
return
|
if !executable(g:crystal_compiler_command)
|
||||||
|
if on_save
|
||||||
|
" Finish command silently on save
|
||||||
|
return
|
||||||
|
else
|
||||||
|
throw 'vim-crystal: Command for formatting is not executable: ' . g:crystal_compiler_command
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
let on_save = a:0 > 0 ? a:1 : 0
|
let before = join(getline(1, '$'), "\n")
|
||||||
|
try
|
||||||
let before = join(getline(1, '$'), "\n")
|
|
||||||
let formatted = crystal_lang#format_string(before, a:option_str)
|
let formatted = crystal_lang#format_string(before, a:option_str)
|
||||||
if !on_save
|
catch /^vim-crystal: /
|
||||||
let after = substitute(formatted, '\n$', '', '')
|
echohl ErrorMsg
|
||||||
if before ==# after
|
echomsg v:exception . ': Your code was not formatted. Exception was thrown at ' . v:throwpoint
|
||||||
return
|
echohl None
|
||||||
endif
|
return
|
||||||
endif
|
endtry
|
||||||
|
|
||||||
let view_save = winsaveview()
|
if !on_save
|
||||||
let pos_save = getpos('.')
|
let after = substitute(formatted, '\n$', '', '')
|
||||||
let lines = split(formatted, '\n')
|
if before ==# after
|
||||||
silent! undojoin
|
return
|
||||||
if line('$') > len(lines)
|
|
||||||
execute len(lines) . ',$delete' '_'
|
|
||||||
endif
|
endif
|
||||||
call setline(1, lines)
|
endif
|
||||||
call winrestview(view_save)
|
|
||||||
call setpos('.', pos_save)
|
let view_save = winsaveview()
|
||||||
|
let pos_save = getpos('.')
|
||||||
|
let lines = split(formatted, '\n')
|
||||||
|
silent! undojoin
|
||||||
|
if line('$') > len(lines)
|
||||||
|
execute len(lines) . ',$delete' '_'
|
||||||
|
endif
|
||||||
|
call setline(1, lines)
|
||||||
|
call winrestview(view_save)
|
||||||
|
call setpos('.', pos_save)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! crystal_lang#expand(file, pos, ...) abort
|
function! crystal_lang#expand(file, pos, ...) abort
|
||||||
return crystal_lang#tool('expand', a:file, a:pos, get(a:, 1, ''))
|
return crystal_lang#tool('expand', a:file, a:pos, get(a:, 1, ''))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
let &cpo = s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
|
||||||
|
" vim: sw=2 sts=2 et:
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ fu! csv#Init(start, end, ...) "{{{3
|
|||||||
else
|
else
|
||||||
let b:csv_cmt = split(g:csv_comment, '%s')
|
let b:csv_cmt = split(g:csv_comment, '%s')
|
||||||
endif
|
endif
|
||||||
|
" Make sure it is a list with 2 chars
|
||||||
|
if b:csv_cmt == []
|
||||||
|
let b:csv_cmt = ["", ""]
|
||||||
|
endif
|
||||||
|
|
||||||
if empty(b:delimiter) && !exists("b:csv_fixed_width")
|
if empty(b:delimiter) && !exists("b:csv_fixed_width")
|
||||||
call csv#Warn("No delimiter found. See :h csv-delimiter to set it manually!")
|
call csv#Warn("No delimiter found. See :h csv-delimiter to set it manually!")
|
||||||
@@ -122,7 +126,7 @@ fu! csv#Init(start, end, ...) "{{{3
|
|||||||
" Enable vartabs for tab delimited files
|
" Enable vartabs for tab delimited files
|
||||||
if b:delimiter=="\t" && has("vartabs")&& !exists("b:csv_fixed_width_cols")
|
if b:delimiter=="\t" && has("vartabs")&& !exists("b:csv_fixed_width_cols")
|
||||||
if get(b:, 'col_width', []) ==# []
|
if get(b:, 'col_width', []) ==# []
|
||||||
call csv#CalculateColumnWidth('')
|
call csv#CalculateColumnWidth(line('$'), 1)
|
||||||
endif
|
endif
|
||||||
let &l:vts=join(b:col_width, ',')
|
let &l:vts=join(b:col_width, ',')
|
||||||
let g:csv_no_conceal=1
|
let g:csv_no_conceal=1
|
||||||
@@ -574,7 +578,7 @@ fu! csv#MaxColumns(...) "{{{3
|
|||||||
return len(b:csv_fixed_width_cols)
|
return len(b:csv_fixed_width_cols)
|
||||||
endif
|
endif
|
||||||
endfu
|
endfu
|
||||||
fu! csv#ColWidth(colnr, ...) "{{{3
|
fu! csv#ColWidth(colnr, row, silent) "{{{3
|
||||||
" if a:1 is given, specifies the row, for which to calculate the width
|
" if a:1 is given, specifies the row, for which to calculate the width
|
||||||
"
|
"
|
||||||
" Return the width of a column
|
" Return the width of a column
|
||||||
@@ -586,14 +590,13 @@ fu! csv#ColWidth(colnr, ...) "{{{3
|
|||||||
if !exists("b:csv_fixed_width_cols")
|
if !exists("b:csv_fixed_width_cols")
|
||||||
if !exists("b:csv_list")
|
if !exists("b:csv_list")
|
||||||
" only check first 10000 lines, to be faster
|
" only check first 10000 lines, to be faster
|
||||||
let last = line('$')
|
let last = a:row
|
||||||
if exists("a:1") && !empty(a:1)
|
|
||||||
let last = a:1
|
|
||||||
endif
|
|
||||||
if !get(b:, 'csv_arrange_use_all_rows', 0)
|
if !get(b:, 'csv_arrange_use_all_rows', 0)
|
||||||
if last > 10000
|
if last > 10000
|
||||||
let last = 10000
|
let last = 10000
|
||||||
call csv#Warn('File too large, only checking the first 10000 rows for the width')
|
if !a:silent
|
||||||
|
call csv#Warn('File too large, only checking the first 10000 rows for the width')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
let b:csv_list=getline(skipfirst+1,last)
|
let b:csv_list=getline(skipfirst+1,last)
|
||||||
@@ -636,8 +639,12 @@ fu! csv#ArrangeCol(first, last, bang, limit, ...) range "{{{3
|
|||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
let cur=winsaveview()
|
let cur=winsaveview()
|
||||||
|
" be sure, that b:col_width is actually valid
|
||||||
|
if exists("b:col_width") && eval(join(b:col_width, '+')) == 0
|
||||||
|
unlet! b:col_width
|
||||||
|
endif
|
||||||
" Force recalculation of Column width
|
" Force recalculation of Column width
|
||||||
let row = exists("a:1") ? a:1 : ''
|
let row = exists("a:1") && !empty(a:1) ? a:1 : line('$')
|
||||||
if a:bang || !empty(row)
|
if a:bang || !empty(row)
|
||||||
if a:bang && exists("b:col_width")
|
if a:bang && exists("b:col_width")
|
||||||
" Unarrange, so that if csv_arrange_align has changed
|
" Unarrange, so that if csv_arrange_align has changed
|
||||||
@@ -671,7 +678,7 @@ fu! csv#ArrangeCol(first, last, bang, limit, ...) range "{{{3
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
if !exists("b:col_width")
|
if !exists("b:col_width")
|
||||||
call csv#CalculateColumnWidth(row)
|
call csv#CalculateColumnWidth(row, 1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" abort on empty file
|
" abort on empty file
|
||||||
@@ -750,7 +757,7 @@ fu! csv#UnArrangeCol(match) "{{{3
|
|||||||
" Strip leading white space, also trims empty recordcsv#
|
" Strip leading white space, also trims empty recordcsv#
|
||||||
return substitute(a:match, '\%(^ \+\)\|\%( \+\ze'.b:delimiter. '\?$\)', '', 'g')
|
return substitute(a:match, '\%(^ \+\)\|\%( \+\ze'.b:delimiter. '\?$\)', '', 'g')
|
||||||
endfu
|
endfu
|
||||||
fu! csv#CalculateColumnWidth(row) "{{{3
|
fu! csv#CalculateColumnWidth(row, silent) "{{{3
|
||||||
" Internal function, not called from external,
|
" Internal function, not called from external,
|
||||||
" does not work with fixed width columns
|
" does not work with fixed width columns
|
||||||
" row for the row for which to calculate the width
|
" row for the row for which to calculate the width
|
||||||
@@ -763,7 +770,7 @@ fu! csv#CalculateColumnWidth(row) "{{{3
|
|||||||
endif
|
endif
|
||||||
let s:max_cols=csv#MaxColumns(line('.'))
|
let s:max_cols=csv#MaxColumns(line('.'))
|
||||||
for i in range(1,s:max_cols)
|
for i in range(1,s:max_cols)
|
||||||
call add(b:col_width, csv#ColWidth(i, a:row))
|
call add(b:col_width, csv#ColWidth(i, a:row, a:silent))
|
||||||
endfor
|
endfor
|
||||||
catch /csv:no_col/
|
catch /csv:no_col/
|
||||||
call csv#Warn("Error: getting Column numbers, aborting!")
|
call csv#Warn("Error: getting Column numbers, aborting!")
|
||||||
@@ -1053,7 +1060,7 @@ fu! csv#MoveCol(forward, line, ...) "{{{3
|
|||||||
let maxcol=csv#MaxColumns(line('.'))
|
let maxcol=csv#MaxColumns(line('.'))
|
||||||
let cpos=getpos('.')[2]
|
let cpos=getpos('.')[2]
|
||||||
if !exists("b:csv_fixed_width_cols")
|
if !exists("b:csv_fixed_width_cols")
|
||||||
let curwidth=CSVWidth()
|
let curwidth=CSVWidth(1)
|
||||||
call search(b:col, 'bc', line('.'))
|
call search(b:col, 'bc', line('.'))
|
||||||
endif
|
endif
|
||||||
let spos=getpos('.')[2]
|
let spos=getpos('.')[2]
|
||||||
@@ -1146,7 +1153,7 @@ fu! csv#MoveCol(forward, line, ...) "{{{3
|
|||||||
" leave the column (if the next column is shorter)
|
" leave the column (if the next column is shorter)
|
||||||
if !exists("b:csv_fixed_width_cols")
|
if !exists("b:csv_fixed_width_cols")
|
||||||
let a = getpos('.')
|
let a = getpos('.')
|
||||||
if CSVWidth() == curwidth
|
if CSVWidth(1) == curwidth
|
||||||
let a[2]+= cpos-spos
|
let a[2]+= cpos-spos
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
@@ -1159,7 +1166,7 @@ fu! csv#MoveCol(forward, line, ...) "{{{3
|
|||||||
" Move to the correct screen column
|
" Move to the correct screen column
|
||||||
if !exists("b:csv_fixed_width_cols")
|
if !exists("b:csv_fixed_width_cols")
|
||||||
let a = getpos('.')
|
let a = getpos('.')
|
||||||
if CSVWidth() == curwidth
|
if CSVWidth(1) == curwidth
|
||||||
let a[2]+= cpos-spos
|
let a[2]+= cpos-spos
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
@@ -1835,7 +1842,7 @@ fu! csv#ProcessFieldValue(field) "{{{3
|
|||||||
|
|
||||||
if a == b:delimiter
|
if a == b:delimiter
|
||||||
try
|
try
|
||||||
let a=repeat(' ', csv#ColWidth(col))
|
let a=repeat(' ', csv#ColWidth(col, line('$'), 1))
|
||||||
catch
|
catch
|
||||||
" no-op
|
" no-op
|
||||||
endtry
|
endtry
|
||||||
@@ -2134,7 +2141,7 @@ fu! csv#NewRecord(line1, line2, count) "{{{3
|
|||||||
if !exists("b:col_width")
|
if !exists("b:col_width")
|
||||||
" Best guess width
|
" Best guess width
|
||||||
if exists("b:csv_fixed_width_cols")
|
if exists("b:csv_fixed_width_cols")
|
||||||
let record .= printf("%*s", csv#ColWidth(item),
|
let record .= printf("%*s", csv#ColWidth(item, line('$'), 1),
|
||||||
\ b:delimiter)
|
\ b:delimiter)
|
||||||
else
|
else
|
||||||
let record .= printf("%20s", b:delimiter)
|
let record .= printf("%20s", b:delimiter)
|
||||||
@@ -3145,7 +3152,9 @@ fu! CSVCount(col, fmt, first, last, ...) "{{{3
|
|||||||
unlet! s:additional['distinct']
|
unlet! s:additional['distinct']
|
||||||
return (empty(result) ? 0 : result)
|
return (empty(result) ? 0 : result)
|
||||||
endfu
|
endfu
|
||||||
fu! CSVWidth() "{{{3
|
fu! CSVWidth(...) "{{{3
|
||||||
|
" do not output any warning
|
||||||
|
let silent = get(a:000, 0, 1)
|
||||||
" does not work with fixed width columns
|
" does not work with fixed width columns
|
||||||
if exists("b:csv_fixed_width_cols")
|
if exists("b:csv_fixed_width_cols")
|
||||||
let c = getline(1,'$')
|
let c = getline(1,'$')
|
||||||
@@ -3164,7 +3173,7 @@ fu! CSVWidth() "{{{3
|
|||||||
" Add width for last column
|
" Add width for last column
|
||||||
call add(width, max-y+1)
|
call add(width, max-y+1)
|
||||||
else
|
else
|
||||||
call csv#CalculateColumnWidth('')
|
call csv#CalculateColumnWidth(line('$'), silent)
|
||||||
let width=map(copy(b:col_width), 'v:val-1')
|
let width=map(copy(b:col_width), 'v:val-1')
|
||||||
endif
|
endif
|
||||||
return width
|
return width
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ endfunction
|
|||||||
" If the path cannot be resolved, or is not a package: uri, returns the
|
" If the path cannot be resolved, or is not a package: uri, returns the
|
||||||
" original.
|
" original.
|
||||||
function! dart#resolveUri(uri) abort
|
function! dart#resolveUri(uri) abort
|
||||||
if a:uri !~ 'package:'
|
if a:uri !~# 'package:'
|
||||||
return a:uri
|
return a:uri
|
||||||
endif
|
endif
|
||||||
let package_name = substitute(a:uri, 'package:\(\w\+\)\/.*', '\1', '')
|
let package_name = substitute(a:uri, 'package:\(\w\+\)\/.*', '\1', '')
|
||||||
@@ -118,20 +118,20 @@ function! s:PackageMap() abort
|
|||||||
let lines = readfile(dot_packages)
|
let lines = readfile(dot_packages)
|
||||||
let map = {}
|
let map = {}
|
||||||
for line in lines
|
for line in lines
|
||||||
if line =~ '\s*#'
|
if line =~# '\s*#'
|
||||||
continue
|
continue
|
||||||
endif
|
endif
|
||||||
let package = substitute(line, ':.*$', '', '')
|
let package = substitute(line, ':.*$', '', '')
|
||||||
let lib_dir = substitute(line, '^[^:]*:', '', '')
|
let lib_dir = substitute(line, '^[^:]*:', '', '')
|
||||||
if lib_dir =~ 'file:/'
|
if lib_dir =~# 'file:/'
|
||||||
let lib_dir = substitute(lib_dir, 'file://', '', '')
|
let lib_dir = substitute(lib_dir, 'file://', '', '')
|
||||||
if lib_dir =~ '/[A-Z]:/'
|
if lib_dir =~# '/[A-Z]:/'
|
||||||
let lib_dir = lib_dir[1:]
|
let lib_dir = lib_dir[1:]
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
let lib_dir = resolve(dot_packages_dir.'/'.lib_dir)
|
let lib_dir = resolve(dot_packages_dir.'/'.lib_dir)
|
||||||
endif
|
endif
|
||||||
if lib_dir =~ '/$'
|
if lib_dir =~# '/$'
|
||||||
let lib_dir = lib_dir[:len(lib_dir) - 2]
|
let lib_dir = lib_dir[:len(lib_dir) - 2]
|
||||||
endif
|
endif
|
||||||
let map[package] = lib_dir
|
let map[package] = lib_dir
|
||||||
@@ -141,7 +141,7 @@ endfunction
|
|||||||
|
|
||||||
" Toggle whether dartfmt is run on save or not.
|
" Toggle whether dartfmt is run on save or not.
|
||||||
function! dart#ToggleFormatOnSave() abort
|
function! dart#ToggleFormatOnSave() abort
|
||||||
if get(g:, "dart_format_on_save", 0)
|
if get(g:, 'dart_format_on_save', 0)
|
||||||
let g:dart_format_on_save = 0
|
let g:dart_format_on_save = 0
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|||||||
36
autoload/ecrystal.vim
Normal file
36
autoload/ecrystal.vim
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'crystal') == -1
|
||||||
|
|
||||||
|
let s:ecrystal_extensions = {
|
||||||
|
\ 'cr': 'crystal',
|
||||||
|
\ 'yml': 'yaml',
|
||||||
|
\ 'js': 'javascript',
|
||||||
|
\ 'txt': 'text',
|
||||||
|
\ 'md': 'markdown'
|
||||||
|
\ }
|
||||||
|
|
||||||
|
if exists('g:ecrystal_extensions')
|
||||||
|
call extend(s:ecrystal_extensions, g:ecrystal_extensions, 'force')
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! ecrystal#SetSubtype() abort
|
||||||
|
if exists('b:ecrystal_subtype')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let b:ecrystal_subtype = matchstr(substitute(expand('%:t'), '\c\%(\.ecr\)\+$', '', ''), '\.\zs\w\+\%(\ze+\w\+\)\=$')
|
||||||
|
|
||||||
|
let b:ecrystal_subtype = get(s:ecrystal_extensions, b:ecrystal_subtype, b:ecrystal_subtype)
|
||||||
|
|
||||||
|
if b:ecrystal_subtype ==# ''
|
||||||
|
let b:ecrystal_subtype = get(g:, 'ecrystal_default_subtype', 'html')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if b:ecrystal_subtype !=# ''
|
||||||
|
exec 'setlocal filetype=ecrystal.' . b:ecrystal_subtype
|
||||||
|
exec 'setlocal syntax=ecrystal.' . b:ecrystal_subtype
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" vim: sw=2 sts=2 et:
|
||||||
|
|
||||||
|
endif
|
||||||
385
autoload/elm.vim
385
autoload/elm.vim
@@ -1,385 +0,0 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1
|
|
||||||
|
|
||||||
let s:errors = []
|
|
||||||
|
|
||||||
function! s:elmOracle(...) abort
|
|
||||||
let l:project = finddir('elm-stuff/..', '.;')
|
|
||||||
if len(l:project) == 0
|
|
||||||
echoerr '`elm-stuff` not found! run `elm-package install` for autocomplete.'
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:filename = expand('%:p')
|
|
||||||
|
|
||||||
if a:0 == 0
|
|
||||||
let l:oldiskeyword = &iskeyword
|
|
||||||
" Some non obvious values used in 'iskeyword':
|
|
||||||
" @ = all alpha
|
|
||||||
" 48-57 = numbers 0 to 9
|
|
||||||
" @-@ = character @
|
|
||||||
" 124 = |
|
|
||||||
setlocal iskeyword=@,48-57,@-@,_,-,~,!,#,$,%,&,*,+,=,<,>,/,?,.,\\,124,^
|
|
||||||
let l:word = expand('<cword>')
|
|
||||||
let &iskeyword = l:oldiskeyword
|
|
||||||
else
|
|
||||||
let l:word = a:1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:infos = elm#Oracle(l:filename, l:word)
|
|
||||||
if v:shell_error != 0
|
|
||||||
call elm#util#EchoError("elm-oracle failed:\n\n", l:infos)
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:d = split(l:infos, '\n')
|
|
||||||
if len(l:d) > 0
|
|
||||||
return elm#util#DecodeJSON(l:d[0])
|
|
||||||
endif
|
|
||||||
|
|
||||||
return []
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Vim command to format Elm files with elm-format
|
|
||||||
function! elm#Format() abort
|
|
||||||
" check for elm-format
|
|
||||||
if elm#util#CheckBin('elm-format', 'https://github.com/avh4/elm-format') ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
" save cursor position, folds and many other things
|
|
||||||
let l:curw = {}
|
|
||||||
try
|
|
||||||
mkview!
|
|
||||||
catch
|
|
||||||
let l:curw = winsaveview()
|
|
||||||
endtry
|
|
||||||
|
|
||||||
" save our undo file to be restored after we are done.
|
|
||||||
let l:tmpundofile = tempname()
|
|
||||||
exe 'wundo! ' . l:tmpundofile
|
|
||||||
|
|
||||||
" write current unsaved buffer to a temporary file
|
|
||||||
let l:tmpname = tempname() . '.elm'
|
|
||||||
call writefile(getline(1, '$'), l:tmpname)
|
|
||||||
|
|
||||||
" call elm-format on the temporary file
|
|
||||||
let l:out = system('elm-format ' . l:tmpname . ' --output ' . l:tmpname)
|
|
||||||
|
|
||||||
" if there is no error
|
|
||||||
if v:shell_error == 0
|
|
||||||
try | silent undojoin | catch | endtry
|
|
||||||
|
|
||||||
" replace current file with temp file, then reload buffer
|
|
||||||
let l:old_fileformat = &fileformat
|
|
||||||
call rename(l:tmpname, expand('%'))
|
|
||||||
silent edit!
|
|
||||||
let &fileformat = l:old_fileformat
|
|
||||||
let &syntax = &syntax
|
|
||||||
elseif g:elm_format_fail_silently == 0
|
|
||||||
call elm#util#EchoLater('EchoError', 'elm-format:', l:out)
|
|
||||||
endif
|
|
||||||
|
|
||||||
" save our undo history
|
|
||||||
silent! exe 'rundo ' . l:tmpundofile
|
|
||||||
call delete(l:tmpundofile)
|
|
||||||
|
|
||||||
" restore our cursor/windows positions, folds, etc..
|
|
||||||
if empty(l:curw)
|
|
||||||
silent! loadview
|
|
||||||
else
|
|
||||||
call winrestview(l:curw)
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Query elm-oracle and echo the type and docs for the word under the cursor.
|
|
||||||
function! elm#ShowDocs() abort
|
|
||||||
" check for the elm-oracle binary
|
|
||||||
if elm#util#CheckBin('elm-oracle', 'https://github.com/elmcast/elm-oracle') ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:response = s:elmOracle()
|
|
||||||
|
|
||||||
if len(l:response) > 0
|
|
||||||
let l:info = l:response[0]
|
|
||||||
redraws! | echohl Identifier | echon l:info.fullName | echohl None | echon ' : ' | echohl Function | echon l:info.signature | echohl None | echon "\n\n" . l:info.comment
|
|
||||||
else
|
|
||||||
call elm#util#Echo('elm-oracle:', '...no match found')
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Query elm-oracle and open the docs for the word under the cursor.
|
|
||||||
function! elm#BrowseDocs() abort
|
|
||||||
" check for the elm-oracle binary
|
|
||||||
if elm#util#CheckBin('elm-oracle', 'https://github.com/elmcast/elm-oracle') ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:response = s:elmOracle()
|
|
||||||
|
|
||||||
if len(l:response) > 0
|
|
||||||
let l:info = l:response[0]
|
|
||||||
call elm#util#OpenBrowser(l:info.href)
|
|
||||||
else
|
|
||||||
call elm#util#Echo('elm-oracle:', '...no match found')
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
|
|
||||||
function! elm#Syntastic(input) abort
|
|
||||||
let l:fixes = []
|
|
||||||
|
|
||||||
let l:bin = 'elm-make'
|
|
||||||
let l:format = '--report=json'
|
|
||||||
let l:input = shellescape(a:input)
|
|
||||||
let l:output = '--output=' . shellescape(syntastic#util#DevNull())
|
|
||||||
let l:command = l:bin . ' ' . l:format . ' ' . l:input . ' ' . l:output
|
|
||||||
let l:reports = s:ExecuteInRoot(l:command)
|
|
||||||
|
|
||||||
for l:report in split(l:reports, '\n')
|
|
||||||
if l:report[0] ==# '['
|
|
||||||
for l:error in elm#util#DecodeJSON(l:report)
|
|
||||||
if g:elm_syntastic_show_warnings == 0 && l:error.type ==? 'warning'
|
|
||||||
else
|
|
||||||
if a:input == l:error.file
|
|
||||||
call add(s:errors, l:error)
|
|
||||||
call add(l:fixes, {'filename': l:error.file,
|
|
||||||
\'valid': 1,
|
|
||||||
\'bufnr': bufnr('%'),
|
|
||||||
\'type': (l:error.type ==? 'error') ? 'E' : 'W',
|
|
||||||
\'lnum': l:error.region.start.line,
|
|
||||||
\'col': l:error.region.start.column,
|
|
||||||
\'text': l:error.overview})
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return l:fixes
|
|
||||||
endf
|
|
||||||
|
|
||||||
function! elm#Build(input, output, show_warnings) abort
|
|
||||||
let s:errors = []
|
|
||||||
let l:fixes = []
|
|
||||||
let l:rawlines = []
|
|
||||||
|
|
||||||
let l:bin = 'elm-make'
|
|
||||||
let l:format = '--report=json'
|
|
||||||
let l:input = shellescape(a:input)
|
|
||||||
let l:output = '--output=' . shellescape(a:output)
|
|
||||||
let l:command = l:bin . ' ' . l:format . ' ' . l:input . ' ' . l:output
|
|
||||||
let l:reports = s:ExecuteInRoot(l:command)
|
|
||||||
|
|
||||||
for l:report in split(l:reports, '\n')
|
|
||||||
if l:report[0] ==# '['
|
|
||||||
for l:error in elm#util#DecodeJSON(l:report)
|
|
||||||
if a:show_warnings == 0 && l:error.type ==? 'warning'
|
|
||||||
else
|
|
||||||
call add(s:errors, l:error)
|
|
||||||
call add(l:fixes, {'filename': l:error.file,
|
|
||||||
\'valid': 1,
|
|
||||||
\'type': (l:error.type ==? 'error') ? 'E' : 'W',
|
|
||||||
\'lnum': l:error.region.start.line,
|
|
||||||
\'col': l:error.region.start.column,
|
|
||||||
\'text': l:error.overview})
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
call add(l:rawlines, l:report)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
let l:details = join(l:rawlines, "\n")
|
|
||||||
let l:lines = split(l:details, "\n")
|
|
||||||
if !empty(l:lines)
|
|
||||||
let l:overview = l:lines[0]
|
|
||||||
else
|
|
||||||
let l:overview = ''
|
|
||||||
endif
|
|
||||||
|
|
||||||
if l:details ==# '' || l:details =~? '^Successfully.*'
|
|
||||||
else
|
|
||||||
call add(s:errors, {'overview': l:details, 'details': l:details})
|
|
||||||
call add(l:fixes, {'filename': expand('%', 1),
|
|
||||||
\'valid': 1,
|
|
||||||
\'type': 'E',
|
|
||||||
\'lnum': 0,
|
|
||||||
\'col': 0,
|
|
||||||
\'text': l:overview})
|
|
||||||
endif
|
|
||||||
|
|
||||||
return l:fixes
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Make the given file, or the current file if none is given.
|
|
||||||
function! elm#Make(...) abort
|
|
||||||
if elm#util#CheckBin('elm-make', 'http://elm-lang.org/install') ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
call elm#util#Echo('elm-make:', 'building...')
|
|
||||||
|
|
||||||
let l:input = (a:0 == 0) ? expand('%:p') : a:1
|
|
||||||
let l:fixes = elm#Build(l:input, g:elm_make_output_file, g:elm_make_show_warnings)
|
|
||||||
|
|
||||||
if len(l:fixes) > 0
|
|
||||||
call elm#util#EchoWarning('', 'found ' . len(l:fixes) . ' errors')
|
|
||||||
|
|
||||||
call setqflist(l:fixes, 'r')
|
|
||||||
cwindow
|
|
||||||
|
|
||||||
if get(g:, 'elm_jump_to_error', 1)
|
|
||||||
ll 1
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call elm#util#EchoSuccess('', 'Sucessfully compiled')
|
|
||||||
|
|
||||||
call setqflist([])
|
|
||||||
cwindow
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Show the detail of the current error in the quickfix window.
|
|
||||||
function! elm#ErrorDetail() abort
|
|
||||||
if !empty(filter(tabpagebuflist(), 'getbufvar(v:val, "&buftype") ==? "quickfix"'))
|
|
||||||
exec ':copen'
|
|
||||||
let l:linenr = line('.')
|
|
||||||
exec ':wincmd p'
|
|
||||||
if len(s:errors) > 0
|
|
||||||
let l:detail = s:errors[l:linenr-1].details
|
|
||||||
if l:detail ==# ''
|
|
||||||
let l:detail = s:errors[l:linenr-1].overview
|
|
||||||
endif
|
|
||||||
echo l:detail
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Open the elm repl in a subprocess.
|
|
||||||
function! elm#Repl() abort
|
|
||||||
" check for the elm-repl binary
|
|
||||||
if elm#util#CheckBin('elm-repl', 'http://elm-lang.org/install') ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
if has('nvim')
|
|
||||||
term('elm-repl')
|
|
||||||
else
|
|
||||||
!elm-repl
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
function! elm#Oracle(filepath, word) abort
|
|
||||||
let l:bin = 'elm-oracle'
|
|
||||||
let l:filepath = shellescape(a:filepath)
|
|
||||||
let l:word = shellescape(a:word)
|
|
||||||
let l:command = l:bin . ' ' . l:filepath . ' ' . l:word
|
|
||||||
return s:ExecuteInRoot(l:command)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:fullComplete = ''
|
|
||||||
|
|
||||||
" Complete the current token using elm-oracle
|
|
||||||
function! elm#Complete(findstart, base) abort
|
|
||||||
" a:base is unused, but the callback function for completion expects 2 arguments
|
|
||||||
if a:findstart
|
|
||||||
let l:line = getline('.')
|
|
||||||
|
|
||||||
let l:idx = col('.') - 1
|
|
||||||
let l:start = 0
|
|
||||||
while l:idx > 0 && l:line[l:idx - 1] =~# '[a-zA-Z0-9_\.]'
|
|
||||||
if l:line[l:idx - 1] ==# '.' && l:start == 0
|
|
||||||
let l:start = l:idx
|
|
||||||
endif
|
|
||||||
let l:idx -= 1
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
if l:start == 0
|
|
||||||
let l:start = l:idx
|
|
||||||
endif
|
|
||||||
|
|
||||||
let s:fullComplete = l:line[l:idx : col('.')-2]
|
|
||||||
|
|
||||||
return l:start
|
|
||||||
else
|
|
||||||
" check for the elm-oracle binary
|
|
||||||
if elm#util#CheckBin('elm-oracle', 'https://github.com/elmcast/elm-oracle') ==# ''
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:res = []
|
|
||||||
let l:response = s:elmOracle(s:fullComplete)
|
|
||||||
|
|
||||||
let l:detailed = get(g:, 'elm_detailed_complete', 0)
|
|
||||||
|
|
||||||
for l:r in l:response
|
|
||||||
let l:menu = ''
|
|
||||||
if l:detailed
|
|
||||||
let l:menu = ': ' . l:r.signature
|
|
||||||
endif
|
|
||||||
call add(l:res, {'word': l:r.name, 'menu': l:menu})
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return l:res
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" If the current buffer contains a consoleRunner, run elm-test with it.
|
|
||||||
" Otherwise run elm-test in the root of your project which deafults to
|
|
||||||
" running 'elm-test tests/TestRunner'.
|
|
||||||
function! elm#Test() abort
|
|
||||||
if elm#util#CheckBin('elm-test', 'https://github.com/rtfeldman/node-elm-test') ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
if match(getline(1, '$'), 'consoleRunner') < 0
|
|
||||||
let l:out = s:ExecuteInRoot('elm-test')
|
|
||||||
call elm#util#EchoSuccess('elm-test', l:out)
|
|
||||||
else
|
|
||||||
let l:filepath = shellescape(expand('%:p'))
|
|
||||||
let l:out = s:ExecuteInRoot('elm-test ' . l:filepath)
|
|
||||||
call elm#util#EchoSuccess('elm-test', l:out)
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Returns the closest parent with an elm-package.json file.
|
|
||||||
function! elm#FindRootDirectory() abort
|
|
||||||
let l:elm_root = getbufvar('%', 'elmRoot')
|
|
||||||
if empty(l:elm_root)
|
|
||||||
let l:current_file = expand('%:p')
|
|
||||||
let l:dir_current_file = fnameescape(fnamemodify(l:current_file, ':h'))
|
|
||||||
let l:old_match = findfile('elm-package.json', l:dir_current_file . ';')
|
|
||||||
let l:new_match = findfile('elm.json', l:dir_current_file . ';')
|
|
||||||
if !empty(l:new_match)
|
|
||||||
let l:elm_root = fnamemodify(l:new_match, ':p:h')
|
|
||||||
elseif !empty(l:old_match)
|
|
||||||
let l:elm_root = fnamemodify(l:old_match, ':p:h')
|
|
||||||
else
|
|
||||||
let l:elm_root = ''
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !empty(l:elm_root)
|
|
||||||
call setbufvar('%', 'elmRoot', l:elm_root)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return l:elm_root
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Executes a command in the project directory.
|
|
||||||
function! s:ExecuteInRoot(cmd) abort
|
|
||||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
|
||||||
let l:current_dir = getcwd()
|
|
||||||
let l:root_dir = elm#FindRootDirectory()
|
|
||||||
|
|
||||||
try
|
|
||||||
execute l:cd . fnameescape(l:root_dir)
|
|
||||||
let l:out = system(a:cmd)
|
|
||||||
finally
|
|
||||||
execute l:cd . fnameescape(l:current_dir)
|
|
||||||
endtry
|
|
||||||
|
|
||||||
return l:out
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
endif
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1
|
|
||||||
|
|
||||||
" IsWin returns 1 if current OS is Windows or 0 otherwise
|
|
||||||
fun! elm#util#IsWin() abort
|
|
||||||
let l:win = ['win16', 'win32', 'win32unix', 'win64', 'win95']
|
|
||||||
for l:w in l:win
|
|
||||||
if (has(l:w))
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return 0
|
|
||||||
endf
|
|
||||||
|
|
||||||
fun! elm#util#CheckBin(bin, url) abort
|
|
||||||
let l:binpath = substitute(a:bin, '^\s*\(.\{-}\)\s*$', '\1', '')
|
|
||||||
|
|
||||||
if executable(l:binpath)
|
|
||||||
return l:binpath
|
|
||||||
endif
|
|
||||||
|
|
||||||
call elm#util#EchoWarning('elm-vim:', 'could not find ' . l:binpath . ' [' . a:url . ']')
|
|
||||||
|
|
||||||
return ''
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Determines the browser command to use
|
|
||||||
fun! s:get_browser_command() abort
|
|
||||||
let l:elm_browser_command = get(g:, 'elm_browser_command', '')
|
|
||||||
if l:elm_browser_command ==? ''
|
|
||||||
if elm#util#IsWin()
|
|
||||||
let l:elm_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
|
|
||||||
elseif has('mac') || has('macunix') || has('gui_macvim') || system('uname') =~? '^darwin'
|
|
||||||
let l:elm_browser_command = 'open %URL%'
|
|
||||||
elseif executable('xdg-open')
|
|
||||||
let l:elm_browser_command = 'xdg-open %URL%'
|
|
||||||
elseif executable('firefox')
|
|
||||||
let l:elm_browser_command = 'firefox %URL% &'
|
|
||||||
else
|
|
||||||
let l:elm_browser_command = ''
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return l:elm_browser_command
|
|
||||||
endf
|
|
||||||
|
|
||||||
" OpenBrowser opens a url in the default browser
|
|
||||||
fun! elm#util#OpenBrowser(url) abort
|
|
||||||
let l:cmd = s:get_browser_command()
|
|
||||||
if len(l:cmd) == 0
|
|
||||||
redraw
|
|
||||||
echohl WarningMsg
|
|
||||||
echo "It seems that you don't have general web browser. Open URL below."
|
|
||||||
echohl None
|
|
||||||
echo a:url
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if l:cmd =~? '^!'
|
|
||||||
let l:cmd = substitute(l:cmd, '%URL%', '\=shellescape(a:url)', 'g')
|
|
||||||
silent! exec l:cmd
|
|
||||||
elseif l:cmd =~# '^:[A-Z]'
|
|
||||||
let l:cmd = substitute(l:cmd, '%URL%', '\=a:url', 'g')
|
|
||||||
exec l:cmd
|
|
||||||
else
|
|
||||||
let l:cmd = substitute(l:cmd, '%URL%', '\=shellescape(a:url)', 'g')
|
|
||||||
call system(l:cmd)
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
" DecodeJSON decodes a string of json into a viml object
|
|
||||||
fun! elm#util#DecodeJSON(s) abort
|
|
||||||
let l:true = 1
|
|
||||||
let l:false = 0
|
|
||||||
let l:null = 0
|
|
||||||
return eval(a:s)
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Remove ANSI escape characters used for highlighting purposes
|
|
||||||
fun! s:strip_color(msg) abort
|
|
||||||
return substitute(a:msg, '\e\[[0-9;]\+[mK]', '', 'g')
|
|
||||||
endf
|
|
||||||
|
|
||||||
" Print functions
|
|
||||||
fun! elm#util#Echo(title, msg) abort
|
|
||||||
redraws! | echon a:title . ' ' | echohl Identifier | echon s:strip_color(a:msg) | echohl None
|
|
||||||
endf
|
|
||||||
|
|
||||||
fun! elm#util#EchoSuccess(title, msg) abort
|
|
||||||
redraws! | echon a:title . ' ' | echohl Function | echon s:strip_color(a:msg) | echohl None
|
|
||||||
endf
|
|
||||||
|
|
||||||
fun! elm#util#EchoWarning(title, msg) abort
|
|
||||||
redraws! | echon a:title . ' ' | echohl WarningMsg | echon s:strip_color(a:msg) | echohl None
|
|
||||||
endf
|
|
||||||
|
|
||||||
fun! elm#util#EchoError(title, msg) abort
|
|
||||||
redraws! | echon a:title . ' ' | echohl ErrorMsg | echon s:strip_color(a:msg) | echohl None
|
|
||||||
endf
|
|
||||||
|
|
||||||
fun! elm#util#EchoLater(func_name, title, msg) abort
|
|
||||||
let s:echo_func_name = a:func_name
|
|
||||||
let s:echo_title = a:title
|
|
||||||
let s:echo_msg = a:msg
|
|
||||||
endf
|
|
||||||
|
|
||||||
fun! elm#util#EchoStored() abort
|
|
||||||
if exists('s:echo_func_name') && exists('s:echo_title') && exists('s:echo_msg')
|
|
||||||
call elm#util#{s:echo_func_name}(s:echo_title, s:echo_msg)
|
|
||||||
unlet s:echo_func_name
|
|
||||||
unlet s:echo_title
|
|
||||||
unlet s:echo_msg
|
|
||||||
endif
|
|
||||||
endf
|
|
||||||
|
|
||||||
function! elm#util#GoToModule(name)
|
|
||||||
if empty(a:name) | return | endif
|
|
||||||
if empty(matchstr(a:name, '^Native\.'))
|
|
||||||
let l:extension = '.elm'
|
|
||||||
else
|
|
||||||
let l:extension = '.js'
|
|
||||||
endif
|
|
||||||
let l:rel_path = substitute(a:name, '\.', '/', 'g') . l:extension
|
|
||||||
let l:root = elm#FindRootDirectory()
|
|
||||||
|
|
||||||
let l:module_file = s:findLocalModule(l:rel_path, l:root)
|
|
||||||
if !filereadable(l:module_file)
|
|
||||||
let l:module_file = s:findDependencyModule(l:rel_path, l:root)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if filereadable(l:module_file)
|
|
||||||
exec 'edit ' . fnameescape(l:module_file)
|
|
||||||
else
|
|
||||||
return s:error("Can't find module \"" . a:name . "\"")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:findLocalModule(rel_path, root)
|
|
||||||
let l:old_match = findfile('elm-package.json', a:root . ';')
|
|
||||||
let l:new_match = findfile('elm.json', a:root . ';')
|
|
||||||
if !empty(l:new_match)
|
|
||||||
let l:package_json = l:new_match
|
|
||||||
elseif !empty(l:old_match)
|
|
||||||
let l:package_json = l:old_match
|
|
||||||
endif
|
|
||||||
if exists('*json_decode')
|
|
||||||
let l:package = json_decode(readfile(l:package_json))
|
|
||||||
let l:source_roots = l:package['source-directories']
|
|
||||||
else
|
|
||||||
" This is a fallback for vim's which do not support json_decode.
|
|
||||||
" It simply only looks in the 'src' subdirectory and fails otherwise.
|
|
||||||
let l:source_roots = ['src']
|
|
||||||
end
|
|
||||||
for l:source_root in l:source_roots
|
|
||||||
let l:file_path = a:root . '/' . l:source_root . '/' . a:rel_path
|
|
||||||
if !filereadable(l:file_path)
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
return l:file_path
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:findDependencyModule(rel_path, root)
|
|
||||||
" If we are a dependency ourselves, we need to check our siblings.
|
|
||||||
" This is because elm package doesn't install dependencies recursively.
|
|
||||||
let l:root = substitute(a:root, '\/elm-stuff/packages.\+$', '', '')
|
|
||||||
|
|
||||||
" We naively craws the dependencies dir for any fitting module name.
|
|
||||||
" If it exists, we'll find it. If multiple filenames match,
|
|
||||||
" there's a chance we return the wrong one.
|
|
||||||
let l:module_paths = glob(l:root . '/elm-stuff/packages/**/' . a:rel_path, 0, 1)
|
|
||||||
if len(l:module_paths) > 0
|
|
||||||
return l:module_paths[0]
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Using the built-in :echoerr prints a stacktrace, which isn't that nice.
|
|
||||||
" From: https://github.com/moll/vim-node/blob/master/autoload/node.vim
|
|
||||||
function! s:error(msg)
|
|
||||||
echohl ErrorMsg
|
|
||||||
echomsg a:msg
|
|
||||||
echohl NONE
|
|
||||||
let v:errmsg = a:msg
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
endif
|
|
||||||
@@ -54,7 +54,7 @@ function! fish#Complete(findstart, base)
|
|||||||
let l:completions =
|
let l:completions =
|
||||||
\ system('fish -c "complete -C'.shellescape(a:base).'"')
|
\ system('fish -c "complete -C'.shellescape(a:base).'"')
|
||||||
let l:cmd = substitute(a:base, '\v\S+$', '', '')
|
let l:cmd = substitute(a:base, '\v\S+$', '', '')
|
||||||
for l:line in split(l:completions, '\n')
|
for l:line in filter(split(l:completions, '\n'), 'len(v:val)')
|
||||||
let l:tokens = split(l:line, '\t')
|
let l:tokens = split(l:line, '\t')
|
||||||
call add(l:results, {'word': l:cmd.l:tokens[0],
|
call add(l:results, {'word': l:cmd.l:tokens[0],
|
||||||
\'abbr': l:tokens[0],
|
\'abbr': l:tokens[0],
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ function! go#config#SetTermCloseOnExit(value) abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#TermEnabled() abort
|
function! go#config#TermEnabled() abort
|
||||||
return has('nvim') && get(g:, 'go_term_enabled', 0)
|
" nvim always support
|
||||||
|
" vim will support if terminal feature exists
|
||||||
|
let l:support = has('nvim') || has('terminal')
|
||||||
|
return support && get(g:, 'go_term_enabled', 0)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#SetTermEnabled(value) abort
|
function! go#config#SetTermEnabled(value) abort
|
||||||
@@ -84,7 +87,18 @@ function! go#config#StatuslineDuration() abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#SnippetEngine() abort
|
function! go#config#SnippetEngine() abort
|
||||||
return get(g:, 'go_snippet_engine', 'automatic')
|
let l:engine = get(g:, 'go_snippet_engine', 'automatic')
|
||||||
|
if l:engine is? "automatic"
|
||||||
|
if get(g:, 'did_plugin_ultisnips') is 1
|
||||||
|
let l:engine = 'ultisnips'
|
||||||
|
elseif get(g:, 'loaded_neosnippet') is 1
|
||||||
|
let l:engine = 'neosnippet'
|
||||||
|
elseif get(g:, 'loaded_minisnip') is 1
|
||||||
|
let l:engine = 'minisnip'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:engine
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#PlayBrowserCommand() abort
|
function! go#config#PlayBrowserCommand() abort
|
||||||
@@ -151,23 +165,6 @@ function! go#config#SetGuruScope(scope) abort
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GocodeUnimportedPackages() abort
|
|
||||||
return get(g:, 'go_gocode_unimported_packages', 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix'
|
|
||||||
function! go#config#GocodeSocketType() abort
|
|
||||||
return get(g:, 'go_gocode_socket_type', s:sock_type)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#GocodeProposeBuiltins() abort
|
|
||||||
return get(g:, 'go_gocode_propose_builtins', 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#GocodeProposeSource() abort
|
|
||||||
return get(g:, 'go_gocode_propose_source', 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#EchoCommandInfo() abort
|
function! go#config#EchoCommandInfo() abort
|
||||||
return get(g:, 'go_echo_command_info', 1)
|
return get(g:, 'go_echo_command_info', 1)
|
||||||
endfunction
|
endfunction
|
||||||
@@ -252,6 +249,10 @@ function! go#config#AddtagsTransform() abort
|
|||||||
return get(g:, 'go_addtags_transform', "snakecase")
|
return get(g:, 'go_addtags_transform', "snakecase")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#AddtagsSkipUnexported() abort
|
||||||
|
return get(g:, 'go_addtags_skip_unexported', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#TemplateAutocreate() abort
|
function! go#config#TemplateAutocreate() abort
|
||||||
return get(g:, "go_template_autocreate", 1)
|
return get(g:, "go_template_autocreate", 1)
|
||||||
endfunction
|
endfunction
|
||||||
@@ -308,6 +309,10 @@ function! go#config#FmtAutosave() abort
|
|||||||
return get(g:, "go_fmt_autosave", 1)
|
return get(g:, "go_fmt_autosave", 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ImportsAutosave() abort
|
||||||
|
return get(g:, 'go_imports_autosave', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#SetFmtAutosave(value) abort
|
function! go#config#SetFmtAutosave(value) abort
|
||||||
let g:go_fmt_autosave = a:value
|
let g:go_fmt_autosave = a:value
|
||||||
endfunction
|
endfunction
|
||||||
@@ -352,8 +357,12 @@ function! go#config#FmtCommand() abort
|
|||||||
return get(g:, "go_fmt_command", "gofmt")
|
return get(g:, "go_fmt_command", "gofmt")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ImportsMode() abort
|
||||||
|
return get(g:, "go_imports_mode", "goimports")
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#FmtOptions() abort
|
function! go#config#FmtOptions() abort
|
||||||
return get(g:, "go_fmt_options", {})
|
return get(b:, "go_fmt_options", get(g:, "go_fmt_options", {}))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#FmtFailSilently() abort
|
function! go#config#FmtFailSilently() abort
|
||||||
@@ -368,9 +377,9 @@ function! go#config#PlayOpenBrowser() abort
|
|||||||
return get(g:, "go_play_open_browser", 1)
|
return get(g:, "go_play_open_browser", 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GorenameCommand() abort
|
function! go#config#RenameCommand() abort
|
||||||
" delegate to go#config#GorenameBin for backwards compatability.
|
" delegate to go#config#GorenameBin for backwards compatability.
|
||||||
return get(g:, "go_gorename_command", go#config#GorenameBin())
|
return get(g:, "go_rename_command", go#config#GorenameBin())
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GorenameBin() abort
|
function! go#config#GorenameBin() abort
|
||||||
@@ -480,6 +489,10 @@ function! go#config#HighlightDebug() abort
|
|||||||
return get(g:, 'go_highlight_debug', 1)
|
return get(g:, 'go_highlight_debug', 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#DebugBreakpointSignText() abort
|
||||||
|
return get(g:, 'go_debug_breakpoint_sign_text', '>')
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#FoldEnable(...) abort
|
function! go#config#FoldEnable(...) abort
|
||||||
if a:0 > 0
|
if a:0 > 0
|
||||||
return index(go#config#FoldEnable(), a:1) > -1
|
return index(go#config#FoldEnable(), a:1) > -1
|
||||||
@@ -504,26 +517,57 @@ function! go#config#ReferrersMode() abort
|
|||||||
return get(g:, 'go_referrers_mode', 'gopls')
|
return get(g:, 'go_referrers_mode', 'gopls')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ImplementsMode() abort
|
||||||
|
return get(g:, 'go_implements_mode', 'guru')
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#GoplsCompleteUnimported() abort
|
function! go#config#GoplsCompleteUnimported() abort
|
||||||
return get(g:, 'go_gopls_complete_unimported', 0)
|
return get(g:, 'go_gopls_complete_unimported', v:null)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GoplsDeepCompletion() abort
|
function! go#config#GoplsDeepCompletion() abort
|
||||||
return get(g:, 'go_gopls_deep_completion', 1)
|
return get(g:, 'go_gopls_deep_completion', v:null)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GoplsFuzzyMatching() abort
|
function! go#config#GoplsMatcher() abort
|
||||||
return get(g:, 'go_gopls_fuzzy_matching', 1)
|
if !exists('g:go_gopls_matcher') && get(g:, 'g:go_gopls_fuzzy_matching', v:null) is 1
|
||||||
|
return 'fuzzy'
|
||||||
|
endif
|
||||||
|
return get(g:, 'go_gopls_matcher', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsStaticCheck() abort
|
||||||
|
return get(g:, 'go_gopls_staticcheck', v:null)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GoplsUsePlaceholders() abort
|
function! go#config#GoplsUsePlaceholders() abort
|
||||||
return get(g:, 'go_gopls_use_placeholders', 0)
|
return get(g:, 'go_gopls_use_placeholders', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsTempModfile() abort
|
||||||
|
return get(g:, 'go_gopls_temp_modfile', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsAnalyses() abort
|
||||||
|
return get(g:, 'go_gopls_analyses', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsLocal() abort
|
||||||
|
return get(g:, 'go_gopls_local', v:null)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GoplsEnabled() abort
|
function! go#config#GoplsEnabled() abort
|
||||||
return get(g:, 'go_gopls_enabled', 1)
|
return get(g:, 'go_gopls_enabled', 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#DiagnosticsEnabled() abort
|
||||||
|
return get(g:, 'go_diagnostics_enabled', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsOptions() abort
|
||||||
|
return get(g:, 'go_gopls_options', [])
|
||||||
|
endfunction
|
||||||
|
|
||||||
" Set the default value. A value of "1" is a shortcut for this, for
|
" Set the default value. A value of "1" is a shortcut for this, for
|
||||||
" compatibility reasons.
|
" compatibility reasons.
|
||||||
if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1
|
if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1
|
||||||
|
|||||||
@@ -1,13 +1,36 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'graphql') == -1
|
||||||
|
|
||||||
" Vim plugin
|
" Copyright (c) 2016-2020 Jon Parise <jon@indelible.org>
|
||||||
|
"
|
||||||
|
" Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
" of this software and associated documentation files (the "Software"), to
|
||||||
|
" deal in the Software without restriction, including without limitation the
|
||||||
|
" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
" sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
" furnished to do so, subject to the following conditions:
|
||||||
|
"
|
||||||
|
" The above copyright notice and this permission notice shall be included in
|
||||||
|
" all copies or substantial portions of the Software.
|
||||||
|
"
|
||||||
|
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
" IN THE SOFTWARE.
|
||||||
|
"
|
||||||
" Language: GraphQL
|
" Language: GraphQL
|
||||||
" Maintainer: Jon Parise <jon@indelible.org>
|
" Maintainer: Jon Parise <jon@indelible.org>
|
||||||
|
|
||||||
if exists('g:autoloaded_graphql')
|
function! graphql#has_syntax_group(group) abort
|
||||||
finish
|
try
|
||||||
endif
|
silent execute 'silent highlight ' . a:group
|
||||||
let g:autoloaded_graphql = 1
|
catch
|
||||||
|
return v:false
|
||||||
|
endtry
|
||||||
|
return v:true
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! graphql#javascript_tags() abort
|
function! graphql#javascript_tags() abort
|
||||||
return get(g:, 'graphql_javascript_tags', ['gql', 'graphql', 'Relay.QL'])
|
return get(g:, 'graphql_javascript_tags', ['gql', 'graphql', 'Relay.QL'])
|
||||||
|
|||||||
164
autoload/health/vimtex.vim
Normal file
164
autoload/health/vimtex.vim
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
function! health#vimtex#check() abort
|
||||||
|
call vimtex#init_options()
|
||||||
|
|
||||||
|
call health#report_start('vimtex')
|
||||||
|
|
||||||
|
call s:check_general()
|
||||||
|
call s:check_plugin_clash()
|
||||||
|
call s:check_view()
|
||||||
|
call s:check_compiler()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:check_general() abort " {{{1
|
||||||
|
if !has('nvim') || v:version < 800
|
||||||
|
call health#report_warn('vimtex works best with Vim 8 or neovim')
|
||||||
|
else
|
||||||
|
call health#report_ok('Vim version should have full support!')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !executable('bibtex')
|
||||||
|
call health#report_warn('bibtex is not executable, so bibtex completions are disabled.')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:check_compiler() abort " {{{1
|
||||||
|
if !g:vimtex_compiler_enabled | return | endif
|
||||||
|
|
||||||
|
if !executable(g:vimtex_compiler_method)
|
||||||
|
let l:ind = ' '
|
||||||
|
call health#report_error(printf(
|
||||||
|
\ '|g:vimtex_compiler_method| (`%s`) is not executable!',
|
||||||
|
\ g:vimtex_compiler_method))
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:ok = 1
|
||||||
|
if !executable(g:vimtex_compiler_progname)
|
||||||
|
call health#report_warn(printf(
|
||||||
|
\ '|g:vimtex_compiler_progname| (`%s`) is not executable!',
|
||||||
|
\ g:vimtex_compiler_progname))
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has('nvim')
|
||||||
|
\ && fnamemodify(g:vimtex_compiler_progname, ':t') !=# 'nvr'
|
||||||
|
call health#report_warn('Compiler callbacks will not work!', [
|
||||||
|
\ '`neovim-remote` / `nvr` is required for callbacks to work with neovim',
|
||||||
|
\ "Please also set |g:vimtex_compiler_progname| = 'nvr'",
|
||||||
|
\ 'For more info, see :help |vimtex-faq-neovim|',
|
||||||
|
\])
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:ok
|
||||||
|
call health#report_ok('Compiler should work!')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:check_plugin_clash() abort " {{{1
|
||||||
|
let l:scriptnames = split(execute('scriptnames'), "\n")
|
||||||
|
|
||||||
|
let l:latexbox = !empty(filter(copy(l:scriptnames), "v:val =~# 'latex-box'"))
|
||||||
|
if l:latexbox
|
||||||
|
call health#report_warn('Conflicting plugin detected: LaTeX-Box')
|
||||||
|
call health#report_info('vimtex does not work as expected when LaTeX-Box is installed!')
|
||||||
|
call health#report_info('Please disable or remove it to use vimtex!')
|
||||||
|
|
||||||
|
let l:polyglot = !empty(filter(copy(l:scriptnames), "v:val =~# 'polyglot'"))
|
||||||
|
if l:polyglot
|
||||||
|
call health#report_info('LaTeX-Box is included with vim-polyglot and may be disabled with:')
|
||||||
|
call health#report_info('let g:polyglot_disabled = [''latex'']')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:check_view() abort " {{{1
|
||||||
|
call s:check_view_{g:vimtex_view_method}()
|
||||||
|
|
||||||
|
if executable('xdotool') && !executable('pstree')
|
||||||
|
call health#report_warn('pstree is not available',
|
||||||
|
\ 'vimtex#view#reverse_goto is better if pstree is available.')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:check_view_general() abort " {{{1
|
||||||
|
if executable(g:vimtex_view_general_viewer)
|
||||||
|
call health#report_ok('General viewer should work properly!')
|
||||||
|
else
|
||||||
|
call health#report_error(
|
||||||
|
\ 'Selected viewer is not executable!',
|
||||||
|
\ '- Selection: ' . g:vimtex_view_general_viewer,
|
||||||
|
\ '- Please see :h g:vimtex_view_general_viewer')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:check_view_zathura() abort " {{{1
|
||||||
|
let l:ok = 1
|
||||||
|
|
||||||
|
if !executable('zathura')
|
||||||
|
call health#report_error('Zathura is not executable!')
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !executable('xdotool')
|
||||||
|
call health#report_warn('Zathura requires xdotool for forward search!')
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:ok
|
||||||
|
call health#report_ok('Zathura should work properly!')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:check_view_mupdf() abort " {{{1
|
||||||
|
let l:ok = 1
|
||||||
|
|
||||||
|
if !executable('mupdf')
|
||||||
|
call health#report_error('MuPDF is not executable!')
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !executable('xdotool')
|
||||||
|
call health#report_warn('MuPDF requires xdotool for forward search!')
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !executable('synctex')
|
||||||
|
call health#report_warn('MuPDF requires synctex for forward search!')
|
||||||
|
let l:ok = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:ok
|
||||||
|
call health#report_ok('MuPDF should work properly!')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:check_view_skim() abort " {{{1
|
||||||
|
let l:cmd = join([
|
||||||
|
\ 'osascript -e ',
|
||||||
|
\ '''tell application "Finder" to POSIX path of ',
|
||||||
|
\ '(get application file id (id of application "Skim") as alias)''',
|
||||||
|
\])
|
||||||
|
|
||||||
|
if system(l:cmd)
|
||||||
|
call health#report_error('Skim is not installed!')
|
||||||
|
else
|
||||||
|
call health#report_ok('Skim viewer should work!')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
if !exists('g:polyglot_disabled') || !(index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'typescript') != -1 || index(g:polyglot_disabled, 'jsx') != -1)
|
||||||
|
|
||||||
function! jsx_pretty#comment#update_commentstring(original)
|
function! jsx_pretty#comment#update_commentstring(original)
|
||||||
let syn_current = s:syn_name(line('.'), col('.'))
|
let line = getline(".")
|
||||||
let syn_start = s:syn_name(line('.'), 1)
|
let col = col('.')
|
||||||
|
if line !~# '^\s*$' && line[: col - 1] =~# '^\s*$' " skip indent
|
||||||
|
let col = indent('.') + 1
|
||||||
|
endif
|
||||||
|
let syn_start = s:syn_name(line('.'), col)
|
||||||
let save_cursor = getcurpos()
|
let save_cursor = getcurpos()
|
||||||
|
|
||||||
if syn_start =~? '^jsx'
|
if syn_start =~? '^jsx'
|
||||||
let line = getline(".")
|
|
||||||
let start = len(matchstr(line, '^\s*'))
|
|
||||||
let syn_name = s:syn_name(line('.'), start + 1)
|
|
||||||
|
|
||||||
if line =~ '^\s*//'
|
if line =~ '^\s*//'
|
||||||
let &l:commentstring = '// %s'
|
let &l:commentstring = '// %s'
|
||||||
elseif s:syn_contains(line('.'), col('.'), 'jsxTaggedRegion')
|
elseif s:syn_contains(line('.'), col, 'jsxTaggedRegion')
|
||||||
let &l:commentstring = '<!-- %s -->'
|
let &l:commentstring = '<!-- %s -->'
|
||||||
elseif syn_name =~? '^jsxAttrib'
|
elseif syn_start =~? '^jsxAttrib'
|
||||||
let &l:commentstring = '// %s'
|
let &l:commentstring = '// %s'
|
||||||
else
|
else
|
||||||
let &l:commentstring = '{/* %s */}'
|
let &l:commentstring = '{/* %s */}'
|
||||||
|
|||||||
@@ -70,9 +70,9 @@ function s:is_jsx_element(syntax)
|
|||||||
return a:syntax =~? 'jsxElement'
|
return a:syntax =~? 'jsxElement'
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Whether the specified syntax group is the jsxEscapeJs
|
" Whether the specified syntax group is the jsxExpressionBlock
|
||||||
function s:is_jsx_escape(syntax)
|
function s:is_jsx_expression(syntax)
|
||||||
return a:syntax =~? 'jsxEscapeJs'
|
return a:syntax =~? 'jsxExpressionBlock'
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Whether the specified syntax group is the jsxBraces
|
" Whether the specified syntax group is the jsxBraces
|
||||||
@@ -191,7 +191,7 @@ endfunction
|
|||||||
" - jsxRegion
|
" - jsxRegion
|
||||||
" - jsxTaggedRegion
|
" - jsxTaggedRegion
|
||||||
" - jsxElement
|
" - jsxElement
|
||||||
" - jsxEscapeJs
|
" - jsxExpressionBlock
|
||||||
" - Other
|
" - Other
|
||||||
function s:syntax_context(lnum)
|
function s:syntax_context(lnum)
|
||||||
let start_col = s:start_col(a:lnum)
|
let start_col = s:start_col(a:lnum)
|
||||||
@@ -201,9 +201,9 @@ function s:syntax_context(lnum)
|
|||||||
let i = 0
|
let i = 0
|
||||||
|
|
||||||
for syntax_name in reversed
|
for syntax_name in reversed
|
||||||
" If the current line is jsxEscapeJs and not starts with jsxBraces
|
" If the current line is jsxExpressionBlock and not starts with jsxBraces
|
||||||
if s:is_jsx_escape(syntax_name)
|
if s:is_jsx_expression(syntax_name)
|
||||||
return 'jsxEscapeJs'
|
return 'jsxExpressionBlock'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if s:is_jsx_region(syntax_name)
|
if s:is_jsx_region(syntax_name)
|
||||||
@@ -287,7 +287,7 @@ function! jsx_pretty#indent#get(js_indent)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
return s:jsx_indent_element(v:lnum)
|
return s:jsx_indent_element(v:lnum)
|
||||||
elseif syntax_context == 'jsxEscapeJs'
|
elseif syntax_context == 'jsxExpressionBlock'
|
||||||
let prev_lnum = s:prev_lnum(v:lnum)
|
let prev_lnum = s:prev_lnum(v:lnum)
|
||||||
let prev_line = s:trim(getline(prev_lnum))
|
let prev_line = s:trim(getline(prev_lnum))
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,11 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'julia') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'julia') == -1
|
||||||
|
|
||||||
function! julia#set_syntax_version(jvers)
|
function! julia#set_syntax_version(jvers)
|
||||||
if &filetype != "julia"
|
echo "The julia#set_syntax_version function is deprecated"
|
||||||
echo "Not a Julia file"
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
syntax clear
|
|
||||||
let b:julia_syntax_version = a:jvers
|
|
||||||
set filetype=julia
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! julia#toggle_deprecated_syntax()
|
function! julia#toggle_deprecated_syntax()
|
||||||
if &filetype != "julia"
|
echo "The julia#toggle_deprecated_syntax function is deprecated"
|
||||||
echo "Not a Julia file"
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
syntax clear
|
|
||||||
let hd = get(b:, "julia_syntax_highlight_deprecated",
|
|
||||||
\ get(g:, "julia_syntax_highlight_deprecated", 0))
|
|
||||||
let b:julia_syntax_highlight_deprecated = hd ? 0 : 1
|
|
||||||
set filetype=julia
|
|
||||||
if b:julia_syntax_highlight_deprecated
|
|
||||||
echo "Highlighting of deprecated syntax enabled"
|
|
||||||
else
|
|
||||||
echo "Highlighting of deprecated syntax disabled"
|
|
||||||
endif
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
if exists("loaded_matchit")
|
if exists("loaded_matchit")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'julia') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'julia') == -1
|
||||||
|
|
||||||
" This file is autogenerated from the script 'generate_latex_symbols_table.jl'
|
" This file is autogenerated from the script 'generate_latex_symbols_table.jl'
|
||||||
" The symbols are based on Julia version 1.3.0-DEV.263
|
" The symbols are based on Julia version 1.5.0-DEV.67
|
||||||
|
|
||||||
scriptencoding utf-8
|
scriptencoding utf-8
|
||||||
|
|
||||||
@@ -658,7 +658,9 @@ function! julia_latex_symbols#get_dict()
|
|||||||
\ '\nequiv': '≢',
|
\ '\nequiv': '≢',
|
||||||
\ '\Equiv': '≣',
|
\ '\Equiv': '≣',
|
||||||
\ '\le': '≤',
|
\ '\le': '≤',
|
||||||
|
\ '\leq': '≤',
|
||||||
\ '\ge': '≥',
|
\ '\ge': '≥',
|
||||||
|
\ '\geq': '≥',
|
||||||
\ '\leqq': '≦',
|
\ '\leqq': '≦',
|
||||||
\ '\geqq': '≧',
|
\ '\geqq': '≧',
|
||||||
\ '\lneqq': '≨',
|
\ '\lneqq': '≨',
|
||||||
|
|||||||
@@ -502,13 +502,8 @@ class VimRubyCompletion
|
|||||||
return if rails_base == nil
|
return if rails_base == nil
|
||||||
$:.push rails_base unless $:.index( rails_base )
|
$:.push rails_base unless $:.index( rails_base )
|
||||||
|
|
||||||
rails_config = rails_base + "config/"
|
bootfile = rails_base + "config/boot.rb"
|
||||||
rails_lib = rails_base + "lib/"
|
envfile = rails_base + "config/environment.rb"
|
||||||
$:.push rails_config unless $:.index( rails_config )
|
|
||||||
$:.push rails_lib unless $:.index( rails_lib )
|
|
||||||
|
|
||||||
bootfile = rails_config + "boot.rb"
|
|
||||||
envfile = rails_config + "environment.rb"
|
|
||||||
if File.exists?( bootfile ) && File.exists?( envfile )
|
if File.exists?( bootfile ) && File.exists?( envfile )
|
||||||
begin
|
begin
|
||||||
require bootfile
|
require bootfile
|
||||||
|
|||||||
@@ -501,7 +501,15 @@ function! s:SearchTestFunctionNameUnderCursor() abort
|
|||||||
|
|
||||||
" Search the end of test function (closing brace) to ensure that the
|
" Search the end of test function (closing brace) to ensure that the
|
||||||
" cursor position is within function definition
|
" cursor position is within function definition
|
||||||
normal! %
|
if maparg('<Plug>(MatchitNormalForward)') ==# ''
|
||||||
|
keepjumps normal! %
|
||||||
|
else
|
||||||
|
" Prefer matchit.vim official plugin to native % since the plugin
|
||||||
|
" provides better behavior than original % (#391)
|
||||||
|
" To load the plugin, run:
|
||||||
|
" :packadd matchit
|
||||||
|
execute 'keepjumps' 'normal' "\<Plug>(MatchitNormalForward)"
|
||||||
|
endif
|
||||||
if line('.') < cursor_line
|
if line('.') < cursor_line
|
||||||
return ''
|
return ''
|
||||||
endif
|
endif
|
||||||
@@ -543,21 +551,20 @@ function! rust#Test(mods, winsize, all, options) abort
|
|||||||
let saved = getpos('.')
|
let saved = getpos('.')
|
||||||
try
|
try
|
||||||
let func_name = s:SearchTestFunctionNameUnderCursor()
|
let func_name = s:SearchTestFunctionNameUnderCursor()
|
||||||
if func_name ==# ''
|
|
||||||
echohl ErrorMsg
|
|
||||||
echomsg 'No test function was found under the cursor. Please add ! to command if you want to run all tests'
|
|
||||||
echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if a:options ==# ''
|
|
||||||
execute cmd . 'cargo test --manifest-path' manifest func_name
|
|
||||||
else
|
|
||||||
execute cmd . 'cargo test --manifest-path' manifest func_name a:options
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
finally
|
finally
|
||||||
call setpos('.', saved)
|
call setpos('.', saved)
|
||||||
endtry
|
endtry
|
||||||
|
if func_name ==# ''
|
||||||
|
echohl ErrorMsg
|
||||||
|
echomsg 'No test function was found under the cursor. Please add ! to command if you want to run all tests'
|
||||||
|
echohl None
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if a:options ==# ''
|
||||||
|
execute cmd . 'cargo test --manifest-path' manifest func_name
|
||||||
|
else
|
||||||
|
execute cmd . 'cargo test --manifest-path' manifest func_name a:options
|
||||||
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" }}}1
|
" }}}1
|
||||||
|
|||||||
@@ -62,18 +62,19 @@ function! s:RustfmtWriteMode()
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:RustfmtConfig()
|
function! s:RustfmtConfigOptions()
|
||||||
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
|
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
|
||||||
if l:rustfmt_toml !=# ''
|
if l:rustfmt_toml !=# ''
|
||||||
return '--config-path '.l:rustfmt_toml
|
return '--config-path '.fnamemodify(l:rustfmt_toml, ":p")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:_rustfmt_toml = findfile('.rustfmt.toml', expand('%:p:h') . ';')
|
let l:_rustfmt_toml = findfile('.rustfmt.toml', expand('%:p:h') . ';')
|
||||||
if l:_rustfmt_toml !=# ''
|
if l:_rustfmt_toml !=# ''
|
||||||
return '--config-path '.l:_rustfmt_toml
|
return '--config-path '.fnamemodify(l:_rustfmt_toml, ":p")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return ''
|
" Default to edition 2018 in case no rustfmt.toml was found.
|
||||||
|
return '--edition 2018'
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:RustfmtCommandRange(filename, line1, line2)
|
function! s:RustfmtCommandRange(filename, line1, line2)
|
||||||
@@ -84,7 +85,7 @@ function! s:RustfmtCommandRange(filename, line1, line2)
|
|||||||
|
|
||||||
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
|
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
|
||||||
let l:write_mode = s:RustfmtWriteMode()
|
let l:write_mode = s:RustfmtWriteMode()
|
||||||
let l:rustfmt_config = s:RustfmtConfig()
|
let l:rustfmt_config = s:RustfmtConfigOptions()
|
||||||
|
|
||||||
" FIXME: When --file-lines gets to be stable, add version range checking
|
" FIXME: When --file-lines gets to be stable, add version range checking
|
||||||
" accordingly.
|
" accordingly.
|
||||||
@@ -98,14 +99,9 @@ function! s:RustfmtCommandRange(filename, line1, line2)
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:RustfmtCommand()
|
function! s:RustfmtCommand()
|
||||||
if g:rustfmt_emit_files
|
let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display'
|
||||||
let l:write_mode = "--emit=stdout"
|
let config = s:RustfmtConfigOptions()
|
||||||
else
|
return join([g:rustfmt_command, write_mode, config, g:rustfmt_options])
|
||||||
let l:write_mode = "--write-mode=display"
|
|
||||||
endif
|
|
||||||
" rustfmt will pick on the right config on its own due to the
|
|
||||||
" current directory change.
|
|
||||||
return g:rustfmt_command . " ". l:write_mode . " " . g:rustfmt_options
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:DeleteLines(start, end) abort
|
function! s:DeleteLines(start, end) abort
|
||||||
|
|||||||
@@ -1,26 +1,39 @@
|
|||||||
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'terraform') == -1
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'terraform') == -1
|
||||||
|
|
||||||
|
let s:cpo_save = &cpoptions
|
||||||
|
set cpoptions&vim
|
||||||
|
|
||||||
" Ensure no conflict with arguments from the environment
|
" Ensure no conflict with arguments from the environment
|
||||||
let $TF_CLI_ARGS_fmt=''
|
let $TF_CLI_ARGS_fmt=''
|
||||||
|
|
||||||
function! terraform#fmt()
|
function! terraform#fmt() abort
|
||||||
if !filereadable(expand('%:p'))
|
" Save the view.
|
||||||
return
|
let curw = winsaveview()
|
||||||
endif
|
|
||||||
let l:curw = winsaveview()
|
|
||||||
" Make a fake change so that the undo point is right.
|
" Make a fake change so that the undo point is right.
|
||||||
normal! ix
|
normal! ix
|
||||||
normal! "_x
|
normal! "_x
|
||||||
|
|
||||||
|
" Execute `terraform fmt`, redirecting stderr to a temporary file.
|
||||||
|
let tmpfile = tempname()
|
||||||
|
let shellredir_save = &shellredir
|
||||||
|
let &shellredir = '>%s 2>'.tmpfile
|
||||||
silent execute '%!terraform fmt -no-color -'
|
silent execute '%!terraform fmt -no-color -'
|
||||||
|
let &shellredir = shellredir_save
|
||||||
|
|
||||||
|
" If there was an error, undo any changes and show stderr.
|
||||||
if v:shell_error != 0
|
if v:shell_error != 0
|
||||||
let output = getline(1, '$')
|
|
||||||
silent undo
|
silent undo
|
||||||
|
let output = readfile(tmpfile)
|
||||||
echo join(output, "\n")
|
echo join(output, "\n")
|
||||||
endif
|
endif
|
||||||
call winrestview(l:curw)
|
|
||||||
|
" Delete the temporary file, and restore the view.
|
||||||
|
call delete(tmpfile)
|
||||||
|
call winrestview(curw)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! terraform#align()
|
function! terraform#align() abort
|
||||||
let p = '^.*=[^>]*$'
|
let p = '^.*=[^>]*$'
|
||||||
if exists(':Tabularize') && getline('.') =~# '^.*=' && (getline(line('.')-1) =~# p || getline(line('.')+1) =~# p)
|
if exists(':Tabularize') && getline('.') =~# '^.*=' && (getline(line('.')-1) =~# p || getline(line('.')+1) =~# p)
|
||||||
let column = strlen(substitute(getline('.')[0:col('.')],'[^=]','','g'))
|
let column = strlen(substitute(getline('.')[0:col('.')],'[^=]','','g'))
|
||||||
@@ -31,8 +44,8 @@ function! terraform#align()
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! terraform#commands(ArgLead, CmdLine, CursorPos)
|
function! terraform#commands(ArgLead, CmdLine, CursorPos) abort
|
||||||
let l:commands = [
|
let commands = [
|
||||||
\ 'apply',
|
\ 'apply',
|
||||||
\ 'console',
|
\ 'console',
|
||||||
\ 'destroy',
|
\ 'destroy',
|
||||||
@@ -58,7 +71,10 @@ function! terraform#commands(ArgLead, CmdLine, CursorPos)
|
|||||||
\ 'push',
|
\ 'push',
|
||||||
\ 'state'
|
\ 'state'
|
||||||
\ ]
|
\ ]
|
||||||
return join(l:commands, "\n")
|
return join(commands, "\n")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
let &cpoptions = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
87
autoload/unite/sources/vimtex.vim
Normal file
87
autoload/unite/sources/vimtex.vim
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
let s:save_cpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
let s:source = {
|
||||||
|
\ 'name' : 'vimtex',
|
||||||
|
\ 'sorters' : 'sorter_nothing',
|
||||||
|
\ 'default_kind' : 'jump_list',
|
||||||
|
\ 'syntax' : 'uniteSource__vimtex',
|
||||||
|
\ 'entries' : [],
|
||||||
|
\ 'maxlevel' : 1,
|
||||||
|
\ 'hooks' : {},
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:source.gather_candidates(args, context) abort " {{{1
|
||||||
|
if exists('b:vimtex')
|
||||||
|
let s:source.entries = vimtex#parser#toc()
|
||||||
|
let s:source.maxlevel = max(map(copy(s:source.entries), 'v:val.level'))
|
||||||
|
endif
|
||||||
|
return map(copy(s:source.entries),
|
||||||
|
\ 's:create_candidate(v:val, s:source.maxlevel)')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:source.hooks.on_syntax(args, context) abort " {{{1
|
||||||
|
syntax match VimtexTocSecs /.* @\d$/
|
||||||
|
\ contains=VimtexTocNum,VimtexTocTag,@Tex
|
||||||
|
\ contained containedin=uniteSource__vimtex
|
||||||
|
syntax match VimtexTocSec0 /.* @0$/
|
||||||
|
\ contains=VimtexTocNum,VimtexTocTag,@Tex
|
||||||
|
\ contained containedin=uniteSource__vimtex
|
||||||
|
syntax match VimtexTocSec1 /.* @1$/
|
||||||
|
\ contains=VimtexTocNum,VimtexTocTag,@Tex
|
||||||
|
\ contained containedin=uniteSource__vimtex
|
||||||
|
syntax match VimtexTocSec2 /.* @2$/
|
||||||
|
\ contains=VimtexTocNum,VimtexTocTag,@Tex
|
||||||
|
\ contained containedin=uniteSource__vimtex
|
||||||
|
syntax match VimtexTocSec3 /.* @3$/
|
||||||
|
\ contains=VimtexTocNum,VimtexTocTag,@Tex
|
||||||
|
\ contained containedin=uniteSource__vimtex
|
||||||
|
syntax match VimtexTocSec4 /.* @4$/
|
||||||
|
\ contains=VimtexTocNum,VimtexTocTag,@Tex
|
||||||
|
\ contained containedin=uniteSource__vimtex
|
||||||
|
syntax match VimtexTocNum
|
||||||
|
\ /\%69v\%(\%([A-Z]\+\>\|\d\+\)\%(\.\d\+\)*\)\?\s*@\d$/
|
||||||
|
\ contains=VimtexTocLevel
|
||||||
|
\ contained containedin=VimtexTocSec[0-9*]
|
||||||
|
syntax match VimtexTocTag
|
||||||
|
\ /\[.\]\s*@\d$/
|
||||||
|
\ contains=VimtexTocLevel
|
||||||
|
\ contained containedin=VimtexTocSec[0-9*]
|
||||||
|
syntax match VimtexTocLevel
|
||||||
|
\ /@\d$/ conceal
|
||||||
|
\ contained containedin=VimtexTocNum,VimtexTocTag
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:create_candidate(entry, maxlevel) abort " {{{1
|
||||||
|
let level = a:maxlevel - a:entry.level
|
||||||
|
let title = printf('%-65S%-10s',
|
||||||
|
\ strpart(repeat(' ', 2*level) . a:entry.title, 0, 60),
|
||||||
|
\ b:vimtex.toc.print_number(a:entry.number))
|
||||||
|
return {
|
||||||
|
\ 'word' : title,
|
||||||
|
\ 'abbr' : title . ' @' . level,
|
||||||
|
\ 'action__path' : a:entry.file,
|
||||||
|
\ 'action__line' : get(a:entry, 'line', 0),
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! unite#sources#vimtex#define() abort
|
||||||
|
return s:source
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let &cpo = s:save_cpo
|
||||||
|
|
||||||
|
endif
|
||||||
707
autoload/vimtex.vim
Normal file
707
autoload/vimtex.vim
Normal file
@@ -0,0 +1,707 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#init() abort " {{{1
|
||||||
|
call vimtex#init_options()
|
||||||
|
|
||||||
|
call s:init_highlights()
|
||||||
|
call s:init_state()
|
||||||
|
call s:init_buffer()
|
||||||
|
call s:init_default_mappings()
|
||||||
|
|
||||||
|
if exists('#User#VimtexEventInitPost')
|
||||||
|
doautocmd <nomodeline> User VimtexEventInitPost
|
||||||
|
endif
|
||||||
|
|
||||||
|
augroup vimtex_main
|
||||||
|
autocmd!
|
||||||
|
autocmd VimLeave * call s:quit()
|
||||||
|
augroup END
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#init_options() abort " {{{1
|
||||||
|
call s:init_option('vimtex_compiler_enabled', 1)
|
||||||
|
call s:init_option('vimtex_compiler_method', 'latexmk')
|
||||||
|
call s:init_option('vimtex_compiler_progname',
|
||||||
|
\ has('nvim') && executable('nvr')
|
||||||
|
\ ? 'nvr'
|
||||||
|
\ : get(v:, 'progpath', get(v:, 'progname', '')))
|
||||||
|
call s:init_option('vimtex_compiler_callback_hooks', [])
|
||||||
|
call s:init_option('vimtex_compiler_latexmk_engines', {})
|
||||||
|
call s:init_option('vimtex_compiler_latexrun_engines', {})
|
||||||
|
|
||||||
|
call s:init_option('vimtex_complete_enabled', 1)
|
||||||
|
call s:init_option('vimtex_complete_close_braces', 0)
|
||||||
|
call s:init_option('vimtex_complete_ignore_case', &ignorecase)
|
||||||
|
call s:init_option('vimtex_complete_smart_case', &smartcase)
|
||||||
|
call s:init_option('vimtex_complete_bib', {
|
||||||
|
\ 'simple': 0,
|
||||||
|
\ 'menu_fmt': '[@type] @author_short (@year), "@title"',
|
||||||
|
\ 'abbr_fmt': '',
|
||||||
|
\ 'custom_patterns': [],
|
||||||
|
\})
|
||||||
|
call s:init_option('vimtex_complete_ref', {
|
||||||
|
\ 'custom_patterns': [],
|
||||||
|
\})
|
||||||
|
|
||||||
|
call s:init_option('vimtex_delim_timeout', 300)
|
||||||
|
call s:init_option('vimtex_delim_insert_timeout', 60)
|
||||||
|
call s:init_option('vimtex_delim_stopline', 500)
|
||||||
|
|
||||||
|
call s:init_option('vimtex_include_search_enabled', 1)
|
||||||
|
|
||||||
|
call s:init_option('vimtex_doc_enabled', 1)
|
||||||
|
call s:init_option('vimtex_doc_handlers', [])
|
||||||
|
|
||||||
|
call s:init_option('vimtex_echo_verbose_input', 1)
|
||||||
|
|
||||||
|
call s:init_option('vimtex_env_change_autofill', 0)
|
||||||
|
|
||||||
|
if &diff
|
||||||
|
let g:vimtex_fold_enabled = 0
|
||||||
|
else
|
||||||
|
call s:init_option('vimtex_fold_enabled', 0)
|
||||||
|
endif
|
||||||
|
call s:init_option('vimtex_fold_manual', 0)
|
||||||
|
call s:init_option('vimtex_fold_levelmarker', '*')
|
||||||
|
call s:init_option('vimtex_fold_types', {})
|
||||||
|
call s:init_option('vimtex_fold_types_defaults', {
|
||||||
|
\ 'preamble' : {},
|
||||||
|
\ 'comments' : { 'enabled' : 0 },
|
||||||
|
\ 'envs' : {
|
||||||
|
\ 'blacklist' : [],
|
||||||
|
\ 'whitelist' : [],
|
||||||
|
\ },
|
||||||
|
\ 'env_options' : {},
|
||||||
|
\ 'markers' : {},
|
||||||
|
\ 'sections' : {
|
||||||
|
\ 'parse_levels' : 0,
|
||||||
|
\ 'sections' : [
|
||||||
|
\ 'part',
|
||||||
|
\ 'chapter',
|
||||||
|
\ 'section',
|
||||||
|
\ 'subsection',
|
||||||
|
\ 'subsubsection',
|
||||||
|
\ ],
|
||||||
|
\ 'parts' : [
|
||||||
|
\ 'appendix',
|
||||||
|
\ 'frontmatter',
|
||||||
|
\ 'mainmatter',
|
||||||
|
\ 'backmatter',
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\ 'cmd_single' : {
|
||||||
|
\ 'cmds' : [
|
||||||
|
\ 'hypersetup',
|
||||||
|
\ 'tikzset',
|
||||||
|
\ 'pgfplotstableread',
|
||||||
|
\ 'lstset',
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\ 'cmd_single_opt' : {
|
||||||
|
\ 'cmds' : [
|
||||||
|
\ 'usepackage',
|
||||||
|
\ 'includepdf',
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\ 'cmd_multi' : {
|
||||||
|
\ 'cmds' : [
|
||||||
|
\ '%(re)?new%(command|environment)',
|
||||||
|
\ 'providecommand',
|
||||||
|
\ 'presetkeys',
|
||||||
|
\ 'Declare%(Multi|Auto)?CiteCommand',
|
||||||
|
\ 'Declare%(Index)?%(Field|List|Name)%(Format|Alias)',
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\ 'cmd_addplot' : {
|
||||||
|
\ 'cmds' : [
|
||||||
|
\ 'addplot[+3]?',
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\})
|
||||||
|
|
||||||
|
call s:init_option('vimtex_format_enabled', 0)
|
||||||
|
|
||||||
|
call s:init_option('vimtex_imaps_enabled', 1)
|
||||||
|
call s:init_option('vimtex_imaps_disabled', [])
|
||||||
|
call s:init_option('vimtex_imaps_list', [
|
||||||
|
\ { 'lhs' : '0', 'rhs' : '\emptyset' },
|
||||||
|
\ { 'lhs' : '6', 'rhs' : '\partial' },
|
||||||
|
\ { 'lhs' : '8', 'rhs' : '\infty' },
|
||||||
|
\ { 'lhs' : '=', 'rhs' : '\equiv' },
|
||||||
|
\ { 'lhs' : '\', 'rhs' : '\setminus' },
|
||||||
|
\ { 'lhs' : '.', 'rhs' : '\cdot' },
|
||||||
|
\ { 'lhs' : '*', 'rhs' : '\times' },
|
||||||
|
\ { 'lhs' : '<', 'rhs' : '\langle' },
|
||||||
|
\ { 'lhs' : '>', 'rhs' : '\rangle' },
|
||||||
|
\ { 'lhs' : 'H', 'rhs' : '\hbar' },
|
||||||
|
\ { 'lhs' : '+', 'rhs' : '\dagger' },
|
||||||
|
\ { 'lhs' : '[', 'rhs' : '\subseteq' },
|
||||||
|
\ { 'lhs' : ']', 'rhs' : '\supseteq' },
|
||||||
|
\ { 'lhs' : '(', 'rhs' : '\subset' },
|
||||||
|
\ { 'lhs' : ')', 'rhs' : '\supset' },
|
||||||
|
\ { 'lhs' : 'A', 'rhs' : '\forall' },
|
||||||
|
\ { 'lhs' : 'E', 'rhs' : '\exists' },
|
||||||
|
\ { 'lhs' : 'jj', 'rhs' : '\downarrow' },
|
||||||
|
\ { 'lhs' : 'jJ', 'rhs' : '\Downarrow' },
|
||||||
|
\ { 'lhs' : 'jk', 'rhs' : '\uparrow' },
|
||||||
|
\ { 'lhs' : 'jK', 'rhs' : '\Uparrow' },
|
||||||
|
\ { 'lhs' : 'jh', 'rhs' : '\leftarrow' },
|
||||||
|
\ { 'lhs' : 'jH', 'rhs' : '\Leftarrow' },
|
||||||
|
\ { 'lhs' : 'jl', 'rhs' : '\rightarrow' },
|
||||||
|
\ { 'lhs' : 'jL', 'rhs' : '\Rightarrow' },
|
||||||
|
\ { 'lhs' : 'a', 'rhs' : '\alpha' },
|
||||||
|
\ { 'lhs' : 'b', 'rhs' : '\beta' },
|
||||||
|
\ { 'lhs' : 'c', 'rhs' : '\chi' },
|
||||||
|
\ { 'lhs' : 'd', 'rhs' : '\delta' },
|
||||||
|
\ { 'lhs' : 'e', 'rhs' : '\epsilon' },
|
||||||
|
\ { 'lhs' : 'f', 'rhs' : '\phi' },
|
||||||
|
\ { 'lhs' : 'g', 'rhs' : '\gamma' },
|
||||||
|
\ { 'lhs' : 'h', 'rhs' : '\eta' },
|
||||||
|
\ { 'lhs' : 'i', 'rhs' : '\iota' },
|
||||||
|
\ { 'lhs' : 'k', 'rhs' : '\kappa' },
|
||||||
|
\ { 'lhs' : 'l', 'rhs' : '\lambda' },
|
||||||
|
\ { 'lhs' : 'm', 'rhs' : '\mu' },
|
||||||
|
\ { 'lhs' : 'n', 'rhs' : '\nu' },
|
||||||
|
\ { 'lhs' : 'p', 'rhs' : '\pi' },
|
||||||
|
\ { 'lhs' : 'q', 'rhs' : '\theta' },
|
||||||
|
\ { 'lhs' : 'r', 'rhs' : '\rho' },
|
||||||
|
\ { 'lhs' : 's', 'rhs' : '\sigma' },
|
||||||
|
\ { 'lhs' : 't', 'rhs' : '\tau' },
|
||||||
|
\ { 'lhs' : 'y', 'rhs' : '\psi' },
|
||||||
|
\ { 'lhs' : 'u', 'rhs' : '\upsilon' },
|
||||||
|
\ { 'lhs' : 'w', 'rhs' : '\omega' },
|
||||||
|
\ { 'lhs' : 'z', 'rhs' : '\zeta' },
|
||||||
|
\ { 'lhs' : 'x', 'rhs' : '\xi' },
|
||||||
|
\ { 'lhs' : 'G', 'rhs' : '\Gamma' },
|
||||||
|
\ { 'lhs' : 'D', 'rhs' : '\Delta' },
|
||||||
|
\ { 'lhs' : 'F', 'rhs' : '\Phi' },
|
||||||
|
\ { 'lhs' : 'G', 'rhs' : '\Gamma' },
|
||||||
|
\ { 'lhs' : 'L', 'rhs' : '\Lambda' },
|
||||||
|
\ { 'lhs' : 'P', 'rhs' : '\Pi' },
|
||||||
|
\ { 'lhs' : 'Q', 'rhs' : '\Theta' },
|
||||||
|
\ { 'lhs' : 'S', 'rhs' : '\Sigma' },
|
||||||
|
\ { 'lhs' : 'U', 'rhs' : '\Upsilon' },
|
||||||
|
\ { 'lhs' : 'W', 'rhs' : '\Omega' },
|
||||||
|
\ { 'lhs' : 'X', 'rhs' : '\Xi' },
|
||||||
|
\ { 'lhs' : 'Y', 'rhs' : '\Psi' },
|
||||||
|
\ { 'lhs' : 've', 'rhs' : '\varepsilon' },
|
||||||
|
\ { 'lhs' : 'vf', 'rhs' : '\varphi' },
|
||||||
|
\ { 'lhs' : 'vk', 'rhs' : '\varkappa' },
|
||||||
|
\ { 'lhs' : 'vq', 'rhs' : '\vartheta' },
|
||||||
|
\ { 'lhs' : 'vr', 'rhs' : '\varrho' },
|
||||||
|
\ { 'lhs' : '/', 'rhs' : 'vimtex#imaps#style_math("slashed")', 'expr' : 1, 'leader' : '#'},
|
||||||
|
\ { 'lhs' : 'b', 'rhs' : 'vimtex#imaps#style_math("mathbf")', 'expr' : 1, 'leader' : '#'},
|
||||||
|
\ { 'lhs' : 'f', 'rhs' : 'vimtex#imaps#style_math("mathfrak")', 'expr' : 1, 'leader' : '#'},
|
||||||
|
\ { 'lhs' : 'c', 'rhs' : 'vimtex#imaps#style_math("mathcal")', 'expr' : 1, 'leader' : '#'},
|
||||||
|
\ { 'lhs' : '-', 'rhs' : 'vimtex#imaps#style_math("overline")', 'expr' : 1, 'leader' : '#'},
|
||||||
|
\ { 'lhs' : 'B', 'rhs' : 'vimtex#imaps#style_math("mathbb")', 'expr' : 1, 'leader' : '#'},
|
||||||
|
\])
|
||||||
|
|
||||||
|
call s:init_option('vimtex_mappings_enabled', 1)
|
||||||
|
call s:init_option('vimtex_mappings_disable', {})
|
||||||
|
|
||||||
|
call s:init_option('vimtex_matchparen_enabled', 1)
|
||||||
|
call s:init_option('vimtex_motion_enabled', 1)
|
||||||
|
|
||||||
|
call s:init_option('vimtex_labels_enabled', 1)
|
||||||
|
call s:init_option('vimtex_labels_refresh_always', 1)
|
||||||
|
|
||||||
|
call s:init_option('vimtex_parser_bib_backend', 'bibtex')
|
||||||
|
|
||||||
|
call s:init_option('vimtex_quickfix_enabled', 1)
|
||||||
|
call s:init_option('vimtex_quickfix_method', 'latexlog')
|
||||||
|
call s:init_option('vimtex_quickfix_autojump', '0')
|
||||||
|
call s:init_option('vimtex_quickfix_ignore_filters', [])
|
||||||
|
call s:init_option('vimtex_quickfix_mode', '2')
|
||||||
|
call s:init_option('vimtex_quickfix_open_on_warning', '1')
|
||||||
|
call s:init_option('vimtex_quickfix_blgparser', {})
|
||||||
|
call s:init_option('vimtex_quickfix_autoclose_after_keystrokes', '0')
|
||||||
|
|
||||||
|
call s:init_option('vimtex_syntax_enabled', 1)
|
||||||
|
call s:init_option('vimtex_syntax_nested', {
|
||||||
|
\ 'aliases' : {
|
||||||
|
\ 'C' : 'c',
|
||||||
|
\ 'csharp' : 'cs',
|
||||||
|
\ },
|
||||||
|
\ 'ignored' : {
|
||||||
|
\ 'cs' : [
|
||||||
|
\ 'csBraces',
|
||||||
|
\ ],
|
||||||
|
\ 'python' : [
|
||||||
|
\ 'pythonEscape',
|
||||||
|
\ 'pythonBEscape',
|
||||||
|
\ 'pythonBytesEscape',
|
||||||
|
\ ],
|
||||||
|
\ 'java' : [
|
||||||
|
\ 'javaError',
|
||||||
|
\ ],
|
||||||
|
\ 'haskell' : [
|
||||||
|
\ 'hsVarSym',
|
||||||
|
\ ],
|
||||||
|
\ }
|
||||||
|
\})
|
||||||
|
|
||||||
|
call s:init_option('vimtex_texcount_custom_arg', '')
|
||||||
|
|
||||||
|
call s:init_option('vimtex_text_obj_enabled', 1)
|
||||||
|
call s:init_option('vimtex_text_obj_variant', 'auto')
|
||||||
|
call s:init_option('vimtex_text_obj_linewise_operators', ['d', 'y'])
|
||||||
|
|
||||||
|
call s:init_option('vimtex_toc_enabled', 1)
|
||||||
|
call s:init_option('vimtex_toc_custom_matchers', [])
|
||||||
|
call s:init_option('vimtex_toc_show_preamble', 1)
|
||||||
|
call s:init_option('vimtex_toc_todo_keywords', ['TODO', 'FIXME'])
|
||||||
|
call s:init_option('vimtex_toc_config', {
|
||||||
|
\ 'name' : 'Table of contents (vimtex)',
|
||||||
|
\ 'mode' : 1,
|
||||||
|
\ 'fold_enable' : 0,
|
||||||
|
\ 'fold_level_start' : -1,
|
||||||
|
\ 'hide_line_numbers' : 1,
|
||||||
|
\ 'hotkeys_enabled' : 0,
|
||||||
|
\ 'hotkeys' : 'abcdeilmnopuvxyz',
|
||||||
|
\ 'hotkeys_leader' : ';',
|
||||||
|
\ 'layer_status' : {
|
||||||
|
\ 'content': 1,
|
||||||
|
\ 'label': 1,
|
||||||
|
\ 'todo': 1,
|
||||||
|
\ 'include': 1,
|
||||||
|
\ },
|
||||||
|
\ 'layer_keys' : {
|
||||||
|
\ 'content': 'C',
|
||||||
|
\ 'label': 'L',
|
||||||
|
\ 'todo': 'T',
|
||||||
|
\ 'include': 'I',
|
||||||
|
\ },
|
||||||
|
\ 'resize' : 0,
|
||||||
|
\ 'refresh_always' : 1,
|
||||||
|
\ 'show_help' : 1,
|
||||||
|
\ 'show_numbers' : 1,
|
||||||
|
\ 'split_pos' : 'vert leftabove',
|
||||||
|
\ 'split_width' : 30,
|
||||||
|
\ 'tocdepth' : 3,
|
||||||
|
\ 'todo_sorted' : 1,
|
||||||
|
\})
|
||||||
|
|
||||||
|
call s:init_option('vimtex_view_enabled', 1)
|
||||||
|
call s:init_option('vimtex_view_automatic', 1)
|
||||||
|
call s:init_option('vimtex_view_method', 'general')
|
||||||
|
call s:init_option('vimtex_view_use_temp_files', 0)
|
||||||
|
call s:init_option('vimtex_view_forward_search_on_start', 1)
|
||||||
|
|
||||||
|
" OS dependent defaults
|
||||||
|
let l:os = vimtex#util#get_os()
|
||||||
|
if l:os ==# 'win'
|
||||||
|
if executable('SumatraPDF')
|
||||||
|
call s:init_option('vimtex_view_general_viewer', 'SumatraPDF')
|
||||||
|
call s:init_option('vimtex_view_general_options',
|
||||||
|
\ '-reuse-instance -forward-search @tex @line @pdf')
|
||||||
|
call s:init_option('vimtex_view_general_options_latexmk',
|
||||||
|
\ 'reuse-instance')
|
||||||
|
elseif executable('mupdf')
|
||||||
|
call s:init_option('vimtex_view_general_viewer', 'mupdf')
|
||||||
|
else
|
||||||
|
call s:init_option('vimtex_view_general_viewer', '')
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
call s:init_option('vimtex_view_general_viewer', get({
|
||||||
|
\ 'linux' : 'xdg-open',
|
||||||
|
\ 'mac' : 'open',
|
||||||
|
\ 'win' : 'start',
|
||||||
|
\}, l:os, ''))
|
||||||
|
call s:init_option('vimtex_view_general_options', '@pdf')
|
||||||
|
call s:init_option('vimtex_view_general_options_latexmk', '')
|
||||||
|
endif
|
||||||
|
|
||||||
|
call s:init_option('vimtex_view_mupdf_options', '')
|
||||||
|
call s:init_option('vimtex_view_mupdf_send_keys', '')
|
||||||
|
call s:init_option('vimtex_view_skim_activate', 0)
|
||||||
|
call s:init_option('vimtex_view_skim_reading_bar', 1)
|
||||||
|
call s:init_option('vimtex_view_zathura_options', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#check_plugin_clash() abort " {{{1
|
||||||
|
let l:scriptnames = vimtex#util#command('scriptnames')
|
||||||
|
|
||||||
|
let l:latexbox = !empty(filter(copy(l:scriptnames), "v:val =~# 'latex-box'"))
|
||||||
|
if l:latexbox
|
||||||
|
let l:polyglot = !empty(filter(copy(l:scriptnames), "v:val =~# 'polyglot'"))
|
||||||
|
call vimtex#log#warning([
|
||||||
|
\ 'Conflicting plugin detected: LaTeX-Box',
|
||||||
|
\ 'vimtex does not work as expected when LaTeX-Box is installed!',
|
||||||
|
\ 'Please disable or remove it to use vimtex!',
|
||||||
|
\])
|
||||||
|
if l:polyglot
|
||||||
|
call vimtex#log#warning([
|
||||||
|
\ 'LaTeX-Box is included with vim-polyglot and may be disabled with:',
|
||||||
|
\ 'let g:polyglot_disabled = [''latex'']',
|
||||||
|
\])
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:init_option(option, default) abort " {{{1
|
||||||
|
let l:option = 'g:' . a:option
|
||||||
|
if !exists(l:option)
|
||||||
|
let {l:option} = a:default
|
||||||
|
elseif type(a:default) == type({})
|
||||||
|
call vimtex#util#extend_recursive({l:option}, a:default, 'keep')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:init_highlights() abort " {{{1
|
||||||
|
for [l:name, l:target] in [
|
||||||
|
\ ['VimtexImapsArrow', 'Comment'],
|
||||||
|
\ ['VimtexImapsLhs', 'ModeMsg'],
|
||||||
|
\ ['VimtexImapsRhs', 'ModeMsg'],
|
||||||
|
\ ['VimtexImapsWrapper', 'Type'],
|
||||||
|
\ ['VimtexInfo', 'Question'],
|
||||||
|
\ ['VimtexInfoTitle', 'PreProc'],
|
||||||
|
\ ['VimtexInfoKey', 'PreProc'],
|
||||||
|
\ ['VimtexInfoValue', 'Statement'],
|
||||||
|
\ ['VimtexInfoOther', 'Normal'],
|
||||||
|
\ ['VimtexMsg', 'ModeMsg'],
|
||||||
|
\ ['VimtexSuccess', 'Statement'],
|
||||||
|
\ ['VimtexTocHelp', 'helpVim'],
|
||||||
|
\ ['VimtexTocHelpKey', 'ModeMsg'],
|
||||||
|
\ ['VimtexTocHelpLayerOn', 'Statement'],
|
||||||
|
\ ['VimtexTocHelpLayerOff', 'Comment'],
|
||||||
|
\ ['VimtexTocTodo', 'Todo'],
|
||||||
|
\ ['VimtexTocNum', 'Number'],
|
||||||
|
\ ['VimtexTocSec0', 'Title'],
|
||||||
|
\ ['VimtexTocSec1', 'Normal'],
|
||||||
|
\ ['VimtexTocSec2', 'helpVim'],
|
||||||
|
\ ['VimtexTocSec3', 'NonText'],
|
||||||
|
\ ['VimtexTocSec4', 'Comment'],
|
||||||
|
\ ['VimtexTocHotkey', 'Comment'],
|
||||||
|
\ ['VimtexTocLabelsSecs', 'Statement'],
|
||||||
|
\ ['VimtexTocLabelsEq', 'PreProc'],
|
||||||
|
\ ['VimtexTocLabelsFig', 'Identifier'],
|
||||||
|
\ ['VimtexTocLabelsTab', 'String'],
|
||||||
|
\ ['VimtexTocIncl', 'Number'],
|
||||||
|
\ ['VimtexTocInclPath', 'Normal'],
|
||||||
|
\ ['VimtexWarning', 'WarningMsg'],
|
||||||
|
\ ['VimtexError', 'ErrorMsg'],
|
||||||
|
\]
|
||||||
|
if !hlexists(l:name)
|
||||||
|
silent execute 'highlight default link' l:name l:target
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:init_state() abort " {{{1
|
||||||
|
call vimtex#state#init()
|
||||||
|
call vimtex#state#init_local()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:init_buffer() abort " {{{1
|
||||||
|
" Set Vim options
|
||||||
|
for l:suf in [
|
||||||
|
\ '.sty',
|
||||||
|
\ '.cls',
|
||||||
|
\ '.log',
|
||||||
|
\ '.aux',
|
||||||
|
\ '.bbl',
|
||||||
|
\ '.out',
|
||||||
|
\ '.blg',
|
||||||
|
\ '.brf',
|
||||||
|
\ '.cb',
|
||||||
|
\ '.dvi',
|
||||||
|
\ '.fdb_latexmk',
|
||||||
|
\ '.fls',
|
||||||
|
\ '.idx',
|
||||||
|
\ '.ilg',
|
||||||
|
\ '.ind',
|
||||||
|
\ '.inx',
|
||||||
|
\ '.pdf',
|
||||||
|
\ '.synctex.gz',
|
||||||
|
\ '.toc',
|
||||||
|
\ ]
|
||||||
|
execute 'set suffixes+=' . l:suf
|
||||||
|
endfor
|
||||||
|
setlocal suffixesadd=.sty,.tex,.cls
|
||||||
|
setlocal comments=sO:%\ -,mO:%\ \ ,eO:%%,:%
|
||||||
|
setlocal commentstring=%%s
|
||||||
|
setlocal iskeyword+=:
|
||||||
|
setlocal includeexpr=vimtex#include#expr()
|
||||||
|
let &l:include = g:vimtex#re#tex_include
|
||||||
|
let &l:define = '\\\([egx]\|char\|mathchar\|count\|dimen\|muskip\|skip'
|
||||||
|
let &l:define .= '\|toks\)\=def\|\\font\|\\\(future\)\=let'
|
||||||
|
let &l:define .= '\|\\new\(count\|dimen\|skip'
|
||||||
|
let &l:define .= '\|muskip\|box\|toks\|read\|write\|fam\|insert\)'
|
||||||
|
let &l:define .= '\|\\\(re\)\=new\(boolean\|command\|counter\|environment'
|
||||||
|
let &l:define .= '\|font\|if\|length\|savebox'
|
||||||
|
let &l:define .= '\|theorem\(style\)\=\)\s*\*\=\s*{\='
|
||||||
|
let &l:define .= '\|DeclareMathOperator\s*{\=\s*'
|
||||||
|
|
||||||
|
" Define autocommands
|
||||||
|
augroup vimtex_buffers
|
||||||
|
autocmd! * <buffer>
|
||||||
|
autocmd BufFilePre <buffer> call s:filename_changed_pre()
|
||||||
|
autocmd BufFilePost <buffer> call s:filename_changed_post()
|
||||||
|
autocmd BufUnload <buffer> call s:buffer_deleted('unload')
|
||||||
|
autocmd BufWipeout <buffer> call s:buffer_deleted('wipe')
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
" Initialize buffer settings for sub modules
|
||||||
|
for l:mod in s:modules
|
||||||
|
if index(get(b:vimtex, 'disabled_modules', []), l:mod) >= 0 | continue | endif
|
||||||
|
|
||||||
|
try
|
||||||
|
call vimtex#{l:mod}#init_buffer()
|
||||||
|
catch /E117.*#init_/
|
||||||
|
catch /E127.*vimtex#profile#/
|
||||||
|
endtry
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:init_default_mappings() abort " {{{1
|
||||||
|
if !g:vimtex_mappings_enabled | return | endif
|
||||||
|
|
||||||
|
function! s:map(mode, lhs, rhs, ...) abort
|
||||||
|
if !hasmapto(a:rhs, a:mode)
|
||||||
|
\ && index(get(g:vimtex_mappings_disable, a:mode, []), a:lhs) < 0
|
||||||
|
\ && (empty(maparg(a:lhs, a:mode)) || a:0 > 0)
|
||||||
|
silent execute a:mode . 'map <silent><nowait><buffer>' a:lhs a:rhs
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call s:map('n', '<localleader>li', '<plug>(vimtex-info)')
|
||||||
|
call s:map('n', '<localleader>lI', '<plug>(vimtex-info-full)')
|
||||||
|
call s:map('n', '<localleader>lx', '<plug>(vimtex-reload)')
|
||||||
|
call s:map('n', '<localleader>lX', '<plug>(vimtex-reload-state)')
|
||||||
|
call s:map('n', '<localleader>ls', '<plug>(vimtex-toggle-main)')
|
||||||
|
call s:map('n', '<localleader>lq', '<plug>(vimtex-log)')
|
||||||
|
|
||||||
|
call s:map('n', 'ds$', '<plug>(vimtex-env-delete-math)')
|
||||||
|
call s:map('n', 'cs$', '<plug>(vimtex-env-change-math)')
|
||||||
|
call s:map('n', 'dse', '<plug>(vimtex-env-delete)')
|
||||||
|
call s:map('n', 'cse', '<plug>(vimtex-env-change)')
|
||||||
|
call s:map('n', 'tse', '<plug>(vimtex-env-toggle-star)')
|
||||||
|
|
||||||
|
call s:map('n', 'dsc', '<plug>(vimtex-cmd-delete)')
|
||||||
|
call s:map('n', 'csc', '<plug>(vimtex-cmd-change)')
|
||||||
|
call s:map('n', 'tsc', '<plug>(vimtex-cmd-toggle-star)')
|
||||||
|
call s:map('n', 'tsf', '<plug>(vimtex-cmd-toggle-frac)')
|
||||||
|
call s:map('x', 'tsf', '<plug>(vimtex-cmd-toggle-frac)')
|
||||||
|
call s:map('i', '<F7>', '<plug>(vimtex-cmd-create)')
|
||||||
|
call s:map('n', '<F7>', '<plug>(vimtex-cmd-create)')
|
||||||
|
call s:map('x', '<F7>', '<plug>(vimtex-cmd-create)')
|
||||||
|
|
||||||
|
call s:map('n', 'dsd', '<plug>(vimtex-delim-delete)')
|
||||||
|
call s:map('n', 'csd', '<plug>(vimtex-delim-change-math)')
|
||||||
|
call s:map('n', 'tsd', '<plug>(vimtex-delim-toggle-modifier)')
|
||||||
|
call s:map('x', 'tsd', '<plug>(vimtex-delim-toggle-modifier)')
|
||||||
|
call s:map('n', 'tsD', '<plug>(vimtex-delim-toggle-modifier-reverse)')
|
||||||
|
call s:map('x', 'tsD', '<plug>(vimtex-delim-toggle-modifier-reverse)')
|
||||||
|
call s:map('i', ']]', '<plug>(vimtex-delim-close)')
|
||||||
|
|
||||||
|
if g:vimtex_compiler_enabled
|
||||||
|
call s:map('n', '<localleader>ll', '<plug>(vimtex-compile)')
|
||||||
|
call s:map('n', '<localleader>lo', '<plug>(vimtex-compile-output)')
|
||||||
|
call s:map('n', '<localleader>lL', '<plug>(vimtex-compile-selected)')
|
||||||
|
call s:map('x', '<localleader>lL', '<plug>(vimtex-compile-selected)')
|
||||||
|
call s:map('n', '<localleader>lk', '<plug>(vimtex-stop)')
|
||||||
|
call s:map('n', '<localleader>lK', '<plug>(vimtex-stop-all)')
|
||||||
|
call s:map('n', '<localleader>le', '<plug>(vimtex-errors)')
|
||||||
|
call s:map('n', '<localleader>lc', '<plug>(vimtex-clean)')
|
||||||
|
call s:map('n', '<localleader>lC', '<plug>(vimtex-clean-full)')
|
||||||
|
call s:map('n', '<localleader>lg', '<plug>(vimtex-status)')
|
||||||
|
call s:map('n', '<localleader>lG', '<plug>(vimtex-status-all)')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:vimtex_motion_enabled
|
||||||
|
" These are forced in order to overwrite matchit mappings
|
||||||
|
call s:map('n', '%', '<plug>(vimtex-%)', 1)
|
||||||
|
call s:map('x', '%', '<plug>(vimtex-%)', 1)
|
||||||
|
call s:map('o', '%', '<plug>(vimtex-%)', 1)
|
||||||
|
|
||||||
|
call s:map('n', ']]', '<plug>(vimtex-]])')
|
||||||
|
call s:map('n', '][', '<plug>(vimtex-][)')
|
||||||
|
call s:map('n', '[]', '<plug>(vimtex-[])')
|
||||||
|
call s:map('n', '[[', '<plug>(vimtex-[[)')
|
||||||
|
call s:map('x', ']]', '<plug>(vimtex-]])')
|
||||||
|
call s:map('x', '][', '<plug>(vimtex-][)')
|
||||||
|
call s:map('x', '[]', '<plug>(vimtex-[])')
|
||||||
|
call s:map('x', '[[', '<plug>(vimtex-[[)')
|
||||||
|
call s:map('o', ']]', '<plug>(vimtex-]])')
|
||||||
|
call s:map('o', '][', '<plug>(vimtex-][)')
|
||||||
|
call s:map('o', '[]', '<plug>(vimtex-[])')
|
||||||
|
call s:map('o', '[[', '<plug>(vimtex-[[)')
|
||||||
|
|
||||||
|
call s:map('n', ']M', '<plug>(vimtex-]M)')
|
||||||
|
call s:map('n', ']m', '<plug>(vimtex-]m)')
|
||||||
|
call s:map('n', '[M', '<plug>(vimtex-[M)')
|
||||||
|
call s:map('n', '[m', '<plug>(vimtex-[m)')
|
||||||
|
call s:map('x', ']M', '<plug>(vimtex-]M)')
|
||||||
|
call s:map('x', ']m', '<plug>(vimtex-]m)')
|
||||||
|
call s:map('x', '[M', '<plug>(vimtex-[M)')
|
||||||
|
call s:map('x', '[m', '<plug>(vimtex-[m)')
|
||||||
|
call s:map('o', ']M', '<plug>(vimtex-]M)')
|
||||||
|
call s:map('o', ']m', '<plug>(vimtex-]m)')
|
||||||
|
call s:map('o', '[M', '<plug>(vimtex-[M)')
|
||||||
|
call s:map('o', '[m', '<plug>(vimtex-[m)')
|
||||||
|
|
||||||
|
call s:map('n', ']/', '<plug>(vimtex-]/)')
|
||||||
|
call s:map('n', ']*', '<plug>(vimtex-]*)')
|
||||||
|
call s:map('n', '[/', '<plug>(vimtex-[/)')
|
||||||
|
call s:map('n', '[*', '<plug>(vimtex-[*)')
|
||||||
|
call s:map('x', ']/', '<plug>(vimtex-]/)')
|
||||||
|
call s:map('x', ']*', '<plug>(vimtex-]*)')
|
||||||
|
call s:map('x', '[/', '<plug>(vimtex-[/)')
|
||||||
|
call s:map('x', '[*', '<plug>(vimtex-[*)')
|
||||||
|
call s:map('o', ']/', '<plug>(vimtex-]/)')
|
||||||
|
call s:map('o', ']*', '<plug>(vimtex-]*)')
|
||||||
|
call s:map('o', '[/', '<plug>(vimtex-[/)')
|
||||||
|
call s:map('o', '[*', '<plug>(vimtex-[*)')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:vimtex_text_obj_enabled
|
||||||
|
call s:map('x', 'id', '<plug>(vimtex-id)')
|
||||||
|
call s:map('x', 'ad', '<plug>(vimtex-ad)')
|
||||||
|
call s:map('o', 'id', '<plug>(vimtex-id)')
|
||||||
|
call s:map('o', 'ad', '<plug>(vimtex-ad)')
|
||||||
|
call s:map('x', 'i$', '<plug>(vimtex-i$)')
|
||||||
|
call s:map('x', 'a$', '<plug>(vimtex-a$)')
|
||||||
|
call s:map('o', 'i$', '<plug>(vimtex-i$)')
|
||||||
|
call s:map('o', 'a$', '<plug>(vimtex-a$)')
|
||||||
|
call s:map('x', 'iP', '<plug>(vimtex-iP)')
|
||||||
|
call s:map('x', 'aP', '<plug>(vimtex-aP)')
|
||||||
|
call s:map('o', 'iP', '<plug>(vimtex-iP)')
|
||||||
|
call s:map('o', 'aP', '<plug>(vimtex-aP)')
|
||||||
|
call s:map('x', 'im', '<plug>(vimtex-im)')
|
||||||
|
call s:map('x', 'am', '<plug>(vimtex-am)')
|
||||||
|
call s:map('o', 'im', '<plug>(vimtex-im)')
|
||||||
|
call s:map('o', 'am', '<plug>(vimtex-am)')
|
||||||
|
|
||||||
|
if vimtex#text_obj#targets#enabled()
|
||||||
|
call vimtex#text_obj#targets#init()
|
||||||
|
|
||||||
|
" These are handled explicitly to avoid conflict with gitgutter
|
||||||
|
call s:map('x', 'ic', '<plug>(vimtex-targets-i)c')
|
||||||
|
call s:map('x', 'ac', '<plug>(vimtex-targets-a)c')
|
||||||
|
call s:map('o', 'ic', '<plug>(vimtex-targets-i)c')
|
||||||
|
call s:map('o', 'ac', '<plug>(vimtex-targets-a)c')
|
||||||
|
else
|
||||||
|
if g:vimtex_text_obj_variant ==# 'targets'
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ "Ignoring g:vimtex_text_obj_variant = 'targets'"
|
||||||
|
\ . " because 'g:loaded_targets' does not exist or is 0.")
|
||||||
|
endif
|
||||||
|
let g:vimtex_text_obj_variant = 'vimtex'
|
||||||
|
|
||||||
|
call s:map('x', 'ie', '<plug>(vimtex-ie)')
|
||||||
|
call s:map('x', 'ae', '<plug>(vimtex-ae)')
|
||||||
|
call s:map('o', 'ie', '<plug>(vimtex-ie)')
|
||||||
|
call s:map('o', 'ae', '<plug>(vimtex-ae)')
|
||||||
|
call s:map('x', 'ic', '<plug>(vimtex-ic)')
|
||||||
|
call s:map('x', 'ac', '<plug>(vimtex-ac)')
|
||||||
|
call s:map('o', 'ic', '<plug>(vimtex-ic)')
|
||||||
|
call s:map('o', 'ac', '<plug>(vimtex-ac)')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:vimtex_toc_enabled
|
||||||
|
call s:map('n', '<localleader>lt', '<plug>(vimtex-toc-open)')
|
||||||
|
call s:map('n', '<localleader>lT', '<plug>(vimtex-toc-toggle)')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(b:vimtex, 'viewer')
|
||||||
|
call s:map('n', '<localleader>lv', '<plug>(vimtex-view)')
|
||||||
|
if has_key(b:vimtex.viewer, 'reverse_search')
|
||||||
|
call s:map('n', '<localleader>lr', '<plug>(vimtex-reverse-search)')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:vimtex_imaps_enabled
|
||||||
|
call s:map('n', '<localleader>lm', '<plug>(vimtex-imaps-list)')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:vimtex_doc_enabled
|
||||||
|
call s:map('n', 'K', '<plug>(vimtex-doc-package)')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:filename_changed_pre() abort " {{{1
|
||||||
|
let s:filename_changed = expand('%:p') ==# b:vimtex.tex
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:filename_changed_post() abort " {{{1
|
||||||
|
if s:filename_changed
|
||||||
|
let l:base_old = b:vimtex.base
|
||||||
|
let b:vimtex.tex = fnamemodify(expand('%'), ':p')
|
||||||
|
let b:vimtex.base = fnamemodify(b:vimtex.tex, ':t')
|
||||||
|
let b:vimtex.name = fnamemodify(b:vimtex.tex, ':t:r')
|
||||||
|
|
||||||
|
call vimtex#log#warning('Filename change detected')
|
||||||
|
call vimtex#log#info('Old filename: ' . l:base_old)
|
||||||
|
call vimtex#log#info('New filename: ' . b:vimtex.base)
|
||||||
|
|
||||||
|
if has_key(b:vimtex, 'compiler')
|
||||||
|
if b:vimtex.compiler.is_running()
|
||||||
|
call vimtex#log#warning('Compilation stopped!')
|
||||||
|
call vimtex#compiler#stop()
|
||||||
|
endif
|
||||||
|
let b:vimtex.compiler.target = b:vimtex.base
|
||||||
|
let b:vimtex.compiler.target_path = b:vimtex.tex
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:buffer_deleted(reason) abort " {{{1
|
||||||
|
"
|
||||||
|
" We need a simple cache of buffer ids because a buffer unload might clear
|
||||||
|
" buffer variables, so that a subsequent buffer wipe will not trigger a full
|
||||||
|
" cleanup. By caching the buffer id, we should avoid this issue.
|
||||||
|
"
|
||||||
|
let s:buffer_cache = get(s:, 'buffer_cache', {})
|
||||||
|
let l:file = expand('<afile>')
|
||||||
|
|
||||||
|
if !has_key(s:buffer_cache, l:file)
|
||||||
|
let s:buffer_cache[l:file] = getbufvar(l:file, 'vimtex_id', -1)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:reason ==# 'wipe'
|
||||||
|
call vimtex#state#cleanup(s:buffer_cache[l:file])
|
||||||
|
call remove(s:buffer_cache, l:file)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:quit() abort " {{{1
|
||||||
|
for l:state in vimtex#state#list_all()
|
||||||
|
call l:state.cleanup()
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call vimtex#cache#write_all()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
" {{{1 Initialize module
|
||||||
|
|
||||||
|
let s:modules = map(
|
||||||
|
\ glob(fnamemodify(expand('<sfile>'), ':r') . '/*.vim', 0, 1),
|
||||||
|
\ 'fnamemodify(v:val, '':t:r'')')
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
179
autoload/vimtex/cache.vim
Normal file
179
autoload/vimtex/cache.vim
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#cache#open(name, ...) abort " {{{1
|
||||||
|
let l:opts = a:0 > 0 ? a:1 : {}
|
||||||
|
let l:name = get(l:opts, 'local') ? s:local_name(a:name) : a:name
|
||||||
|
|
||||||
|
let s:caches = get(s:, 'caches', {})
|
||||||
|
if has_key(s:caches, l:name)
|
||||||
|
return s:caches[l:name]
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:caches[l:name] = s:cache.init(l:name, l:opts)
|
||||||
|
return s:caches[l:name]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cache#close(name) abort " {{{1
|
||||||
|
let s:caches = get(s:, 'caches', {})
|
||||||
|
|
||||||
|
" Try global name first, then local name
|
||||||
|
let l:name = a:name
|
||||||
|
if !has_key(s:caches, l:name)
|
||||||
|
let l:name = s:local_name(l:name)
|
||||||
|
endif
|
||||||
|
if !has_key(s:caches, l:name) | return | endif
|
||||||
|
|
||||||
|
let l:cache = s:caches[l:name]
|
||||||
|
call l:cache.write()
|
||||||
|
unlet s:caches[l:name]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cache#wrap(Func, name, ...) abort " {{{1
|
||||||
|
if !has('lambda')
|
||||||
|
throw 'error: vimtex#cache#wrap requires +lambda'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:opts = a:0 > 0 ? a:1 : {}
|
||||||
|
let l:cache = vimtex#cache#open(a:name, l:opts)
|
||||||
|
|
||||||
|
function! CachedFunc(key) closure
|
||||||
|
if l:cache.has(a:key)
|
||||||
|
return l:cache.get(a:key)
|
||||||
|
else
|
||||||
|
return l:cache.set(a:key, a:Func(a:key))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
return function('CachedFunc')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cache#clear(name, local) abort " {{{1
|
||||||
|
let l:cache = vimtex#cache#open(a:name, {'local': a:local})
|
||||||
|
|
||||||
|
call l:cache.read()
|
||||||
|
if !empty(l:cache.data)
|
||||||
|
let l:cache.data = {}
|
||||||
|
call l:cache.write()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cache#write_all() abort " {{{1
|
||||||
|
for l:cache in values(get(s:, 'caches', {}))
|
||||||
|
call l:cache.write()
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:cache = {}
|
||||||
|
|
||||||
|
function! s:cache.init(name, opts) dict abort " {{{1
|
||||||
|
let new = deepcopy(self)
|
||||||
|
unlet new.init
|
||||||
|
|
||||||
|
let l:root = get(g:, 'vimtex_cache_root', $HOME . '/.cache/vimtex')
|
||||||
|
if !isdirectory(l:root)
|
||||||
|
call mkdir(l:root, 'p')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let new.name = a:name
|
||||||
|
let new.path = l:root . '/' . a:name . '.json'
|
||||||
|
let new.local = get(a:opts, 'local')
|
||||||
|
let new.persistent = get(a:opts, 'persistent',
|
||||||
|
\ get(g:, 'vimtex_cache_persistent', 1))
|
||||||
|
|
||||||
|
if has_key(a:opts, 'default')
|
||||||
|
let new.default = a:opts.default
|
||||||
|
endif
|
||||||
|
|
||||||
|
let new.data = {}
|
||||||
|
let new.ftime = -1
|
||||||
|
let new.modified = 0
|
||||||
|
|
||||||
|
return new
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:cache.get(key) dict abort " {{{1
|
||||||
|
call self.read()
|
||||||
|
|
||||||
|
if has_key(self, 'default') && !has_key(self.data, a:key)
|
||||||
|
let self.data[a:key] = deepcopy(self.default)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return get(self.data, a:key)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:cache.has(key) dict abort " {{{1
|
||||||
|
call self.read()
|
||||||
|
|
||||||
|
return has_key(self.data, a:key)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:cache.set(key, value) dict abort " {{{1
|
||||||
|
call self.read()
|
||||||
|
|
||||||
|
let self.data[a:key] = a:value
|
||||||
|
let self.modified = 1
|
||||||
|
call self.write()
|
||||||
|
|
||||||
|
return a:value
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:cache.write() dict abort " {{{1
|
||||||
|
if !self.persistent
|
||||||
|
let self.modified = 0
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !self.modified | return | endif
|
||||||
|
|
||||||
|
call self.read()
|
||||||
|
call writefile([json_encode(self.data)], self.path)
|
||||||
|
let self.ftime = getftime(self.path)
|
||||||
|
let self.modified = 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:cache.read() dict abort " {{{1
|
||||||
|
if !self.persistent | return | endif
|
||||||
|
|
||||||
|
if getftime(self.path) > self.ftime
|
||||||
|
let self.ftime = getftime(self.path)
|
||||||
|
call extend(self.data,
|
||||||
|
\ json_decode(join(readfile(self.path))), 'keep')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Utility functions
|
||||||
|
"
|
||||||
|
function! s:local_name(name) abort " {{{1
|
||||||
|
let l:filename = exists('b:vimtex.tex')
|
||||||
|
\ ? fnamemodify(b:vimtex.tex, ':r')
|
||||||
|
\ : expand('%:p:r')
|
||||||
|
let l:filename = substitute(l:filename, '\s\+', '_', 'g')
|
||||||
|
let l:filename = substitute(l:filename, '\/', '%', 'g')
|
||||||
|
let l:filename = substitute(l:filename, '\\', '%', 'g')
|
||||||
|
let l:filename = substitute(l:filename, ':', '%', 'g')
|
||||||
|
return a:name . l:filename
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
718
autoload/vimtex/cmd.vim
Normal file
718
autoload/vimtex/cmd.vim
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#cmd#init_buffer() abort " {{{1
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-delete)
|
||||||
|
\ :<c-u>call <sid>operator_setup('delete')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-change)
|
||||||
|
\ :<c-u>call <sid>operator_setup('change')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
inoremap <silent><buffer> <plug>(vimtex-cmd-create)
|
||||||
|
\ <c-r>=vimtex#cmd#create_insert()<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-create)
|
||||||
|
\ :<c-u>call <sid>operator_setup('create')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
xnoremap <silent><buffer> <plug>(vimtex-cmd-create)
|
||||||
|
\ :<c-u>call vimtex#cmd#create_visual()<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-toggle-star)
|
||||||
|
\ :<c-u>call <sid>operator_setup('toggle_star')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-toggle-frac)
|
||||||
|
\ :<c-u>call <sid>operator_setup('toggle_frac')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
xnoremap <silent><buffer> <plug>(vimtex-cmd-toggle-frac)
|
||||||
|
\ :<c-u>call vimtex#cmd#toggle_frac_visual()<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#cmd#change(new_name) abort " {{{1
|
||||||
|
let l:cmd = vimtex#cmd#get_current()
|
||||||
|
if empty(l:cmd) | return | endif
|
||||||
|
|
||||||
|
let l:old_name = l:cmd.name
|
||||||
|
let l:lnum = l:cmd.pos_start.lnum
|
||||||
|
let l:cnum = l:cmd.pos_start.cnum
|
||||||
|
|
||||||
|
" Get new command name
|
||||||
|
let l:new_name = substitute(a:new_name, '^\\', '', '')
|
||||||
|
if empty(l:new_name) | return | endif
|
||||||
|
|
||||||
|
" Update current position
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
if strlen(l:new_name) < strlen(l:old_name)
|
||||||
|
let l:col = searchpos('\\\k', 'bcnW')[1] + strlen(l:new_name)
|
||||||
|
if l:col < l:save_pos[2]
|
||||||
|
let l:save_pos[2] = l:col
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Perform the change
|
||||||
|
let l:line = getline(l:lnum)
|
||||||
|
call setline(l:lnum,
|
||||||
|
\ strpart(l:line, 0, l:cnum)
|
||||||
|
\ . l:new_name
|
||||||
|
\ . strpart(l:line, l:cnum + strlen(l:old_name) - 1))
|
||||||
|
|
||||||
|
" Restore cursor position
|
||||||
|
cal vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimtex#cmd#delete(...) abort " {{{1
|
||||||
|
if a:0 > 0
|
||||||
|
let l:cmd = call('vimtex#cmd#get_at', a:000)
|
||||||
|
else
|
||||||
|
let l:cmd = vimtex#cmd#get_current()
|
||||||
|
endif
|
||||||
|
if empty(l:cmd) | return | endif
|
||||||
|
|
||||||
|
" Save current position
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
let l:lnum_cur = l:save_pos[1]
|
||||||
|
let l:cnum_cur = l:save_pos[2]
|
||||||
|
|
||||||
|
" Remove closing bracket (if exactly one argument)
|
||||||
|
if len(l:cmd.args) == 1
|
||||||
|
let l:lnum = l:cmd.args[0].close.lnum
|
||||||
|
let l:cnum = l:cmd.args[0].close.cnum
|
||||||
|
let l:line = getline(l:lnum)
|
||||||
|
call setline(l:lnum,
|
||||||
|
\ strpart(l:line, 0, l:cnum - 1)
|
||||||
|
\ . strpart(l:line, l:cnum))
|
||||||
|
|
||||||
|
let l:cnum2 = l:cmd.args[0].open.cnum
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Remove command (and possibly the opening bracket)
|
||||||
|
let l:lnum = l:cmd.pos_start.lnum
|
||||||
|
let l:cnum = l:cmd.pos_start.cnum
|
||||||
|
let l:cnum2 = get(l:, 'cnum2', l:cnum + strlen(l:cmd.name) - 1)
|
||||||
|
let l:line = getline(l:lnum)
|
||||||
|
call setline(l:lnum,
|
||||||
|
\ strpart(l:line, 0, l:cnum - 1)
|
||||||
|
\ . strpart(l:line, l:cnum2))
|
||||||
|
|
||||||
|
" Restore appropriate cursor position
|
||||||
|
if l:lnum_cur == l:lnum
|
||||||
|
if l:cnum_cur > l:cnum2
|
||||||
|
let l:save_pos[2] -= l:cnum2 - l:cnum + 1
|
||||||
|
else
|
||||||
|
let l:save_pos[2] -= l:cnum_cur - l:cnum
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
cal vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimtex#cmd#delete_all(...) abort " {{{1
|
||||||
|
if a:0 > 0
|
||||||
|
let l:cmd = call('vimtex#cmd#get_at', a:000)
|
||||||
|
else
|
||||||
|
let l:cmd = vimtex#cmd#get_current()
|
||||||
|
endif
|
||||||
|
if empty(l:cmd) | return | endif
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(l:cmd.pos_start)
|
||||||
|
normal! v
|
||||||
|
call vimtex#pos#set_cursor(l:cmd.pos_end)
|
||||||
|
normal! d
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimtex#cmd#create_insert() abort " {{{1
|
||||||
|
if mode() !=# 'i' | return | endif
|
||||||
|
|
||||||
|
let l:re = '\v%(^|\A)\zs\a+\ze%(\A|$)'
|
||||||
|
let l:c0 = col('.') - 1
|
||||||
|
|
||||||
|
let [l:l1, l:c1] = searchpos(l:re, 'bcn', line('.'))
|
||||||
|
let l:c1 -= 1
|
||||||
|
let l:line = getline(l:l1)
|
||||||
|
let l:match = matchstr(l:line, l:re, l:c1)
|
||||||
|
let l:c2 = l:c1 + strlen(l:match)
|
||||||
|
|
||||||
|
if l:c0 > l:c2
|
||||||
|
call vimtex#log#warning('Could not create command')
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:strpart1 = strpart(l:line, 0, l:c1)
|
||||||
|
let l:strpart2 = '\' . strpart(l:match, 0, l:c0 - l:c1) . '{'
|
||||||
|
let l:strpart3 = strpart(l:line, l:c0)
|
||||||
|
call setline(l:l1, l:strpart1 . l:strpart2 . l:strpart3)
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(l:l1, l:c2+3)
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#create(cmd, visualmode) abort " {{{1
|
||||||
|
if empty(a:cmd) | return | endif
|
||||||
|
|
||||||
|
" Avoid autoindent (disable indentkeys)
|
||||||
|
let l:save_indentkeys = &l:indentkeys
|
||||||
|
setlocal indentkeys=
|
||||||
|
|
||||||
|
if a:visualmode
|
||||||
|
let l:pos_start = getpos("'<")
|
||||||
|
let l:pos_end = getpos("'>")
|
||||||
|
|
||||||
|
if visualmode() ==# ''
|
||||||
|
normal! gvA}
|
||||||
|
execute 'normal! gvI\' . a:cmd . '{'
|
||||||
|
|
||||||
|
let l:pos_end[2] += strlen(a:cmd) + 3
|
||||||
|
else
|
||||||
|
normal! `>a}
|
||||||
|
normal! `<
|
||||||
|
execute 'normal! i\' . a:cmd . '{'
|
||||||
|
|
||||||
|
let l:pos_end[2] +=
|
||||||
|
\ l:pos_end[1] == l:pos_start[1] ? strlen(a:cmd) + 3 : 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(l:pos_end)
|
||||||
|
else
|
||||||
|
let l:pos = vimtex#pos#get_cursor()
|
||||||
|
let l:save_reg = getreg('"')
|
||||||
|
let l:pos[2] += strlen(a:cmd) + 2
|
||||||
|
execute 'normal! ciw\' . a:cmd . '{"}'
|
||||||
|
call setreg('"', l:save_reg)
|
||||||
|
call vimtex#pos#set_cursor(l:pos)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Restore indentkeys setting
|
||||||
|
let &l:indentkeys = l:save_indentkeys
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#create_visual() abort " {{{1
|
||||||
|
let l:cmd = vimtex#echo#input({
|
||||||
|
\ 'info' :
|
||||||
|
\ ['Create command: ', ['VimtexWarning', '(empty to cancel)']],
|
||||||
|
\})
|
||||||
|
let l:cmd = substitute(l:cmd, '^\\', '', '')
|
||||||
|
call vimtex#cmd#create(l:cmd, 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#toggle_star() abort " {{{1
|
||||||
|
let l:cmd = vimtex#cmd#get_current()
|
||||||
|
if empty(l:cmd) | return | endif
|
||||||
|
|
||||||
|
let l:old_name = l:cmd.name
|
||||||
|
let l:lnum = l:cmd.pos_start.lnum
|
||||||
|
let l:cnum = l:cmd.pos_start.cnum
|
||||||
|
|
||||||
|
" Set new command name
|
||||||
|
if match(l:old_name, '\*$') == -1
|
||||||
|
let l:new_name = l:old_name.'*'
|
||||||
|
else
|
||||||
|
let l:new_name = strpart(l:old_name, 0, strlen(l:old_name)-1)
|
||||||
|
endif
|
||||||
|
let l:new_name = substitute(l:new_name, '^\\', '', '')
|
||||||
|
if empty(l:new_name) | return | endif
|
||||||
|
|
||||||
|
" Update current position
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
let l:save_pos[2] += strlen(l:new_name) - strlen(l:old_name) + 1
|
||||||
|
|
||||||
|
" Perform the change
|
||||||
|
let l:line = getline(l:lnum)
|
||||||
|
call setline(l:lnum,
|
||||||
|
\ strpart(l:line, 0, l:cnum)
|
||||||
|
\ . l:new_name
|
||||||
|
\ . strpart(l:line, l:cnum + strlen(l:old_name) - 1))
|
||||||
|
|
||||||
|
" Restore cursor position
|
||||||
|
cal vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#toggle_frac() abort " {{{1
|
||||||
|
let l:frac = s:get_frac_cmd()
|
||||||
|
if empty(l:frac)
|
||||||
|
let l:frac = s:get_frac_inline()
|
||||||
|
endif
|
||||||
|
if empty(l:frac) | return | endif
|
||||||
|
|
||||||
|
let l:lnum = line('.')
|
||||||
|
let l:line = getline(l:lnum)
|
||||||
|
call setline(l:lnum,
|
||||||
|
\ strpart(l:line, 0, l:frac.col_start)
|
||||||
|
\ . l:frac.text_toggled
|
||||||
|
\ . strpart(l:line, l:frac.col_end+1))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#toggle_frac_visual() abort " {{{1
|
||||||
|
let l:save_reg = getreg('a')
|
||||||
|
normal! gv"ay
|
||||||
|
let l:selected = substitute(getreg('a'), '\n\s*', ' ', '')
|
||||||
|
call setreg('a', l:save_reg)
|
||||||
|
|
||||||
|
let l:frac = s:get_frac_inline_visual(l:selected)
|
||||||
|
if empty(l:frac)
|
||||||
|
let l:frac = s:get_frac_cmd_visual(l:selected)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if empty(l:frac) | return | endif
|
||||||
|
|
||||||
|
let l:save_reg = getreg('a')
|
||||||
|
call setreg('a', l:frac.text_toggled)
|
||||||
|
normal! gv"ap
|
||||||
|
call setreg('a', l:save_reg)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:get_frac_cmd() abort " {{{1
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
while v:true
|
||||||
|
let l:cmd = s:get_cmd('prev')
|
||||||
|
if empty(l:cmd) || l:cmd.pos_start.lnum < line('.')
|
||||||
|
call vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
return {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:cmd.name ==# '\frac'
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(vimtex#pos#prev(l:cmd.pos_start))
|
||||||
|
endwhile
|
||||||
|
call vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
|
||||||
|
let l:frac = {
|
||||||
|
\ 'type': 'cmd',
|
||||||
|
\ 'col_start': l:cmd.pos_start.cnum - 1,
|
||||||
|
\ 'col_end': l:cmd.pos_end.cnum - 1,
|
||||||
|
\}
|
||||||
|
|
||||||
|
if len(l:cmd.args) >= 2
|
||||||
|
let l:consume = []
|
||||||
|
let l:frac.denominator = l:cmd.args[0].text
|
||||||
|
let l:frac.numerator = l:cmd.args[1].text
|
||||||
|
elseif len(l:cmd.args) == 1
|
||||||
|
let l:consume = ['numerator']
|
||||||
|
let l:frac.denominator = l:cmd.args[0].text
|
||||||
|
let l:frac.numerator = ''
|
||||||
|
else
|
||||||
|
let l:consume = ['denominator', 'numerator']
|
||||||
|
let l:frac.denominator = ''
|
||||||
|
let l:frac.numerator = ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Handle unfinished cases
|
||||||
|
let l:line = getline('.')
|
||||||
|
let l:pos = l:frac.col_end + 1
|
||||||
|
for l:key in l:consume
|
||||||
|
let l:part = strpart(l:line, l:frac.col_end + 1)
|
||||||
|
|
||||||
|
let l:blurp = matchstr(l:part, '^\s*{[^}]*}')
|
||||||
|
if !empty(l:blurp)
|
||||||
|
let l:frac[l:key] = vimtex#util#trim(l:blurp)[1:-2]
|
||||||
|
let l:frac.col_end += len(l:blurp)
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:blurp = matchstr(l:part, '^\s*\w')
|
||||||
|
if !empty(l:blurp)
|
||||||
|
let l:frac[l:key] = vimtex#util#trim(l:blurp)
|
||||||
|
let l:frac.col_end += len(l:blurp)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Abort if \frac region does not cover cursor
|
||||||
|
if l:frac.col_end < col('.') | return {} | endif
|
||||||
|
|
||||||
|
let l:frac.text = strpart(getline('.'),
|
||||||
|
\ l:frac.col_start, l:frac.col_end - l:frac.col_start + 1)
|
||||||
|
|
||||||
|
return s:get_frac_cmd_aux(l:frac)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_frac_cmd_visual(selected) abort " {{{1
|
||||||
|
let l:matches = matchlist(a:selected, '^\s*\\frac\s*{\(.*\)}\s*{\(.*\)}\s*$')
|
||||||
|
if empty(l:matches) | return {} | endif
|
||||||
|
|
||||||
|
let l:frac = {
|
||||||
|
\ 'type': 'cmd',
|
||||||
|
\ 'text': a:selected,
|
||||||
|
\ 'denominator': l:matches[1],
|
||||||
|
\ 'numerator': l:matches[2],
|
||||||
|
\}
|
||||||
|
|
||||||
|
return s:get_frac_cmd_aux(l:frac)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_frac_cmd_aux(frac) abort " {{{1
|
||||||
|
let l:denominator = (a:frac.denominator =~# '^\\\?\w*$')
|
||||||
|
\ ? a:frac.denominator
|
||||||
|
\ : '(' . a:frac.denominator . ')'
|
||||||
|
|
||||||
|
let l:numerator = (a:frac.numerator =~# '^\\\?\w*$')
|
||||||
|
\ ? a:frac.numerator
|
||||||
|
\ : '(' . a:frac.numerator . ')'
|
||||||
|
|
||||||
|
let a:frac.text_toggled = l:denominator . '/' . l:numerator
|
||||||
|
|
||||||
|
return a:frac
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_frac_inline() abort " {{{1
|
||||||
|
let l:line = getline('.')
|
||||||
|
let l:col = col('.') - 1
|
||||||
|
|
||||||
|
let l:pos_after = -1
|
||||||
|
let l:pos_before = -1
|
||||||
|
while v:true
|
||||||
|
let l:pos_before = l:pos_after
|
||||||
|
let l:pos_after = match(l:line, '\/', l:pos_after+1)
|
||||||
|
if l:pos_after < 0 || l:pos_after >= l:col | break | endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
if l:pos_after == -1 && l:pos_before == -1
|
||||||
|
return {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:positions = []
|
||||||
|
if l:pos_before > 0
|
||||||
|
let l:positions += [l:pos_before]
|
||||||
|
endif
|
||||||
|
if l:pos_after > 0
|
||||||
|
let l:positions += [l:pos_after]
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:pos in l:positions
|
||||||
|
let l:frac = {'type': 'inline'}
|
||||||
|
|
||||||
|
"
|
||||||
|
" Parse numerator
|
||||||
|
"
|
||||||
|
let l:before = strpart(l:line, 0, l:pos)
|
||||||
|
if l:before =~# ')\s*$'
|
||||||
|
let l:pos_before = s:get_inline_limit(l:before, -1) - 1
|
||||||
|
let l:parens = strpart(l:before, l:pos_before)
|
||||||
|
else
|
||||||
|
let l:pos_before = match(l:before, '\s*$')
|
||||||
|
let l:parens = ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:before = strpart(l:line, 0, l:pos_before)
|
||||||
|
let l:atoms = matchstr(l:before, '\(\\(\)\?\zs[^-$(){} ]*$')
|
||||||
|
let l:pos_before = l:pos_before - strlen(l:atoms)
|
||||||
|
let l:frac.numerator = s:get_inline_trim(l:atoms . l:parens)
|
||||||
|
let l:frac.col_start = l:pos_before
|
||||||
|
|
||||||
|
"
|
||||||
|
" Parse denominator
|
||||||
|
"
|
||||||
|
let l:after = strpart(l:line, l:pos+1)
|
||||||
|
let l:atoms = l:after =~# '^\s*[^$()} ]*\\)'
|
||||||
|
\ ? matchstr(l:after, '^\s*[^$()} ]*\ze\\)')
|
||||||
|
\ : matchstr(l:after, '^\s*[^$()} ]*')
|
||||||
|
let l:pos_after = l:pos + strlen(l:atoms)
|
||||||
|
let l:after = strpart(l:line, l:pos_after+1)
|
||||||
|
if l:after =~# '^('
|
||||||
|
let l:index = s:get_inline_limit(l:after, 1)
|
||||||
|
let l:pos_after = l:pos_after + l:index + 1
|
||||||
|
let l:parens = strpart(l:after, 0, l:index+1)
|
||||||
|
else
|
||||||
|
let l:parens = ''
|
||||||
|
endif
|
||||||
|
let l:frac.denominator = s:get_inline_trim(l:atoms . l:parens)
|
||||||
|
let l:frac.col_end = l:pos_after
|
||||||
|
|
||||||
|
"
|
||||||
|
" Combine/Parse inline and frac expressions
|
||||||
|
"
|
||||||
|
let l:frac.text = strpart(l:line,
|
||||||
|
\ l:frac.col_start,
|
||||||
|
\ l:frac.col_end - l:frac.col_start + 1)
|
||||||
|
let l:frac.text_toggled = printf('\frac{%s}{%s}',
|
||||||
|
\ l:frac.numerator, l:frac.denominator)
|
||||||
|
|
||||||
|
"
|
||||||
|
" Accept result if the range contains the cursor column
|
||||||
|
"
|
||||||
|
if l:col >= l:frac.col_start && l:col <= l:frac.col_end
|
||||||
|
return l:frac
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return {}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_frac_inline_visual(selected) abort " {{{1
|
||||||
|
let l:parts = split(a:selected, '/')
|
||||||
|
if len(l:parts) != 2 | return {} | endif
|
||||||
|
|
||||||
|
let l:frac = {
|
||||||
|
\ 'type': 'inline',
|
||||||
|
\ 'text': a:selected,
|
||||||
|
\ 'numerator': s:get_inline_trim(l:parts[0]),
|
||||||
|
\ 'denominator': s:get_inline_trim(l:parts[1]),
|
||||||
|
\}
|
||||||
|
|
||||||
|
let l:frac.text_toggled = printf('\frac{%s}{%s}',
|
||||||
|
\ l:frac.numerator, l:frac.denominator)
|
||||||
|
|
||||||
|
return l:frac
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_inline_limit(str, dir) abort " {{{1
|
||||||
|
if a:dir > 0
|
||||||
|
let l:open = '('
|
||||||
|
let l:string = a:str
|
||||||
|
else
|
||||||
|
let l:open = ')'
|
||||||
|
let l:string = join(reverse(split(a:str, '\zs')), '')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let idx = -1
|
||||||
|
let depth = 0
|
||||||
|
|
||||||
|
while idx < len(l:string)
|
||||||
|
let idx = match(l:string, '[()]', idx + 1)
|
||||||
|
if idx < 0
|
||||||
|
let idx = len(l:string)
|
||||||
|
endif
|
||||||
|
if idx >= len(l:string) || l:string[idx] ==# l:open
|
||||||
|
let depth += 1
|
||||||
|
else
|
||||||
|
let depth -= 1
|
||||||
|
if depth == 0
|
||||||
|
return a:dir < 0 ? len(a:str) - idx : idx
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return -1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_inline_trim(str) abort " {{{1
|
||||||
|
let l:str = vimtex#util#trim(a:str)
|
||||||
|
return substitute(l:str, '^(\(.*\))$', '\1', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#cmd#get_next() abort " {{{1
|
||||||
|
return s:get_cmd('next')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#get_prev() abort " {{{1
|
||||||
|
return s:get_cmd('prev')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#get_current() abort " {{{1
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
let l:pos_val_cursor = vimtex#pos#val(l:save_pos)
|
||||||
|
|
||||||
|
let l:depth = 3
|
||||||
|
while l:depth > 0
|
||||||
|
let l:depth -= 1
|
||||||
|
let l:cmd = s:get_cmd('prev')
|
||||||
|
if empty(l:cmd) | break | endif
|
||||||
|
|
||||||
|
let l:pos_val = vimtex#pos#val(l:cmd.pos_end)
|
||||||
|
if l:pos_val >= l:pos_val_cursor
|
||||||
|
call vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
return l:cmd
|
||||||
|
else
|
||||||
|
call vimtex#pos#set_cursor(vimtex#pos#prev(l:cmd.pos_start))
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
|
||||||
|
return {}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#cmd#get_at(...) abort " {{{1
|
||||||
|
let l:pos_saved = vimtex#pos#get_cursor()
|
||||||
|
call call('vimtex#pos#set_cursor', a:000)
|
||||||
|
let l:cmd = vimtex#cmd#get_current()
|
||||||
|
call vimtex#pos#set_cursor(l:pos_saved)
|
||||||
|
return l:cmd
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:operator_setup(operator) abort " {{{1
|
||||||
|
let s:operator = a:operator
|
||||||
|
let &opfunc = s:snr() . 'operator_function'
|
||||||
|
|
||||||
|
" Ask for user input if necessary/relevant
|
||||||
|
if s:operator ==# 'change'
|
||||||
|
let l:current = vimtex#cmd#get_current()
|
||||||
|
if empty(l:current) | return | endif
|
||||||
|
|
||||||
|
let s:operator_cmd_name = substitute(vimtex#echo#input({
|
||||||
|
\ 'info' : ['Change command: ', ['VimtexWarning', l:current.name]],
|
||||||
|
\}), '^\\', '', '')
|
||||||
|
elseif s:operator ==# 'create'
|
||||||
|
let s:operator_cmd_name = substitute(vimtex#echo#input({
|
||||||
|
\ 'info' : ['Create command: ', ['VimtexWarning', '(empty to cancel)']],
|
||||||
|
\}), '^\\', '', '')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:operator_function(_) abort " {{{1
|
||||||
|
let l:name = get(s:, 'operator_cmd_name', '')
|
||||||
|
|
||||||
|
execute 'call vimtex#cmd#' . {
|
||||||
|
\ 'change': 'change(l:name)',
|
||||||
|
\ 'create': 'create(l:name, 0)',
|
||||||
|
\ 'delete': 'delete()',
|
||||||
|
\ 'toggle_star': 'toggle_star()',
|
||||||
|
\ 'toggle_frac': 'toggle_frac()',
|
||||||
|
\ }[s:operator]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:snr() abort " {{{1
|
||||||
|
return matchstr(expand('<sfile>'), '<SNR>\d\+_')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:get_cmd(direction) abort " {{{1
|
||||||
|
let [lnum, cnum, match] = s:get_cmd_name(a:direction ==# 'next')
|
||||||
|
if lnum == 0 | return {} | endif
|
||||||
|
|
||||||
|
let res = {
|
||||||
|
\ 'name' : match,
|
||||||
|
\ 'text' : '',
|
||||||
|
\ 'pos_start' : { 'lnum' : lnum, 'cnum' : cnum },
|
||||||
|
\ 'pos_end' : { 'lnum' : lnum, 'cnum' : cnum + strlen(match) - 1 },
|
||||||
|
\ 'args' : [],
|
||||||
|
\}
|
||||||
|
|
||||||
|
" Environments always start with environment name and allows option
|
||||||
|
" afterwords
|
||||||
|
if res.name ==# '\begin'
|
||||||
|
let arg = s:get_cmd_part('{', res.pos_end)
|
||||||
|
if empty(arg) | return res | endif
|
||||||
|
|
||||||
|
call add(res.args, arg)
|
||||||
|
let res.pos_end.lnum = arg.close.lnum
|
||||||
|
let res.pos_end.cnum = arg.close.cnum
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Get overlay specification
|
||||||
|
let res.overlay = s:get_cmd_overlay(res.pos_end.lnum, res.pos_end.cnum)
|
||||||
|
if !empty(res.overlay)
|
||||||
|
let res.pos_end.lnum = res.overlay.close.lnum
|
||||||
|
let res.pos_end.cnum = res.overlay.close.cnum
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Get options
|
||||||
|
let res.opt = s:get_cmd_part('[', res.pos_end)
|
||||||
|
if !empty(res.opt)
|
||||||
|
let res.pos_end.lnum = res.opt.close.lnum
|
||||||
|
let res.pos_end.cnum = res.opt.close.cnum
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Get arguments
|
||||||
|
let arg = s:get_cmd_part('{', res.pos_end)
|
||||||
|
while !empty(arg)
|
||||||
|
call add(res.args, arg)
|
||||||
|
let res.pos_end.lnum = arg.close.lnum
|
||||||
|
let res.pos_end.cnum = arg.close.cnum
|
||||||
|
let arg = s:get_cmd_part('{', res.pos_end)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" Include entire cmd text
|
||||||
|
let res.text = s:text_between(res.pos_start, res.pos_end, 1)
|
||||||
|
|
||||||
|
return res
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_cmd_name(next) abort " {{{1
|
||||||
|
let [l:lnum, l:cnum] = searchpos('\v\\\a+\*?', a:next ? 'nW' : 'cbnW')
|
||||||
|
let l:match = matchstr(getline(l:lnum), '^\v\\\a*\*?', l:cnum-1)
|
||||||
|
return [l:lnum, l:cnum, l:match]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_cmd_part(part, start_pos) abort " {{{1
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
call vimtex#pos#set_cursor(a:start_pos)
|
||||||
|
let l:open = vimtex#delim#get_next('delim_tex', 'open')
|
||||||
|
call vimtex#pos#set_cursor(l:save_pos)
|
||||||
|
|
||||||
|
"
|
||||||
|
" Ensure that the delimiter
|
||||||
|
" 1) exists,
|
||||||
|
" 2) is of the right type,
|
||||||
|
" 3) and is the next non-whitespace character.
|
||||||
|
"
|
||||||
|
if empty(l:open)
|
||||||
|
\ || l:open.match !=# a:part
|
||||||
|
\ || strlen(substitute(
|
||||||
|
\ s:text_between(a:start_pos, l:open), '\_s', '', 'g')) != 0
|
||||||
|
return {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:close = vimtex#delim#get_matching(l:open)
|
||||||
|
if empty(l:close)
|
||||||
|
return {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'open' : l:open,
|
||||||
|
\ 'close' : l:close,
|
||||||
|
\ 'text' : s:text_between(l:open, l:close),
|
||||||
|
\}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_cmd_overlay(lnum, cnum) abort " {{{1
|
||||||
|
let l:match = matchstr(getline(a:lnum), '^\s*[^>]*>', a:cnum)
|
||||||
|
|
||||||
|
return empty(l:match)
|
||||||
|
\ ? {}
|
||||||
|
\ : {
|
||||||
|
\ 'open' : {'lnum' : a:lnum, 'cnum' : a:cnum + 1},
|
||||||
|
\ 'close' : {'lnum' : a:lnum, 'cnum' : a:cnum + strlen(l:match)},
|
||||||
|
\ 'text' : l:match
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:text_between(p1, p2, ...) abort " {{{1
|
||||||
|
let [l1, c1] = [a:p1.lnum, a:p1.cnum - (a:0 > 0)]
|
||||||
|
let [l2, c2] = [a:p2.lnum, a:p2.cnum - (a:0 <= 0)]
|
||||||
|
|
||||||
|
let lines = getline(l1, l2)
|
||||||
|
if !empty(lines)
|
||||||
|
let lines[0] = strpart(lines[0], c1)
|
||||||
|
let lines[-1] = strpart(lines[-1], 0,
|
||||||
|
\ l1 == l2 ? c2 - c1 : c2)
|
||||||
|
endif
|
||||||
|
return join(lines, "\n")
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
334
autoload/vimtex/compiler.vim
Normal file
334
autoload/vimtex/compiler.vim
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#compiler#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_compiler_enabled | return | endif
|
||||||
|
|
||||||
|
" Define commands
|
||||||
|
command! -buffer VimtexCompile call vimtex#compiler#compile()
|
||||||
|
command! -buffer -bang VimtexCompileSS call vimtex#compiler#compile_ss()
|
||||||
|
command! -buffer -range VimtexCompileSelected <line1>,<line2>call vimtex#compiler#compile_selected('cmd')
|
||||||
|
command! -buffer VimtexCompileOutput call vimtex#compiler#output()
|
||||||
|
command! -buffer VimtexStop call vimtex#compiler#stop()
|
||||||
|
command! -buffer VimtexStopAll call vimtex#compiler#stop_all()
|
||||||
|
command! -buffer -bang VimtexClean call vimtex#compiler#clean(<q-bang> == "!")
|
||||||
|
command! -buffer -bang VimtexStatus call vimtex#compiler#status(<q-bang> == "!")
|
||||||
|
|
||||||
|
" Define mappings
|
||||||
|
nnoremap <buffer> <plug>(vimtex-compile) :call vimtex#compiler#compile()<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-compile-ss) :call vimtex#compiler#compile_ss()<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-compile-selected) :set opfunc=vimtex#compiler#compile_selected<cr>g@
|
||||||
|
xnoremap <buffer> <plug>(vimtex-compile-selected) :<c-u>call vimtex#compiler#compile_selected('visual')<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-compile-output) :call vimtex#compiler#output()<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-stop) :call vimtex#compiler#stop()<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-stop-all) :call vimtex#compiler#stop_all()<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-clean) :call vimtex#compiler#clean(0)<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-clean-full) :call vimtex#compiler#clean(1)<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-status) :call vimtex#compiler#status(0)<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-status-all) :call vimtex#compiler#status(1)<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#init_state(state) abort " {{{1
|
||||||
|
if !g:vimtex_compiler_enabled | return | endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:options = {
|
||||||
|
\ 'root': a:state.root,
|
||||||
|
\ 'target' : a:state.base,
|
||||||
|
\ 'target_path' : a:state.tex,
|
||||||
|
\ 'tex_program' : a:state.tex_program,
|
||||||
|
\}
|
||||||
|
let a:state.compiler
|
||||||
|
\ = vimtex#compiler#{g:vimtex_compiler_method}#init(l:options)
|
||||||
|
catch /vimtex: Requirements not met/
|
||||||
|
call vimtex#log#error('Compiler was not initialized!')
|
||||||
|
catch /E117/
|
||||||
|
call vimtex#log#error(
|
||||||
|
\ 'Invalid compiler: ' . g:vimtex_compiler_method,
|
||||||
|
\ 'Please see :h g:vimtex_compiler_method')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#compiler#callback(status) abort " {{{1
|
||||||
|
if exists('b:vimtex') && get(b:vimtex.compiler, 'silence_next_callback')
|
||||||
|
let b:vimtex.compiler.silence_next_callback = 0
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#qf#open(0)
|
||||||
|
redraw
|
||||||
|
|
||||||
|
if exists('s:output')
|
||||||
|
call s:output.update()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:status
|
||||||
|
call vimtex#log#info('Compilation completed')
|
||||||
|
else
|
||||||
|
call vimtex#log#warning('Compilation failed!')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:status && exists('b:vimtex')
|
||||||
|
call b:vimtex.parse_packages()
|
||||||
|
call vimtex#syntax#load#packages()
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:hook in g:vimtex_compiler_callback_hooks
|
||||||
|
if exists('*' . l:hook)
|
||||||
|
execute 'call' l:hook . '(' . a:status . ')'
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#compiler#compile() abort " {{{1
|
||||||
|
if get(b:vimtex.compiler, 'continuous')
|
||||||
|
if b:vimtex.compiler.is_running()
|
||||||
|
call vimtex#compiler#stop()
|
||||||
|
else
|
||||||
|
call b:vimtex.compiler.start()
|
||||||
|
let b:vimtex.compiler.check_timer = s:check_if_running_start()
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
call b:vimtex.compiler.start_single()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#compile_ss() abort " {{{1
|
||||||
|
call b:vimtex.compiler.start_single()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#compile_selected(type) abort range " {{{1
|
||||||
|
let l:file = vimtex#parser#selection_to_texfile(a:type)
|
||||||
|
if empty(l:file) | return | endif
|
||||||
|
|
||||||
|
" Create and initialize temporary compiler
|
||||||
|
let l:options = {
|
||||||
|
\ 'root' : l:file.root,
|
||||||
|
\ 'target' : l:file.base,
|
||||||
|
\ 'target_path' : l:file.tex,
|
||||||
|
\ 'backend' : 'process',
|
||||||
|
\ 'tex_program' : b:vimtex.tex_program,
|
||||||
|
\ 'background' : 1,
|
||||||
|
\ 'continuous' : 0,
|
||||||
|
\ 'callback' : 0,
|
||||||
|
\}
|
||||||
|
let l:compiler = vimtex#compiler#{g:vimtex_compiler_method}#init(l:options)
|
||||||
|
|
||||||
|
call vimtex#log#toggle_verbose()
|
||||||
|
call l:compiler.start()
|
||||||
|
|
||||||
|
" Check if successful
|
||||||
|
if vimtex#qf#inquire(l:file.base)
|
||||||
|
call vimtex#log#toggle_verbose()
|
||||||
|
call vimtex#log#warning('Compiling selected lines ... failed!')
|
||||||
|
botright cwindow
|
||||||
|
return
|
||||||
|
else
|
||||||
|
call l:compiler.clean(0)
|
||||||
|
call b:vimtex.viewer.view(l:file.pdf)
|
||||||
|
call vimtex#log#toggle_verbose()
|
||||||
|
call vimtex#log#info('Compiling selected lines ... done')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#output() abort " {{{1
|
||||||
|
let l:file = get(b:vimtex.compiler, 'output', '')
|
||||||
|
if empty(l:file)
|
||||||
|
call vimtex#log#warning('No output exists!')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" If window already open, then go there
|
||||||
|
if exists('s:output')
|
||||||
|
if bufwinnr(l:file) == s:output.winnr
|
||||||
|
execute s:output.winnr . 'wincmd w'
|
||||||
|
return
|
||||||
|
else
|
||||||
|
call s:output.destroy()
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Create new output window
|
||||||
|
silent execute 'split' l:file
|
||||||
|
|
||||||
|
" Create the output object
|
||||||
|
let s:output = {}
|
||||||
|
let s:output.name = l:file
|
||||||
|
let s:output.bufnr = bufnr('%')
|
||||||
|
let s:output.winnr = bufwinnr('%')
|
||||||
|
function! s:output.update() dict abort
|
||||||
|
if bufwinnr(self.name) != self.winnr
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if mode() ==? 'v' || mode() ==# "\<c-v>"
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Go to last line of file if it is not the current window
|
||||||
|
if bufwinnr('%') != self.winnr
|
||||||
|
let l:return = bufwinnr('%')
|
||||||
|
execute 'keepalt' self.winnr . 'wincmd w'
|
||||||
|
edit
|
||||||
|
normal! Gzb
|
||||||
|
execute 'keepalt' l:return . 'wincmd w'
|
||||||
|
redraw
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
function! s:output.destroy() dict abort
|
||||||
|
autocmd! vimtex_output_window
|
||||||
|
augroup! vimtex_output_window
|
||||||
|
unlet s:output
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Better automatic update
|
||||||
|
augroup vimtex_output_window
|
||||||
|
autocmd!
|
||||||
|
autocmd BufDelete <buffer> call s:output.destroy()
|
||||||
|
autocmd BufEnter * call s:output.update()
|
||||||
|
autocmd FocusGained * call s:output.update()
|
||||||
|
autocmd CursorHold * call s:output.update()
|
||||||
|
autocmd CursorHoldI * call s:output.update()
|
||||||
|
autocmd CursorMoved * call s:output.update()
|
||||||
|
autocmd CursorMovedI * call s:output.update()
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
" Set some mappings
|
||||||
|
nnoremap <silent><nowait><buffer> q :bwipeout<cr>
|
||||||
|
if has('nvim') || has('gui_running')
|
||||||
|
nnoremap <silent><nowait><buffer> <esc> :bwipeout<cr>
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Set some buffer options
|
||||||
|
setlocal autoread
|
||||||
|
setlocal nomodifiable
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#stop() abort " {{{1
|
||||||
|
call b:vimtex.compiler.stop()
|
||||||
|
silent! call timer_stop(b:vimtex.compiler.check_timer)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#stop_all() abort " {{{1
|
||||||
|
for l:state in vimtex#state#list_all()
|
||||||
|
if exists('l:state.compiler.is_running')
|
||||||
|
\ && l:state.compiler.is_running()
|
||||||
|
call l:state.compiler.stop()
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#clean(full) abort " {{{1
|
||||||
|
call b:vimtex.compiler.clean(a:full)
|
||||||
|
|
||||||
|
if empty(b:vimtex.compiler.build_dir) | return | endif
|
||||||
|
sleep 100m
|
||||||
|
|
||||||
|
" Remove auxilliary output directories if they are empty
|
||||||
|
let l:build_dir = (vimtex#paths#is_abs(b:vimtex.compiler.build_dir)
|
||||||
|
\ ? '' : b:vimtex.root . '/')
|
||||||
|
\ . b:vimtex.compiler.build_dir
|
||||||
|
let l:tree = glob(l:build_dir . '/**/*', 0, 1)
|
||||||
|
let l:files = filter(copy(l:tree), 'filereadable(v:val)')
|
||||||
|
if !empty(l:files) | return | endif
|
||||||
|
|
||||||
|
for l:dir in sort(l:tree) + [l:build_dir]
|
||||||
|
call delete(l:dir, 'd')
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#status(detailed) abort " {{{1
|
||||||
|
if a:detailed
|
||||||
|
let l:running = []
|
||||||
|
for l:data in vimtex#state#list_all()
|
||||||
|
if l:data.compiler.is_running()
|
||||||
|
let l:name = l:data.tex
|
||||||
|
if len(l:name) >= winwidth('.') - 20
|
||||||
|
let l:name = '...' . l:name[-winwidth('.')+23:]
|
||||||
|
endif
|
||||||
|
call add(l:running, printf('%-6s %s',
|
||||||
|
\ string(l:data.compiler.get_pid()) . ':', l:name))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if empty(l:running)
|
||||||
|
call vimtex#log#warning('Compiler is not running!')
|
||||||
|
else
|
||||||
|
call vimtex#log#info('Compiler is running', l:running)
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
if b:vimtex.compiler.is_running()
|
||||||
|
call vimtex#log#info('Compiler is running')
|
||||||
|
else
|
||||||
|
call vimtex#log#warning('Compiler is not running!')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:check_timers = {}
|
||||||
|
function! s:check_if_running_start() abort " {{{1
|
||||||
|
if !exists('*timer_start') | return -1 | endif
|
||||||
|
|
||||||
|
let l:timer = timer_start(50, function('s:check_if_running'), {'repeat': 20})
|
||||||
|
|
||||||
|
let s:check_timers[l:timer] = {
|
||||||
|
\ 'compiler' : b:vimtex.compiler,
|
||||||
|
\ 'vimtex_id' : b:vimtex_id,
|
||||||
|
\}
|
||||||
|
|
||||||
|
return l:timer
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:check_if_running(timer) abort " {{{1
|
||||||
|
if s:check_timers[a:timer].compiler.is_running() | return | endif
|
||||||
|
|
||||||
|
call timer_stop(a:timer)
|
||||||
|
|
||||||
|
if get(b:, 'vimtex_id', -1) == s:check_timers[a:timer].vimtex_id
|
||||||
|
call vimtex#compiler#output()
|
||||||
|
endif
|
||||||
|
call vimtex#log#error('Compiler did not start successfully!')
|
||||||
|
|
||||||
|
unlet s:check_timers[a:timer].compiler.check_timer
|
||||||
|
unlet s:check_timers[a:timer]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
" {{{1 Initialize module
|
||||||
|
|
||||||
|
if !g:vimtex_compiler_enabled | finish | endif
|
||||||
|
|
||||||
|
augroup vimtex_compiler
|
||||||
|
autocmd!
|
||||||
|
autocmd VimLeave * call vimtex#compiler#stop_all()
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
218
autoload/vimtex/compiler/arara.vim
Normal file
218
autoload/vimtex/compiler/arara.vim
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#compiler#arara#init(options) abort " {{{1
|
||||||
|
let l:compiler = deepcopy(s:compiler)
|
||||||
|
|
||||||
|
call l:compiler.init(extend(a:options,
|
||||||
|
\ get(g:, 'vimtex_compiler_arara', {}), 'keep'))
|
||||||
|
|
||||||
|
return l:compiler
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler = {
|
||||||
|
\ 'name' : 'arara',
|
||||||
|
\ 'backend' : has('nvim') ? 'nvim'
|
||||||
|
\ : v:version >= 800 ? 'jobs' : 'process',
|
||||||
|
\ 'root' : '',
|
||||||
|
\ 'target' : '',
|
||||||
|
\ 'target_path' : '',
|
||||||
|
\ 'background' : 1,
|
||||||
|
\ 'output' : tempname(),
|
||||||
|
\ 'options' : ['--log'],
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:compiler.init(options) abort dict " {{{1
|
||||||
|
call extend(self, a:options)
|
||||||
|
|
||||||
|
if !executable('arara')
|
||||||
|
call vimtex#log#warning('arara is not executable!')
|
||||||
|
throw 'vimtex: Requirements not met'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call extend(self, deepcopy(s:compiler_{self.backend}))
|
||||||
|
|
||||||
|
" Processes run with the new jobs api will not run in the foreground
|
||||||
|
if self.backend !=# 'process'
|
||||||
|
let self.background = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.build_cmd() abort dict " {{{1
|
||||||
|
let l:cmd = 'arara'
|
||||||
|
|
||||||
|
for l:opt in self.options
|
||||||
|
let l:cmd .= ' ' . l:opt
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:cmd . ' ' . vimtex#util#shellescape(self.target)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.cleanup() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.pprint_items() abort dict " {{{1
|
||||||
|
let l:configuration = []
|
||||||
|
|
||||||
|
if self.backend ==# 'process'
|
||||||
|
call add(l:configuration, ['background', self.background])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:configuration, ['arara options', self.options])
|
||||||
|
|
||||||
|
let l:list = []
|
||||||
|
call add(l:list, ['backend', self.backend])
|
||||||
|
if self.background
|
||||||
|
call add(l:list, ['output', self.output])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.target_path !=# b:vimtex.tex
|
||||||
|
call add(l:list, ['root', self.root])
|
||||||
|
call add(l:list, ['target', self.target_path])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:list, ['configuration', l:configuration])
|
||||||
|
|
||||||
|
if has_key(self, 'process')
|
||||||
|
call add(l:list, ['process', self.process])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(self, 'job')
|
||||||
|
call add(l:list, ['cmd', self.cmd])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:list
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.clean(...) abort dict " {{{1
|
||||||
|
call vimtex#log#warning('Clean not implemented for arara')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start(...) abort dict " {{{1
|
||||||
|
call self.exec()
|
||||||
|
|
||||||
|
if self.background
|
||||||
|
call vimtex#log#info('Compiler started in background')
|
||||||
|
else
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start_single() abort dict " {{{1
|
||||||
|
call self.start()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.stop() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.is_running() abort dict " {{{1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.kill() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.get_pid() abort dict " {{{1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_process = {}
|
||||||
|
function! s:compiler_process.exec() abort dict " {{{1
|
||||||
|
let self.process = vimtex#process#new()
|
||||||
|
let self.process.name = 'arara'
|
||||||
|
let self.process.background = self.background
|
||||||
|
let self.process.workdir = self.root
|
||||||
|
let self.process.output = self.output
|
||||||
|
let self.process.cmd = self.build_cmd()
|
||||||
|
call self.process.run()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_jobs = {}
|
||||||
|
function! s:compiler_jobs.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
let l:options = {
|
||||||
|
\ 'out_io' : 'file',
|
||||||
|
\ 'err_io' : 'file',
|
||||||
|
\ 'out_name' : self.output,
|
||||||
|
\ 'err_name' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let s:cb_target = self.target_path !=# b:vimtex.tex ? self.target_path : ''
|
||||||
|
let l:options.exit_cb = function('s:callback')
|
||||||
|
|
||||||
|
call vimtex#paths#pushd(self.root)
|
||||||
|
let self.job = job_start(l:cmd, l:options)
|
||||||
|
call vimtex#paths#popd()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback(ch, msg) abort " {{{1
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(s:cb_target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_nvim = {}
|
||||||
|
function! s:compiler_nvim.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
|
||||||
|
let l:shell = {
|
||||||
|
\ 'on_stdout' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_stderr' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_exit' : function('s:callback_nvim_exit'),
|
||||||
|
\ 'cwd' : self.root,
|
||||||
|
\ 'target' : self.target_path,
|
||||||
|
\ 'output' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let self.job = jobstart(l:cmd, l:shell)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_output(id, data, event) abort dict " {{{1
|
||||||
|
if !empty(a:data)
|
||||||
|
call writefile(filter(a:data, '!empty(v:val)'), self.output, 'a')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_exit(id, data, event) abort dict " {{{1
|
||||||
|
let l:target = self.target !=# b:vimtex.tex ? self.target : ''
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(l:target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
700
autoload/vimtex/compiler/latexmk.vim
Normal file
700
autoload/vimtex/compiler/latexmk.vim
Normal file
@@ -0,0 +1,700 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#compiler#latexmk#init(options) abort " {{{1
|
||||||
|
let l:compiler = deepcopy(s:compiler)
|
||||||
|
|
||||||
|
call l:compiler.init(extend(a:options,
|
||||||
|
\ get(g:, 'vimtex_compiler_latexmk', {}), 'keep'))
|
||||||
|
|
||||||
|
return l:compiler
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#compiler#latexmk#wrap_option(name, value) abort " {{{1
|
||||||
|
return has('win32')
|
||||||
|
\ ? ' -e "$' . a:name . ' = ''' . a:value . '''"'
|
||||||
|
\ : ' -e ''$' . a:name . ' = "' . a:value . '"'''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
"}}}1
|
||||||
|
|
||||||
|
function! vimtex#compiler#latexmk#get_rc_opt(root, opt, type, default) abort " {{{1
|
||||||
|
"
|
||||||
|
" Parse option from .latexmkrc.
|
||||||
|
"
|
||||||
|
" Arguments:
|
||||||
|
" root Root of LaTeX project
|
||||||
|
" opt Name of options
|
||||||
|
" type 0 if string, 1 if integer, 2 if list
|
||||||
|
" default Value to return if option not found in latexmkrc file
|
||||||
|
"
|
||||||
|
" Output:
|
||||||
|
" [value, location]
|
||||||
|
"
|
||||||
|
" value Option value (integer or string)
|
||||||
|
" location An integer that indicates where option was found
|
||||||
|
" -1: not found (default value returned)
|
||||||
|
" 0: global latexmkrc file
|
||||||
|
" 1: local latexmkrc file
|
||||||
|
"
|
||||||
|
|
||||||
|
if a:type == 0
|
||||||
|
let l:pattern = '^\s*\$' . a:opt . '\s*=\s*[''"]\(.\+\)[''"]'
|
||||||
|
elseif a:type == 1
|
||||||
|
let l:pattern = '^\s*\$' . a:opt . '\s*=\s*\(\d\+\)'
|
||||||
|
elseif a:type == 2
|
||||||
|
let l:pattern = '^\s*@' . a:opt . '\s*=\s*(\(.*\))'
|
||||||
|
else
|
||||||
|
throw 'vimtex: argument error'
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Candidate files
|
||||||
|
" - each element is a pair [path_to_file, is_local_rc_file].
|
||||||
|
let l:files = [
|
||||||
|
\ [a:root . '/latexmkrc', 1],
|
||||||
|
\ [a:root . '/.latexmkrc', 1],
|
||||||
|
\ [fnamemodify('~/.latexmkrc', ':p'), 0],
|
||||||
|
\]
|
||||||
|
if !empty($XDG_CONFIG_HOME)
|
||||||
|
call add(l:files, [$XDG_CONFIG_HOME . '/latexmk/latexmkrc', 0])
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:result = [a:default, -1]
|
||||||
|
|
||||||
|
for [l:file, l:is_local] in l:files
|
||||||
|
if filereadable(l:file)
|
||||||
|
let l:match = matchlist(readfile(l:file), l:pattern)
|
||||||
|
if len(l:match) > 1
|
||||||
|
let l:result = [l:match[1], l:is_local]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Parse the list
|
||||||
|
if a:type == 2 && l:result[1] > -1
|
||||||
|
let l:array = split(l:result[0], ',')
|
||||||
|
let l:result[0] = []
|
||||||
|
for l:x in l:array
|
||||||
|
let l:x = substitute(l:x, "^'", '', '')
|
||||||
|
let l:x = substitute(l:x, "'$", '', '')
|
||||||
|
let l:result[0] += [l:x]
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:result
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler = {
|
||||||
|
\ 'name' : 'latexmk',
|
||||||
|
\ 'executable' : 'latexmk',
|
||||||
|
\ 'backend' : has('nvim') ? 'nvim'
|
||||||
|
\ : v:version >= 800 ? 'jobs' : 'process',
|
||||||
|
\ 'root' : '',
|
||||||
|
\ 'target' : '',
|
||||||
|
\ 'target_path' : '',
|
||||||
|
\ 'background' : 1,
|
||||||
|
\ 'build_dir' : '',
|
||||||
|
\ 'callback' : 1,
|
||||||
|
\ 'continuous' : 1,
|
||||||
|
\ 'output' : tempname(),
|
||||||
|
\ 'options' : [
|
||||||
|
\ '-verbose',
|
||||||
|
\ '-file-line-error',
|
||||||
|
\ '-synctex=1',
|
||||||
|
\ '-interaction=nonstopmode',
|
||||||
|
\ ],
|
||||||
|
\ 'hooks' : [],
|
||||||
|
\ 'shell' : fnamemodify(&shell, ':t'),
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:compiler.init(options) abort dict " {{{1
|
||||||
|
call extend(self, a:options)
|
||||||
|
|
||||||
|
call self.init_check_requirements()
|
||||||
|
call self.init_build_dir_option()
|
||||||
|
call self.init_pdf_mode_option()
|
||||||
|
|
||||||
|
call extend(self, deepcopy(s:compiler_{self.backend}))
|
||||||
|
|
||||||
|
" Continuous processes can't run in foreground, neither can processes run
|
||||||
|
" with the new jobs api
|
||||||
|
if self.continuous || self.backend !=# 'process'
|
||||||
|
let self.background = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.backend !=# 'process'
|
||||||
|
let self.shell = 'sh'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.init_build_dir_option() abort dict " {{{1
|
||||||
|
"
|
||||||
|
" Check if .latexmkrc sets the build_dir - if so this should be respected
|
||||||
|
"
|
||||||
|
let l:out_dir =
|
||||||
|
\ vimtex#compiler#latexmk#get_rc_opt(self.root, 'out_dir', 0, '')[0]
|
||||||
|
|
||||||
|
if !empty(l:out_dir)
|
||||||
|
if !empty(self.build_dir) && (self.build_dir !=# l:out_dir)
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Setting out_dir from latexmkrc overrides build_dir!',
|
||||||
|
\ 'Changed build_dir from: ' . self.build_dir,
|
||||||
|
\ 'Changed build_dir to: ' . l:out_dir)
|
||||||
|
endif
|
||||||
|
let self.build_dir = l:out_dir
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.init_pdf_mode_option() abort dict " {{{1
|
||||||
|
" If the TeX program directive was not set, and if the pdf_mode is set in
|
||||||
|
" a .latexmkrc file, then deduce the compiler engine from the value of
|
||||||
|
" pdf_mode.
|
||||||
|
|
||||||
|
" Parse the pdf_mode option. If not found, it is set to -1.
|
||||||
|
let [l:pdf_mode, l:is_local] =
|
||||||
|
\ vimtex#compiler#latexmk#get_rc_opt(self.root, 'pdf_mode', 1, -1)
|
||||||
|
|
||||||
|
" If pdf_mode has a supported value (1: pdflatex, 4: lualatex, 5: xelatex),
|
||||||
|
" override the value of self.tex_program.
|
||||||
|
if l:pdf_mode == 1
|
||||||
|
let l:tex_program = 'pdflatex'
|
||||||
|
elseif l:pdf_mode == 3
|
||||||
|
let l:tex_program = 'pdfdvi'
|
||||||
|
elseif l:pdf_mode == 4
|
||||||
|
let l:tex_program = 'lualatex'
|
||||||
|
elseif l:pdf_mode == 5
|
||||||
|
let l:tex_program = 'xelatex'
|
||||||
|
else
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.tex_program ==# '_'
|
||||||
|
" The TeX program directive was not specified
|
||||||
|
let self.tex_program = l:tex_program
|
||||||
|
elseif l:is_local && self.tex_program !=# l:tex_program
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Value of pdf_mode from latexmkrc is inconsistent with ' .
|
||||||
|
\ 'TeX program directive!',
|
||||||
|
\ 'TeX program: ' . self.tex_program,
|
||||||
|
\ 'pdf_mode: ' . l:tex_program,
|
||||||
|
\ 'The value of pdf_mode will be ignored.')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.init_check_requirements() abort dict " {{{1
|
||||||
|
" Check option validity
|
||||||
|
if self.callback
|
||||||
|
if !(has('clientserver') || has('nvim') || has('job'))
|
||||||
|
let self.callback = 0
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Can''t use callbacks without +job, +nvim, or +clientserver',
|
||||||
|
\ 'Callback option has been disabled.')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Check for required executables
|
||||||
|
let l:required = [self.executable]
|
||||||
|
if self.continuous && !(has('win32') || has('win32unix'))
|
||||||
|
let l:required += ['pgrep']
|
||||||
|
endif
|
||||||
|
let l:missing = filter(l:required, '!executable(v:val)')
|
||||||
|
|
||||||
|
" Disable latexmk if required programs are missing
|
||||||
|
if len(l:missing) > 0
|
||||||
|
for l:cmd in l:missing
|
||||||
|
call vimtex#log#warning(l:cmd . ' is not executable')
|
||||||
|
endfor
|
||||||
|
throw 'vimtex: Requirements not met'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.build_cmd() abort dict " {{{1
|
||||||
|
if has('win32')
|
||||||
|
let l:cmd = 'set max_print_line=2000 & ' . self.executable
|
||||||
|
else
|
||||||
|
if self.shell ==# 'fish'
|
||||||
|
let l:cmd = 'set max_print_line 2000; and ' . self.executable
|
||||||
|
else
|
||||||
|
let l:cmd = 'max_print_line=2000 ' . self.executable
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:opt in self.options
|
||||||
|
let l:cmd .= ' ' . l:opt
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let l:cmd .= ' ' . self.get_engine()
|
||||||
|
|
||||||
|
if !empty(self.build_dir)
|
||||||
|
let l:cmd .= ' -outdir=' . fnameescape(self.build_dir)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.continuous
|
||||||
|
let l:cmd .= ' -pvc'
|
||||||
|
|
||||||
|
" Set viewer options
|
||||||
|
if !get(g:, 'vimtex_view_automatic', 1)
|
||||||
|
\ || get(get(b:vimtex, 'viewer', {}), 'xwin_id') > 0
|
||||||
|
\ || get(s:, 'silence_next_callback', 0)
|
||||||
|
let l:cmd .= ' -view=none'
|
||||||
|
elseif g:vimtex_view_enabled
|
||||||
|
\ && has_key(b:vimtex.viewer, 'latexmk_append_argument')
|
||||||
|
let l:cmd .= b:vimtex.viewer.latexmk_append_argument()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.callback
|
||||||
|
if has('job') || has('nvim')
|
||||||
|
for [l:opt, l:val] in items({
|
||||||
|
\ 'success_cmd' : 'vimtex_compiler_callback_success',
|
||||||
|
\ 'failure_cmd' : 'vimtex_compiler_callback_failure',
|
||||||
|
\})
|
||||||
|
let l:func = 'echo ' . l:val
|
||||||
|
let l:cmd .= vimtex#compiler#latexmk#wrap_option(l:opt, l:func)
|
||||||
|
endfor
|
||||||
|
elseif empty(v:servername)
|
||||||
|
call vimtex#log#warning('Can''t use callbacks with empty v:servername')
|
||||||
|
else
|
||||||
|
" Some notes:
|
||||||
|
" - We excape the v:servername because this seems necessary on Windows
|
||||||
|
" for neovim, see e.g. Github Issue #877
|
||||||
|
for [l:opt, l:val] in items({'success_cmd' : 1, 'failure_cmd' : 0})
|
||||||
|
let l:callback = has('win32')
|
||||||
|
\ ? '"vimtex#compiler#callback(' . l:val . ')"'
|
||||||
|
\ : '\"vimtex\#compiler\#callback(' . l:val . ')\"'
|
||||||
|
let l:func = vimtex#util#shellescape('""')
|
||||||
|
\ . g:vimtex_compiler_progname
|
||||||
|
\ . vimtex#util#shellescape('""')
|
||||||
|
\ . ' --servername ' . vimtex#util#shellescape(v:servername)
|
||||||
|
\ . ' --remote-expr ' . l:callback
|
||||||
|
let l:cmd .= vimtex#compiler#latexmk#wrap_option(l:opt, l:func)
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:cmd . ' ' . vimtex#util#shellescape(self.target)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.get_engine() abort dict " {{{1
|
||||||
|
return get(extend(g:vimtex_compiler_latexmk_engines,
|
||||||
|
\ {
|
||||||
|
\ 'pdfdvi' : '-pdfdvi',
|
||||||
|
\ 'pdflatex' : '-pdf',
|
||||||
|
\ 'luatex' : '-lualatex',
|
||||||
|
\ 'lualatex' : '-lualatex',
|
||||||
|
\ 'xelatex' : '-xelatex',
|
||||||
|
\ 'context (pdftex)' : '-pdf -pdflatex=texexec',
|
||||||
|
\ 'context (luatex)' : '-pdf -pdflatex=context',
|
||||||
|
\ 'context (xetex)' : '-pdf -pdflatex=''texexec --xtx''',
|
||||||
|
\ }, 'keep'), self.tex_program, '-pdf')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.cleanup() abort dict " {{{1
|
||||||
|
if self.is_running()
|
||||||
|
call self.kill()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.pprint_items() abort dict " {{{1
|
||||||
|
let l:configuration = [
|
||||||
|
\ ['continuous', self.continuous],
|
||||||
|
\ ['callback', self.callback],
|
||||||
|
\]
|
||||||
|
|
||||||
|
if self.backend ==# 'process' && !self.continuous
|
||||||
|
call add(l:configuration, ['background', self.background])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !empty(self.build_dir)
|
||||||
|
call add(l:configuration, ['build_dir', self.build_dir])
|
||||||
|
endif
|
||||||
|
call add(l:configuration, ['latexmk options', self.options])
|
||||||
|
call add(l:configuration, ['latexmk engine', self.get_engine()])
|
||||||
|
|
||||||
|
let l:list = []
|
||||||
|
call add(l:list, ['backend', self.backend])
|
||||||
|
if self.executable !=# s:compiler.executable
|
||||||
|
call add(l:list, ['latexmk executable', self.executable])
|
||||||
|
endif
|
||||||
|
if self.background
|
||||||
|
call add(l:list, ['output', self.output])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.target_path !=# b:vimtex.tex
|
||||||
|
call add(l:list, ['root', self.root])
|
||||||
|
call add(l:list, ['target', self.target_path])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:list, ['configuration', l:configuration])
|
||||||
|
|
||||||
|
if has_key(self, 'process')
|
||||||
|
call add(l:list, ['process', self.process])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(self, 'job')
|
||||||
|
if self.continuous
|
||||||
|
if self.backend ==# 'jobs'
|
||||||
|
call add(l:list, ['job', self.job])
|
||||||
|
else
|
||||||
|
call add(l:list, ['pid', self.get_pid()])
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
call add(l:list, ['cmd', self.cmd])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:list
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.clean(full) abort dict " {{{1
|
||||||
|
let l:restart = self.is_running()
|
||||||
|
if l:restart
|
||||||
|
call self.stop()
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Define and run the latexmk clean cmd
|
||||||
|
let l:cmd = (has('win32')
|
||||||
|
\ ? 'cd /D "' . self.root . '" & '
|
||||||
|
\ : 'cd ' . vimtex#util#shellescape(self.root) . '; ')
|
||||||
|
\ . self.executable . ' ' . (a:full ? '-C ' : '-c ')
|
||||||
|
if !empty(self.build_dir)
|
||||||
|
let l:cmd .= printf(' -outdir=%s ', fnameescape(self.build_dir))
|
||||||
|
endif
|
||||||
|
let l:cmd .= vimtex#util#shellescape(self.target)
|
||||||
|
call vimtex#process#run(l:cmd)
|
||||||
|
|
||||||
|
call vimtex#log#info('Compiler clean finished' . (a:full ? ' (full)' : ''))
|
||||||
|
|
||||||
|
if l:restart
|
||||||
|
let self.silent_next_callback = 1
|
||||||
|
silent call self.start()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start(...) abort dict " {{{1
|
||||||
|
if self.is_running()
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Compiler is already running for `' . self.target . "'")
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Create build dir if it does not exist
|
||||||
|
"
|
||||||
|
if !empty(self.build_dir)
|
||||||
|
let l:dirs = split(glob(self.root . '/**/*.tex'), '\n')
|
||||||
|
call map(l:dirs, 'fnamemodify(v:val, '':h'')')
|
||||||
|
call map(l:dirs, 'strpart(v:val, strlen(self.root) + 1)')
|
||||||
|
call vimtex#util#uniq(sort(filter(l:dirs, "v:val !=# ''")))
|
||||||
|
call map(l:dirs,
|
||||||
|
\ (vimtex#paths#is_abs(self.build_dir) ? '' : "self.root . '/' . ")
|
||||||
|
\ . "self.build_dir . '/' . v:val")
|
||||||
|
call filter(l:dirs, '!isdirectory(v:val)')
|
||||||
|
|
||||||
|
" Create the non-existing directories
|
||||||
|
for l:dir in l:dirs
|
||||||
|
call mkdir(l:dir, 'p')
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
call self.exec()
|
||||||
|
|
||||||
|
if self.continuous
|
||||||
|
call vimtex#log#info('Compiler started in continuous mode'
|
||||||
|
\ . (a:0 > 0 ? ' (single shot)' : ''))
|
||||||
|
if exists('#User#VimtexEventCompileStarted')
|
||||||
|
doautocmd <nomodeline> User VimtexEventCompileStarted
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
if self.background
|
||||||
|
call vimtex#log#info('Compiler started in background!')
|
||||||
|
else
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.stop() abort dict " {{{1
|
||||||
|
if self.is_running()
|
||||||
|
call self.kill()
|
||||||
|
call vimtex#log#info('Compiler stopped (' . self.target . ')')
|
||||||
|
if exists('#User#VimtexEventCompileStopped')
|
||||||
|
doautocmd <nomodeline> User VimtexEventCompileStopped
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'There is no process to stop (' . self.target . ')')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_process = {}
|
||||||
|
function! s:compiler_process.exec() abort dict " {{{1
|
||||||
|
let l:process = vimtex#process#new()
|
||||||
|
let l:process.name = 'latexmk'
|
||||||
|
let l:process.continuous = self.continuous
|
||||||
|
let l:process.background = self.background
|
||||||
|
let l:process.workdir = self.root
|
||||||
|
let l:process.output = self.output
|
||||||
|
let l:process.cmd = self.build_cmd()
|
||||||
|
|
||||||
|
if l:process.continuous
|
||||||
|
if (has('win32') || has('win32unix'))
|
||||||
|
" Not implemented
|
||||||
|
else
|
||||||
|
for l:pid in split(system(
|
||||||
|
\ 'pgrep -f "^[^ ]*perl.*latexmk.*' . self.target . '"'), "\n")
|
||||||
|
let l:path = resolve('/proc/' . l:pid . '/cwd') . '/' . self.target
|
||||||
|
if l:path ==# self.target_path
|
||||||
|
let l:process.pid = str2nr(l:pid)
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! l:process.set_pid() abort dict " {{{2
|
||||||
|
if (has('win32') || has('win32unix'))
|
||||||
|
let pidcmd = 'tasklist /fi "imagename eq latexmk.exe"'
|
||||||
|
let pidinfo = vimtex#process#capture(pidcmd)[-1]
|
||||||
|
let self.pid = str2nr(split(pidinfo,'\s\+')[1])
|
||||||
|
else
|
||||||
|
let self.pid = str2nr(system('pgrep -nf "^[^ ]*perl.*latexmk"')[:-2])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return self.pid
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}2
|
||||||
|
|
||||||
|
let self.process = l:process
|
||||||
|
call self.process.run()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_process.start_single() abort dict " {{{1
|
||||||
|
let l:continuous = self.continuous
|
||||||
|
let self.continuous = self.background && self.callback && !empty(v:servername)
|
||||||
|
|
||||||
|
if self.continuous
|
||||||
|
let g:vimtex_compiler_callback_hooks += ['VimtexSSCallback']
|
||||||
|
function! VimtexSSCallback(status) abort
|
||||||
|
silent call vimtex#compiler#stop()
|
||||||
|
call remove(g:vimtex_compiler_callback_hooks, 'VimtexSSCallback')
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
call self.start(1)
|
||||||
|
let self.continuous = l:continuous
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_process.is_running() abort dict " {{{1
|
||||||
|
return exists('self.process.pid') && self.process.pid > 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_process.kill() abort dict " {{{1
|
||||||
|
call self.process.stop()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_process.get_pid() abort dict " {{{1
|
||||||
|
return has_key(self, 'process') ? self.process.pid : 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_jobs = {}
|
||||||
|
function! s:compiler_jobs.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
|
||||||
|
let l:options = {
|
||||||
|
\ 'out_io' : 'file',
|
||||||
|
\ 'err_io' : 'file',
|
||||||
|
\ 'out_name' : self.output,
|
||||||
|
\ 'err_name' : self.output,
|
||||||
|
\}
|
||||||
|
if self.continuous
|
||||||
|
let l:options.out_io = 'pipe'
|
||||||
|
let l:options.err_io = 'pipe'
|
||||||
|
let l:options.out_cb = function('s:callback_continuous_output')
|
||||||
|
let l:options.err_cb = function('s:callback_continuous_output')
|
||||||
|
call writefile([], self.output, 'a')
|
||||||
|
else
|
||||||
|
let s:cb_target = self.target_path !=# b:vimtex.tex
|
||||||
|
\ ? self.target_path : ''
|
||||||
|
let l:options.exit_cb = function('s:callback')
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#paths#pushd(self.root)
|
||||||
|
let self.job = job_start(l:cmd, l:options)
|
||||||
|
call vimtex#paths#popd()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_jobs.start_single() abort dict " {{{1
|
||||||
|
let l:continuous = self.continuous
|
||||||
|
let self.continuous = 0
|
||||||
|
call self.start()
|
||||||
|
let self.continuous = l:continuous
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_jobs.kill() abort dict " {{{1
|
||||||
|
call job_stop(self.job)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_jobs.is_running() abort dict " {{{1
|
||||||
|
return has_key(self, 'job') && job_status(self.job) ==# 'run'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_jobs.get_pid() abort dict " {{{1
|
||||||
|
return has_key(self, 'job')
|
||||||
|
\ ? get(job_info(self.job), 'process') : 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback(ch, msg) abort " {{{1
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(s:cb_target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_continuous_output(channel, msg) abort " {{{1
|
||||||
|
if exists('b:vimtex') && filewritable(b:vimtex.compiler.output)
|
||||||
|
call writefile([a:msg], b:vimtex.compiler.output, 'a')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:msg ==# 'vimtex_compiler_callback_success'
|
||||||
|
call vimtex#compiler#callback(1)
|
||||||
|
elseif a:msg ==# 'vimtex_compiler_callback_failure'
|
||||||
|
call vimtex#compiler#callback(0)
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
for l:Hook in get(get(get(b:, 'vimtex', {}), 'compiler', {}), 'hooks', [])
|
||||||
|
call l:Hook(a:msg)
|
||||||
|
endfor
|
||||||
|
catch /E716/
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_nvim = {}
|
||||||
|
function! s:compiler_nvim.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
|
||||||
|
let l:shell = {
|
||||||
|
\ 'on_stdout' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_stderr' : function('s:callback_nvim_output'),
|
||||||
|
\ 'cwd' : self.root,
|
||||||
|
\ 'target' : self.target_path,
|
||||||
|
\ 'output' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
if !self.continuous
|
||||||
|
let l:shell.on_exit = function('s:callback_nvim_exit')
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Initialize output file
|
||||||
|
try
|
||||||
|
call writefile([], self.output)
|
||||||
|
endtry
|
||||||
|
|
||||||
|
let self.job = jobstart(l:cmd, l:shell)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_nvim.start_single() abort dict " {{{1
|
||||||
|
let l:continuous = self.continuous
|
||||||
|
let self.continuous = 0
|
||||||
|
call self.start()
|
||||||
|
let self.continuous = l:continuous
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_nvim.kill() abort dict " {{{1
|
||||||
|
call jobstop(self.job)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_nvim.is_running() abort dict " {{{1
|
||||||
|
try
|
||||||
|
let pid = jobpid(self.job)
|
||||||
|
return 1
|
||||||
|
catch
|
||||||
|
return 0
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler_nvim.get_pid() abort dict " {{{1
|
||||||
|
try
|
||||||
|
return jobpid(self.job)
|
||||||
|
catch
|
||||||
|
return 0
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_output(id, data, event) abort dict " {{{1
|
||||||
|
" Filter out unwanted newlines
|
||||||
|
let l:data = split(substitute(join(a:data, 'QQ'), '^QQ\|QQ$', '', ''), 'QQ')
|
||||||
|
|
||||||
|
if !empty(l:data) && filewritable(self.output)
|
||||||
|
call writefile(l:data, self.output, 'a')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if match(a:data, 'vimtex_compiler_callback_success') != -1
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
||||||
|
elseif match(a:data, 'vimtex_compiler_callback_failure') != -1
|
||||||
|
call vimtex#compiler#callback(0)
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
for l:Hook in get(get(get(b:, 'vimtex', {}), 'compiler', {}), 'hooks', [])
|
||||||
|
call l:Hook(join(a:data, "\n"))
|
||||||
|
endfor
|
||||||
|
catch /E716/
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_exit(id, data, event) abort dict " {{{1
|
||||||
|
let l:target = self.target !=# b:vimtex.tex ? self.target : ''
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(l:target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
250
autoload/vimtex/compiler/latexrun.vim
Normal file
250
autoload/vimtex/compiler/latexrun.vim
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#compiler#latexrun#init(options) abort " {{{1
|
||||||
|
let l:compiler = deepcopy(s:compiler)
|
||||||
|
|
||||||
|
call l:compiler.init(extend(a:options,
|
||||||
|
\ get(g:, 'vimtex_compiler_latexrun', {}), 'keep'))
|
||||||
|
|
||||||
|
return l:compiler
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler = {
|
||||||
|
\ 'name' : 'latexrun',
|
||||||
|
\ 'backend' : has('nvim') ? 'nvim'
|
||||||
|
\ : v:version >= 800 ? 'jobs' : 'process',
|
||||||
|
\ 'root' : '',
|
||||||
|
\ 'target' : '',
|
||||||
|
\ 'target_path' : '',
|
||||||
|
\ 'background' : 1,
|
||||||
|
\ 'build_dir' : '',
|
||||||
|
\ 'output' : tempname(),
|
||||||
|
\ 'options' : [
|
||||||
|
\ '--verbose-cmds',
|
||||||
|
\ '--latex-args="-synctex=1"',
|
||||||
|
\ ],
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:compiler.init(options) abort dict " {{{1
|
||||||
|
call extend(self, a:options)
|
||||||
|
|
||||||
|
if !executable('latexrun')
|
||||||
|
call vimtex#log#warning('latexrun is not executable!')
|
||||||
|
throw 'vimtex: Requirements not met'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call extend(self, deepcopy(s:compiler_{self.backend}))
|
||||||
|
|
||||||
|
" Processes run with the new jobs api will not run in the foreground
|
||||||
|
if self.backend !=# 'process'
|
||||||
|
let self.background = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.build_cmd() abort dict " {{{1
|
||||||
|
let l:cmd = 'latexrun'
|
||||||
|
|
||||||
|
for l:opt in self.options
|
||||||
|
let l:cmd .= ' ' . l:opt
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let l:cmd .= ' --latex-cmd ' . self.get_engine()
|
||||||
|
|
||||||
|
let l:cmd .= ' -O '
|
||||||
|
\ . (empty(self.build_dir) ? '.' : fnameescape(self.build_dir))
|
||||||
|
|
||||||
|
return l:cmd . ' ' . vimtex#util#shellescape(self.target)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.get_engine() abort dict " {{{1
|
||||||
|
return get(extend(g:vimtex_compiler_latexrun_engines,
|
||||||
|
\ {
|
||||||
|
\ '_' : 'pdflatex',
|
||||||
|
\ 'pdflatex' : 'pdflatex',
|
||||||
|
\ 'lualatex' : 'lualatex',
|
||||||
|
\ 'xelatex' : 'xelatex',
|
||||||
|
\ }, 'keep'), self.tex_program, '_')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.cleanup() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.pprint_items() abort dict " {{{1
|
||||||
|
let l:configuration = []
|
||||||
|
|
||||||
|
if self.backend ==# 'process'
|
||||||
|
call add(l:configuration, ['background', self.background])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !empty(self.build_dir)
|
||||||
|
call add(l:configuration, ['build_dir', self.build_dir])
|
||||||
|
endif
|
||||||
|
call add(l:configuration, ['latexrun options', self.options])
|
||||||
|
call add(l:configuration, ['latexrun engine', self.get_engine()])
|
||||||
|
|
||||||
|
let l:list = []
|
||||||
|
call add(l:list, ['backend', self.backend])
|
||||||
|
if self.background
|
||||||
|
call add(l:list, ['output', self.output])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.target_path !=# b:vimtex.tex
|
||||||
|
call add(l:list, ['root', self.root])
|
||||||
|
call add(l:list, ['target', self.target_path])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:list, ['configuration', l:configuration])
|
||||||
|
|
||||||
|
if has_key(self, 'process')
|
||||||
|
call add(l:list, ['process', self.process])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(self, 'job')
|
||||||
|
call add(l:list, ['cmd', self.cmd])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:list
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.clean(...) abort dict " {{{1
|
||||||
|
let l:cmd = (has('win32')
|
||||||
|
\ ? 'cd /D "' . self.root . '" & '
|
||||||
|
\ : 'cd ' . vimtex#util#shellescape(self.root) . '; ')
|
||||||
|
\ . 'latexrun --clean-all'
|
||||||
|
\ . ' -O '
|
||||||
|
\ . (empty(self.build_dir) ? '.' : fnameescape(self.build_dir))
|
||||||
|
call vimtex#process#run(l:cmd)
|
||||||
|
|
||||||
|
call vimtex#log#info('Compiler clean finished')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start(...) abort dict " {{{1
|
||||||
|
call self.exec()
|
||||||
|
|
||||||
|
if self.background
|
||||||
|
call vimtex#log#info('Compiler started in background')
|
||||||
|
else
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start_single() abort dict " {{{1
|
||||||
|
call self.start()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.stop() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.is_running() abort dict " {{{1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.kill() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.get_pid() abort dict " {{{1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_process = {}
|
||||||
|
function! s:compiler_process.exec() abort dict " {{{1
|
||||||
|
let self.process = vimtex#process#new()
|
||||||
|
let self.process.name = 'latexrun'
|
||||||
|
let self.process.background = self.background
|
||||||
|
let self.process.workdir = self.root
|
||||||
|
let self.process.output = self.output
|
||||||
|
let self.process.cmd = self.build_cmd()
|
||||||
|
call self.process.run()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_jobs = {}
|
||||||
|
function! s:compiler_jobs.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
let l:options = {
|
||||||
|
\ 'out_io' : 'file',
|
||||||
|
\ 'err_io' : 'file',
|
||||||
|
\ 'out_name' : self.output,
|
||||||
|
\ 'err_name' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let s:cb_target = self.target_path !=# b:vimtex.tex ? self.target_path : ''
|
||||||
|
let l:options.exit_cb = function('s:callback')
|
||||||
|
|
||||||
|
call vimtex#paths#pushd(self.root)
|
||||||
|
let self.job = job_start(l:cmd, l:options)
|
||||||
|
call vimtex#paths#popd()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback(ch, msg) abort " {{{1
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(s:cb_target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_nvim = {}
|
||||||
|
function! s:compiler_nvim.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
|
||||||
|
let l:shell = {
|
||||||
|
\ 'on_stdout' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_stderr' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_exit' : function('s:callback_nvim_exit'),
|
||||||
|
\ 'cwd' : self.root,
|
||||||
|
\ 'target' : self.target_path,
|
||||||
|
\ 'output' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let self.job = jobstart(l:cmd, l:shell)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_output(id, data, event) abort dict " {{{1
|
||||||
|
if !empty(a:data)
|
||||||
|
call writefile(filter(a:data, '!empty(v:val)'), self.output, 'a')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_exit(id, data, event) abort dict " {{{1
|
||||||
|
let l:target = self.target !=# b:vimtex.tex ? self.target : ''
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(l:target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
255
autoload/vimtex/compiler/tectonic.vim
Normal file
255
autoload/vimtex/compiler/tectonic.vim
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#compiler#tectonic#init(options) abort " {{{1
|
||||||
|
let l:compiler = deepcopy(s:compiler)
|
||||||
|
|
||||||
|
call l:compiler.init(extend(a:options,
|
||||||
|
\ get(g:, 'vimtex_compiler_tectonic', {}), 'keep'))
|
||||||
|
|
||||||
|
return l:compiler
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler = {
|
||||||
|
\ 'name' : 'tectonic',
|
||||||
|
\ 'backend' : has('nvim') ? 'nvim'
|
||||||
|
\ : v:version >= 800 ? 'jobs' : 'process',
|
||||||
|
\ 'root' : '',
|
||||||
|
\ 'target' : '',
|
||||||
|
\ 'target_path' : '',
|
||||||
|
\ 'background' : 1,
|
||||||
|
\ 'build_dir' : '',
|
||||||
|
\ 'output' : tempname(),
|
||||||
|
\ 'options' : [
|
||||||
|
\ '--keep-logs',
|
||||||
|
\ '--synctex'
|
||||||
|
\ ],
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:compiler.init(options) abort dict " {{{1
|
||||||
|
call extend(self, a:options)
|
||||||
|
|
||||||
|
if !executable('tectonic')
|
||||||
|
call vimtex#log#warning('tectonic is not executable!')
|
||||||
|
throw 'vimtex: Requirements not met'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call extend(self, deepcopy(s:compiler_{self.backend}))
|
||||||
|
|
||||||
|
" Processes run with the new jobs api will not run in the foreground
|
||||||
|
if self.backend !=# 'process'
|
||||||
|
let self.background = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.build_cmd() abort dict " {{{1
|
||||||
|
let l:cmd = 'tectonic'
|
||||||
|
|
||||||
|
for l:opt in self.options
|
||||||
|
if l:opt =~# '^-\%(o\|-outdir\)'
|
||||||
|
call vimtex#log#warning("Don't use --outdir or -o in compiler options,"
|
||||||
|
\ . ' use build_dir instead, see :help g:vimtex_compiler_tectonic'
|
||||||
|
\ . ' for more details')
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:cmd .= ' ' . l:opt
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if empty(self.build_dir)
|
||||||
|
let self.build_dir = fnamemodify(self.target_path, ':p:h')
|
||||||
|
elseif !isdirectory(self.build_dir)
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ "build_dir doesn't exist, it will be created: " . self.build_dir)
|
||||||
|
call mkdir(self.build_dir, 'p')
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:cmd
|
||||||
|
\ . ' --outdir=' . self.build_dir
|
||||||
|
\ . ' ' . vimtex#util#shellescape(self.target)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.cleanup() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.pprint_items() abort dict " {{{1
|
||||||
|
let l:configuration = []
|
||||||
|
|
||||||
|
if self.backend ==# 'process'
|
||||||
|
call add(l:configuration, ['background', self.background])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:configuration, ['tectonic options', self.options])
|
||||||
|
|
||||||
|
let l:list = []
|
||||||
|
call add(l:list, ['backend', self.backend])
|
||||||
|
if self.background
|
||||||
|
call add(l:list, ['output', self.output])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.target_path !=# b:vimtex.tex
|
||||||
|
call add(l:list, ['root', self.root])
|
||||||
|
call add(l:list, ['target', self.target_path])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:list, ['configuration', l:configuration])
|
||||||
|
|
||||||
|
if has_key(self, 'process')
|
||||||
|
call add(l:list, ['process', self.process])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(self, 'job')
|
||||||
|
call add(l:list, ['cmd', self.cmd])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:list
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compiler.clean(...) abort dict " {{{1
|
||||||
|
let l:files = ['synctex.gz', 'toc', 'out', 'aux', 'log']
|
||||||
|
|
||||||
|
" If a full clean is required
|
||||||
|
if a:0 > 0 && a:1
|
||||||
|
call extend(l:intermediate, ['pdf'])
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:basename = self.build_dir . '/' . fnamemodify(self.target_path, ':t:r')
|
||||||
|
call map(l:files, 'l:basename . v:val')
|
||||||
|
|
||||||
|
call vimtex#process#run('rm -f ' . join(l:files))
|
||||||
|
call vimtex#log#info('Compiler clean finished')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start(...) abort dict " {{{1
|
||||||
|
call self.exec()
|
||||||
|
|
||||||
|
if self.background
|
||||||
|
call vimtex#log#info('Compiler started in background')
|
||||||
|
else
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.start_single() abort dict " {{{1
|
||||||
|
call self.start()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.stop() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.is_running() abort dict " {{{1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.kill() abort dict " {{{1
|
||||||
|
" Pass
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:compiler.get_pid() abort dict " {{{1
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_process = {}
|
||||||
|
function! s:compiler_process.exec() abort dict " {{{1
|
||||||
|
let self.process = vimtex#process#new()
|
||||||
|
let self.process.name = 'tectonic'
|
||||||
|
let self.process.background = self.background
|
||||||
|
let self.process.workdir = self.root
|
||||||
|
let self.process.output = self.output
|
||||||
|
let self.process.cmd = self.build_cmd()
|
||||||
|
call self.process.run()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_jobs = {}
|
||||||
|
function! s:compiler_jobs.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
let l:options = {
|
||||||
|
\ 'out_io' : 'file',
|
||||||
|
\ 'err_io' : 'file',
|
||||||
|
\ 'out_name' : self.output,
|
||||||
|
\ 'err_name' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let s:cb_target = self.target_path !=# b:vimtex.tex ? self.target_path : ''
|
||||||
|
let l:options.exit_cb = function('s:callback')
|
||||||
|
|
||||||
|
if !empty(self.root)
|
||||||
|
let l:save_pwd = getcwd()
|
||||||
|
execute 'lcd' fnameescape(self.root)
|
||||||
|
endif
|
||||||
|
let self.job = job_start(l:cmd, l:options)
|
||||||
|
if !empty(self.root)
|
||||||
|
execute 'lcd' fnameescape(l:save_pwd)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback(ch, msg) abort " {{{1
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(s:cb_target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:compiler_nvim = {}
|
||||||
|
function! s:compiler_nvim.exec() abort dict " {{{1
|
||||||
|
let self.cmd = self.build_cmd()
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
||||||
|
\ : ['sh', '-c', self.cmd]
|
||||||
|
|
||||||
|
let l:shell = {
|
||||||
|
\ 'on_stdout' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_stderr' : function('s:callback_nvim_output'),
|
||||||
|
\ 'on_exit' : function('s:callback_nvim_exit'),
|
||||||
|
\ 'cwd' : self.root,
|
||||||
|
\ 'target' : self.target_path,
|
||||||
|
\ 'output' : self.output,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let self.job = jobstart(l:cmd, l:shell)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_output(id, data, event) abort dict " {{{1
|
||||||
|
if !empty(a:data)
|
||||||
|
call writefile(filter(a:data, '!empty(v:val)'), self.output, 'a')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:callback_nvim_exit(id, data, event) abort dict " {{{1
|
||||||
|
let l:target = self.target !=# b:vimtex.tex ? self.target : ''
|
||||||
|
call vimtex#compiler#callback(!vimtex#qf#inquire(l:target))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
1089
autoload/vimtex/complete.vim
Normal file
1089
autoload/vimtex/complete.vim
Normal file
File diff suppressed because it is too large
Load Diff
114
autoload/vimtex/debug.vim
Normal file
114
autoload/vimtex/debug.vim
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#debug#stacktrace(...) abort " {{{1
|
||||||
|
"
|
||||||
|
" This function builds on Luc Hermite's answer on Stack Exchange:
|
||||||
|
" http://vi.stackexchange.com/a/6024/21
|
||||||
|
"
|
||||||
|
|
||||||
|
"
|
||||||
|
" Get stack and exception
|
||||||
|
"
|
||||||
|
if empty(v:throwpoint)
|
||||||
|
try
|
||||||
|
throw 'dummy'
|
||||||
|
catch
|
||||||
|
let l:stack = reverse(split(v:throwpoint, '\.\.'))[1:]
|
||||||
|
let l:exception = 'Manual stacktrace'
|
||||||
|
endtry
|
||||||
|
else
|
||||||
|
let l:stack = reverse(split(v:throwpoint, '\.\.'))
|
||||||
|
let l:exception = v:exception
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Build the quickfix entries
|
||||||
|
"
|
||||||
|
let l:qflist = []
|
||||||
|
let l:files = {}
|
||||||
|
for l:func in l:stack
|
||||||
|
try
|
||||||
|
let [l:name, l:offset] = (l:func =~# '\S\+\[\d')
|
||||||
|
\ ? matchlist(l:func, '\(\S\+\)\[\(\d\+\)\]')[1:2]
|
||||||
|
\ : matchlist(l:func, '\(\S\+\), line \(\d\+\)')[1:2]
|
||||||
|
catch
|
||||||
|
let l:name = l:func
|
||||||
|
let l:offset = 0
|
||||||
|
endtry
|
||||||
|
|
||||||
|
if l:name =~# '\v(\<SNR\>|^)\d+_'
|
||||||
|
let l:sid = matchstr(l:name, '\v(\<SNR\>|^)\zs\d+\ze_')
|
||||||
|
let l:name = substitute(l:name, '\v(\<SNR\>|^)\d+_', 's:', '')
|
||||||
|
let l:filename = substitute(
|
||||||
|
\ vimtex#util#command('scriptnames')[l:sid-1],
|
||||||
|
\ '^\s*\d\+:\s*', '', '')
|
||||||
|
else
|
||||||
|
let l:func_name = l:name =~# '^\d\+$' ? '{' . l:name . '}' : l:name
|
||||||
|
let l:filename = matchstr(
|
||||||
|
\ vimtex#util#command('verbose function ' . l:func_name)[1],
|
||||||
|
\ v:lang[0:1] ==# 'en'
|
||||||
|
\ ? 'Last set from \zs.*\.vim' : '\f\+\.vim')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:filename = fnamemodify(l:filename, ':p')
|
||||||
|
if filereadable(l:filename)
|
||||||
|
if !has_key(l:files, l:filename)
|
||||||
|
let l:files[l:filename] = reverse(readfile(l:filename))
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:name =~# '^\d\+$'
|
||||||
|
let l:lnum = 0
|
||||||
|
let l:output = vimtex#util#command('function {' . l:name . '}')
|
||||||
|
let l:text = substitute(
|
||||||
|
\ matchstr(l:output, '^\s*' . l:offset),
|
||||||
|
\ '^\d\+\s*', '', '')
|
||||||
|
else
|
||||||
|
let l:lnum = l:offset + len(l:files[l:filename])
|
||||||
|
\ - match(l:files[l:filename], '^\s*fu\%[nction]!\=\s\+' . l:name .'(')
|
||||||
|
let l:lnum_rev = len(l:files[l:filename]) - l:lnum
|
||||||
|
let l:text = substitute(l:files[l:filename][l:lnum_rev], '^\s*', '', '')
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
let l:filename = ''
|
||||||
|
let l:lnum = 0
|
||||||
|
let l:text = ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:qflist, {
|
||||||
|
\ 'filename': l:filename,
|
||||||
|
\ 'function': l:name,
|
||||||
|
\ 'lnum': l:lnum,
|
||||||
|
\ 'text': len(l:qflist) == 0 ? l:exception : l:text,
|
||||||
|
\ 'nr': len(l:qflist),
|
||||||
|
\})
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Fill in empty filenames
|
||||||
|
let l:prev_filename = '_'
|
||||||
|
call reverse(l:qflist)
|
||||||
|
for l:entry in l:qflist
|
||||||
|
if empty(l:entry.filename)
|
||||||
|
let l:entry.filename = l:prev_filename
|
||||||
|
endif
|
||||||
|
let l:prev_filename = l:entry.filename
|
||||||
|
endfor
|
||||||
|
call reverse(l:qflist)
|
||||||
|
|
||||||
|
if a:0 > 0
|
||||||
|
call setqflist(l:qflist)
|
||||||
|
execute 'copen' len(l:qflist) + 2
|
||||||
|
wincmd p
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:qflist
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
1096
autoload/vimtex/delim.vim
Normal file
1096
autoload/vimtex/delim.vim
Normal file
File diff suppressed because it is too large
Load Diff
251
autoload/vimtex/doc.vim
Normal file
251
autoload/vimtex/doc.vim
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#doc#init_buffer() abort " {{{1
|
||||||
|
command! -buffer -nargs=? VimtexDocPackage call vimtex#doc#package(<q-args>)
|
||||||
|
|
||||||
|
nnoremap <buffer> <plug>(vimtex-doc-package) :VimtexDocPackage<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#doc#package(word) abort " {{{1
|
||||||
|
let l:context = empty(a:word)
|
||||||
|
\ ? s:packages_get_from_cursor()
|
||||||
|
\ : {
|
||||||
|
\ 'type': 'word',
|
||||||
|
\ 'candidates': [a:word],
|
||||||
|
\ }
|
||||||
|
if empty(l:context) | return | endif
|
||||||
|
|
||||||
|
call s:packages_remove_invalid(l:context)
|
||||||
|
|
||||||
|
for l:handler in g:vimtex_doc_handlers
|
||||||
|
if exists('*' . l:handler)
|
||||||
|
if call(l:handler, [l:context]) | return | endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call s:packages_open(l:context)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#doc#make_selection(context) abort " {{{1
|
||||||
|
if has_key(a:context, 'selected') | return | endif
|
||||||
|
|
||||||
|
if len(a:context.candidates) == 0
|
||||||
|
if exists('a:context.name')
|
||||||
|
echohl ErrorMsg
|
||||||
|
echo 'Sorry, no doc for '.a:context.name
|
||||||
|
echohl NONE
|
||||||
|
endif
|
||||||
|
let a:context.selected = ''
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if len(a:context.candidates) == 1
|
||||||
|
let a:context.selected = a:context.candidates[0]
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#echo#echo('Multiple candidates detected, please select one:')
|
||||||
|
let l:count = 0
|
||||||
|
for l:package in a:context.candidates
|
||||||
|
let l:count += 1
|
||||||
|
call vimtex#echo#formatted([
|
||||||
|
\ ' [' . string(l:count) . '] ',
|
||||||
|
\ ['VimtexSuccess', l:package]
|
||||||
|
\])
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call vimtex#echo#echo('Type number (everything else cancels): ')
|
||||||
|
let l:choice = nr2char(getchar())
|
||||||
|
if l:choice !~# '\d'
|
||||||
|
\ || l:choice == 0
|
||||||
|
\ || l:choice > len(a:context.candidates)
|
||||||
|
echohl VimtexWarning
|
||||||
|
echon l:choice =~# '\d' ? l:choice : '-'
|
||||||
|
echohl NONE
|
||||||
|
let a:context.selected = ''
|
||||||
|
else
|
||||||
|
echon l:choice
|
||||||
|
let a:context.selected = a:context.candidates[l:choice-1]
|
||||||
|
let a:context.ask_before_open = 0
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:packages_get_from_cursor() abort " {{{1
|
||||||
|
let l:cmd = vimtex#cmd#get_current()
|
||||||
|
if empty(l:cmd) | return {} | endif
|
||||||
|
|
||||||
|
if l:cmd.name ==# '\usepackage'
|
||||||
|
return s:packages_from_usepackage(l:cmd)
|
||||||
|
elseif l:cmd.name ==# '\documentclass'
|
||||||
|
return s:packages_from_documentclass(l:cmd)
|
||||||
|
else
|
||||||
|
return s:packages_from_command(strpart(l:cmd.name, 1))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:packages_from_usepackage(cmd) abort " {{{1
|
||||||
|
try
|
||||||
|
" Gather and clean up candidate list
|
||||||
|
let l:candidates = substitute(a:cmd.args[0].text, '%.\{-}\n', '', 'g')
|
||||||
|
let l:candidates = substitute(l:candidates, '\s*', '', 'g')
|
||||||
|
let l:candidates = split(l:candidates, ',')
|
||||||
|
|
||||||
|
let l:context = {
|
||||||
|
\ 'type': 'usepackage',
|
||||||
|
\ 'candidates': l:candidates,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let l:cword = expand('<cword>')
|
||||||
|
if len(l:context.candidates) > 1 && index(l:context.candidates, l:cword) >= 0
|
||||||
|
let l:context.selected = l:cword
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:context
|
||||||
|
catch
|
||||||
|
call vimtex#log#warning('Could not parse the package from \usepackage!')
|
||||||
|
return {}
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:packages_from_documentclass(cmd) abort " {{{1
|
||||||
|
try
|
||||||
|
return {
|
||||||
|
\ 'type': 'documentclass',
|
||||||
|
\ 'candidates': [a:cmd.args[0].text],
|
||||||
|
\}
|
||||||
|
catch
|
||||||
|
call vimtex#log#warning('Could not parse the package from \documentclass!')
|
||||||
|
return {}
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:packages_from_command(cmd) abort " {{{1
|
||||||
|
let l:packages = [
|
||||||
|
\ 'default',
|
||||||
|
\ 'class-' . get(b:vimtex, 'documentclass', ''),
|
||||||
|
\] + keys(b:vimtex.packages)
|
||||||
|
call filter(l:packages, 'filereadable(s:complete_dir . v:val)')
|
||||||
|
|
||||||
|
let l:queue = copy(l:packages)
|
||||||
|
while !empty(l:queue)
|
||||||
|
let l:current = remove(l:queue, 0)
|
||||||
|
let l:includes = filter(readfile(s:complete_dir . l:current), 'v:val =~# ''^\#\s*include:''')
|
||||||
|
if empty(l:includes) | continue | endif
|
||||||
|
|
||||||
|
call map(l:includes, 'matchstr(v:val, ''include:\s*\zs.*\ze\s*$'')')
|
||||||
|
call filter(l:includes, 'filereadable(s:complete_dir . v:val)')
|
||||||
|
call filter(l:includes, 'index(l:packages, v:val) < 0')
|
||||||
|
|
||||||
|
let l:packages += l:includes
|
||||||
|
let l:queue += l:includes
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
let l:candidates = []
|
||||||
|
let l:filter = 'v:val =~# ''^' . a:cmd . '\>'''
|
||||||
|
for l:package in l:packages
|
||||||
|
let l:cmds = filter(readfile(s:complete_dir . l:package), l:filter)
|
||||||
|
if empty(l:cmds) | continue | endif
|
||||||
|
|
||||||
|
if l:package ==# 'default'
|
||||||
|
call extend(l:candidates, ['latex2e', 'lshort'])
|
||||||
|
else
|
||||||
|
call add(l:candidates, substitute(l:package, '^class-', '', ''))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'type': 'command',
|
||||||
|
\ 'name': a:cmd,
|
||||||
|
\ 'candidates': l:candidates,
|
||||||
|
\}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:packages_remove_invalid(context) abort " {{{1
|
||||||
|
let l:invalid_packages = filter(copy(a:context.candidates),
|
||||||
|
\ 'empty(vimtex#kpsewhich#find(v:val . ''.sty'')) && '
|
||||||
|
\ . 'empty(vimtex#kpsewhich#find(v:val . ''.cls''))')
|
||||||
|
|
||||||
|
call filter(l:invalid_packages,
|
||||||
|
\ 'index([''latex2e'', ''lshort''], v:val) < 0')
|
||||||
|
|
||||||
|
" Warn about invalid candidates
|
||||||
|
if !empty(l:invalid_packages)
|
||||||
|
if len(l:invalid_packages) == 1
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Package not recognized: ' . l:invalid_packages[0])
|
||||||
|
else
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Packages not recognized:',
|
||||||
|
\ map(copy(l:invalid_packages), "'- ' . v:val"))
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Remove invalid candidates
|
||||||
|
call filter(a:context.candidates, 'index(l:invalid_packages, v:val) < 0')
|
||||||
|
|
||||||
|
" Reset the selection if the selected candidate is not valid
|
||||||
|
if has_key(a:context, 'selected')
|
||||||
|
\ && index(a:context.candidates, a:context.selected) < 0
|
||||||
|
unlet a:context.selected
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:packages_open(context) abort " {{{1
|
||||||
|
if !has_key(a:context, 'selected')
|
||||||
|
call vimtex#doc#make_selection(a:context)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if empty(a:context.selected) | return | endif
|
||||||
|
|
||||||
|
if get(a:context, 'ask_before_open', 1)
|
||||||
|
call vimtex#echo#formatted([
|
||||||
|
\ 'Open documentation for ',
|
||||||
|
\ ['VimtexSuccess', a:context.selected], ' [y/N]? '
|
||||||
|
\])
|
||||||
|
|
||||||
|
let l:choice = nr2char(getchar())
|
||||||
|
if l:choice ==# 'y'
|
||||||
|
echon 'y'
|
||||||
|
else
|
||||||
|
echohl VimtexWarning
|
||||||
|
echon l:choice =~# '\w' ? l:choice : 'N'
|
||||||
|
echohl NONE
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:os = vimtex#util#get_os()
|
||||||
|
let l:url = 'http://texdoc.net/pkg/' . a:context.selected
|
||||||
|
|
||||||
|
silent execute (l:os ==# 'linux'
|
||||||
|
\ ? '!xdg-open'
|
||||||
|
\ : (l:os ==# 'mac'
|
||||||
|
\ ? '!open'
|
||||||
|
\ : '!start'))
|
||||||
|
\ . ' ' . l:url
|
||||||
|
\ . (l:os ==# 'win' ? '' : ' &')
|
||||||
|
|
||||||
|
redraw!
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:complete_dir = fnamemodify(expand('<sfile>'), ':h') . '/complete/'
|
||||||
|
|
||||||
|
endif
|
||||||
121
autoload/vimtex/echo.vim
Normal file
121
autoload/vimtex/echo.vim
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#echo#echo(message) abort " {{{1
|
||||||
|
echohl VimtexMsg
|
||||||
|
echo a:message
|
||||||
|
echohl None
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#echo#input(opts) abort " {{{1
|
||||||
|
if g:vimtex_echo_verbose_input
|
||||||
|
\ && has_key(a:opts, 'info')
|
||||||
|
call vimtex#echo#formatted(a:opts.info)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:args = [get(a:opts, 'prompt', '> ')]
|
||||||
|
let l:args += [get(a:opts, 'default', '')]
|
||||||
|
if has_key(a:opts, 'complete')
|
||||||
|
let l:args += [a:opts.complete]
|
||||||
|
endif
|
||||||
|
|
||||||
|
echohl VimtexMsg
|
||||||
|
let l:reply = call('input', l:args)
|
||||||
|
echohl None
|
||||||
|
return l:reply
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#echo#choose(list_or_dict, prompt) abort " {{{1
|
||||||
|
if empty(a:list_or_dict) | return '' | endif
|
||||||
|
|
||||||
|
return type(a:list_or_dict) == type({})
|
||||||
|
\ ? s:choose_dict(a:list_or_dict, a:prompt)
|
||||||
|
\ : s:choose_list(a:list_or_dict, a:prompt)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#echo#formatted(parts) abort " {{{1
|
||||||
|
echo ''
|
||||||
|
try
|
||||||
|
for part in a:parts
|
||||||
|
if type(part) == type('')
|
||||||
|
echohl VimtexMsg
|
||||||
|
echon part
|
||||||
|
else
|
||||||
|
execute 'echohl' part[0]
|
||||||
|
echon part[1]
|
||||||
|
endif
|
||||||
|
unlet part
|
||||||
|
endfor
|
||||||
|
finally
|
||||||
|
echohl None
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:choose_dict(dict, prompt) abort " {{{1
|
||||||
|
if len(a:dict) == 1
|
||||||
|
return values(a:dict)[0]
|
||||||
|
endif
|
||||||
|
|
||||||
|
while v:true
|
||||||
|
redraw!
|
||||||
|
if !empty(a:prompt)
|
||||||
|
echohl VimtexMsg
|
||||||
|
unsilent echo a:prompt
|
||||||
|
echohl None
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:choice = 0
|
||||||
|
for l:x in values(a:dict)
|
||||||
|
let l:choice += 1
|
||||||
|
unsilent call vimtex#echo#formatted([['VimtexWarning', l:choice], ': ', l:x])
|
||||||
|
endfor
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:choice = str2nr(input('> ')) - 1
|
||||||
|
if l:choice >= 0 && l:choice < len(a:dict)
|
||||||
|
return keys(a:dict)[l:choice]
|
||||||
|
endif
|
||||||
|
endtry
|
||||||
|
endwhile
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:choose_list(list, prompt) abort " {{{1
|
||||||
|
if len(a:list) == 1 | return a:list[0] | endif
|
||||||
|
|
||||||
|
while v:true
|
||||||
|
redraw!
|
||||||
|
if !empty(a:prompt)
|
||||||
|
echohl VimtexMsg
|
||||||
|
unsilent echo a:prompt
|
||||||
|
echohl None
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:choice = 0
|
||||||
|
for l:x in a:list
|
||||||
|
let l:choice += 1
|
||||||
|
unsilent call vimtex#echo#formatted([['VimtexWarning', l:choice], ': ', l:x])
|
||||||
|
endfor
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:choice = str2nr(input('> ')) - 1
|
||||||
|
if l:choice >= 0 && l:choice < len(a:list)
|
||||||
|
return a:list[l:choice]
|
||||||
|
endif
|
||||||
|
endtry
|
||||||
|
endwhile
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
202
autoload/vimtex/env.vim
Normal file
202
autoload/vimtex/env.vim
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#env#init_buffer() abort " {{{1
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-env-delete)
|
||||||
|
\ :<c-u>call <sid>operator_setup('delete', 'env_tex')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-env-change)
|
||||||
|
\ :<c-u>call <sid>operator_setup('change', 'env_tex')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-env-delete-math)
|
||||||
|
\ :<c-u>call <sid>operator_setup('delete', 'env_math')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-env-change-math)
|
||||||
|
\ :<c-u>call <sid>operator_setup('change', 'env_math')<bar>normal! g@l<cr>
|
||||||
|
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-env-toggle-star)
|
||||||
|
\ :<c-u>call <sid>operator_setup('toggle_star', '')<bar>normal! g@l<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#env#change(open, close, new) abort " {{{1
|
||||||
|
"
|
||||||
|
" Set target environment
|
||||||
|
"
|
||||||
|
if a:new ==# ''
|
||||||
|
let [l:beg, l:end] = ['', '']
|
||||||
|
elseif a:new ==# '$'
|
||||||
|
let [l:beg, l:end] = ['$', '$']
|
||||||
|
elseif a:new ==# '$$'
|
||||||
|
let [l:beg, l:end] = ['$$', '$$']
|
||||||
|
elseif a:new ==# '\['
|
||||||
|
let [l:beg, l:end] = ['\[', '\]']
|
||||||
|
elseif a:new ==# '\('
|
||||||
|
let [l:beg, l:end] = ['\(', '\)']
|
||||||
|
else
|
||||||
|
let l:beg = '\begin{' . a:new . '}'
|
||||||
|
let l:end = '\end{' . a:new . '}'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:line = getline(a:open.lnum)
|
||||||
|
call setline(a:open.lnum,
|
||||||
|
\ strpart(l:line, 0, a:open.cnum-1)
|
||||||
|
\ . l:beg
|
||||||
|
\ . strpart(l:line, a:open.cnum + len(a:open.match) - 1))
|
||||||
|
|
||||||
|
let l:c1 = a:close.cnum
|
||||||
|
let l:c2 = a:close.cnum + len(a:close.match) - 1
|
||||||
|
if a:open.lnum == a:close.lnum
|
||||||
|
let n = len(l:beg) - len(a:open.match)
|
||||||
|
let l:c1 += n
|
||||||
|
let l:c2 += n
|
||||||
|
let pos = vimtex#pos#get_cursor()
|
||||||
|
if pos[2] > a:open.cnum + len(a:open.match) - 1
|
||||||
|
let pos[2] += n
|
||||||
|
call vimtex#pos#set_cursor(pos)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:line = getline(a:close.lnum)
|
||||||
|
call setline(a:close.lnum,
|
||||||
|
\ strpart(l:line, 0, l:c1-1) . l:end . strpart(l:line, l:c2))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimtex#env#change_surrounding_to(type, new) abort " {{{1
|
||||||
|
let [l:open, l:close] = vimtex#delim#get_surrounding(a:type)
|
||||||
|
if empty(l:open) | return | endif
|
||||||
|
|
||||||
|
return vimtex#env#change(l:open, l:close, a:new)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimtex#env#delete(type) abort " {{{1
|
||||||
|
let [l:open, l:close] = vimtex#delim#get_surrounding(a:type)
|
||||||
|
if empty(l:open) | return | endif
|
||||||
|
|
||||||
|
if a:type ==# 'env_tex'
|
||||||
|
call vimtex#cmd#delete_all(l:close)
|
||||||
|
call vimtex#cmd#delete_all(l:open)
|
||||||
|
else
|
||||||
|
call l:close.remove()
|
||||||
|
call l:open.remove()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if getline(l:close.lnum) =~# '^\s*$'
|
||||||
|
execute l:close.lnum . 'd _'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if getline(l:open.lnum) =~# '^\s*$'
|
||||||
|
execute l:open.lnum . 'd _'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimtex#env#toggle_star() abort " {{{1
|
||||||
|
let [l:open, l:close] = vimtex#delim#get_surrounding('env_tex')
|
||||||
|
if empty(l:open) | return | endif
|
||||||
|
|
||||||
|
call vimtex#env#change(l:open, l:close,
|
||||||
|
\ l:open.starred ? l:open.name : l:open.name . '*')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#env#is_inside(env) abort " {{{1
|
||||||
|
let l:re_start = '\\begin\s*{' . a:env . '\*\?}'
|
||||||
|
let l:re_end = '\\end\s*{' . a:env . '\*\?}'
|
||||||
|
try
|
||||||
|
return searchpairpos(l:re_start, '', l:re_end, 'bnW', '', 0, 100)
|
||||||
|
catch /E118/
|
||||||
|
let l:stopline = max([line('.') - 500, 1])
|
||||||
|
return searchpairpos(l:re_start, '', l:re_end, 'bnW', '', l:stopline)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#env#input_complete(lead, cmdline, pos) abort " {{{1
|
||||||
|
let l:cands = map(vimtex#complete#complete('env', '', '\begin'), 'v:val.word')
|
||||||
|
|
||||||
|
" Never include document and remove current env (place it first)
|
||||||
|
call filter(l:cands, 'index([''document'', s:env_name], v:val) < 0')
|
||||||
|
|
||||||
|
" Always include current env and displaymath
|
||||||
|
let l:cands = [s:env_name] + l:cands + ['\[']
|
||||||
|
|
||||||
|
return filter(l:cands, 'v:val =~# ''^' . a:lead . '''')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:change_prompt(type) abort " {{{1
|
||||||
|
let [l:open, l:close] = vimtex#delim#get_surrounding(a:type)
|
||||||
|
if empty(l:open) | return | endif
|
||||||
|
|
||||||
|
if g:vimtex_env_change_autofill
|
||||||
|
let l:name = get(l:open, 'name', l:open.match)
|
||||||
|
let s:env_name = l:name
|
||||||
|
return vimtex#echo#input({
|
||||||
|
\ 'prompt' : 'Change surrounding environment: ',
|
||||||
|
\ 'default' : l:name,
|
||||||
|
\ 'complete' : 'customlist,vimtex#env#input_complete',
|
||||||
|
\})
|
||||||
|
else
|
||||||
|
let l:name = get(l:open, 'name', l:open.is_open
|
||||||
|
\ ? l:open.match . ' ... ' . l:open.corr
|
||||||
|
\ : l:open.match . ' ... ' . l:open.corr)
|
||||||
|
let s:env_name = l:name
|
||||||
|
return vimtex#echo#input({
|
||||||
|
\ 'info' :
|
||||||
|
\ ['Change surrounding environment: ', ['VimtexWarning', l:name]],
|
||||||
|
\ 'complete' : 'customlist,vimtex#env#input_complete',
|
||||||
|
\})
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:operator_setup(operator, type) abort " {{{1
|
||||||
|
let &opfunc = s:snr() . 'operator_function'
|
||||||
|
|
||||||
|
let s:operator_abort = 0
|
||||||
|
let s:operator = a:operator
|
||||||
|
let s:operator_type = a:type
|
||||||
|
|
||||||
|
" Ask for user input if necessary/relevant
|
||||||
|
if s:operator ==# 'change'
|
||||||
|
let l:new_env = s:change_prompt(s:operator_type)
|
||||||
|
if empty(l:new_env)
|
||||||
|
let s:operator_abort = 1
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:operator_name = l:new_env
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:operator_function(_) abort " {{{1
|
||||||
|
if get(s:, 'operator_abort', 0) | return | endif
|
||||||
|
|
||||||
|
let l:type = get(s:, 'operator_type', '')
|
||||||
|
let l:name = get(s:, 'operator_name', '')
|
||||||
|
|
||||||
|
execute 'call vimtex#env#' . {
|
||||||
|
\ 'change': 'change_surrounding_to(l:type, l:name)',
|
||||||
|
\ 'delete': 'delete(l:type)',
|
||||||
|
\ 'toggle_star': 'toggle_star()',
|
||||||
|
\ }[s:operator]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:snr() abort " {{{1
|
||||||
|
return matchstr(expand('<sfile>'), '<SNR>\d\+_')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
143
autoload/vimtex/fold.vim
Normal file
143
autoload/vimtex/fold.vim
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_fold_enabled
|
||||||
|
\ || s:foldmethod_in_modeline() | return | endif
|
||||||
|
|
||||||
|
" Set fold options
|
||||||
|
setlocal foldmethod=expr
|
||||||
|
setlocal foldexpr=vimtex#fold#level(v:lnum)
|
||||||
|
setlocal foldtext=vimtex#fold#text()
|
||||||
|
|
||||||
|
if g:vimtex_fold_manual
|
||||||
|
" Remap zx to refresh fold levels
|
||||||
|
nnoremap <silent><nowait><buffer> zx :call vimtex#fold#refresh('zx')<cr>
|
||||||
|
nnoremap <silent><nowait><buffer> zX :call vimtex#fold#refresh('zX')<cr>
|
||||||
|
|
||||||
|
" Define commands
|
||||||
|
command! -buffer VimtexRefreshFolds call vimtex#fold#refresh('zx')
|
||||||
|
|
||||||
|
" Ensure that folds are refreshed on startup
|
||||||
|
augroup vimtex_temporary
|
||||||
|
autocmd! * <buffer>
|
||||||
|
autocmd CursorMoved <buffer>
|
||||||
|
\ call vimtex#fold#refresh('zx')
|
||||||
|
\ | autocmd! vimtex_temporary CursorMoved <buffer>
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#fold#init_state(state) abort " {{{1
|
||||||
|
"
|
||||||
|
" Initialize the enabled fold types
|
||||||
|
"
|
||||||
|
let a:state.fold_types_dict = {}
|
||||||
|
for [l:key, l:val] in items(g:vimtex_fold_types_defaults)
|
||||||
|
let l:config = extend(deepcopy(l:val), get(g:vimtex_fold_types, l:key, {}))
|
||||||
|
if get(l:config, 'enabled', 1)
|
||||||
|
let a:state.fold_types_dict[l:key] = vimtex#fold#{l:key}#new(l:config)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
"
|
||||||
|
" Define ordered list and the global fold regex
|
||||||
|
"
|
||||||
|
let a:state.fold_types_ordered = []
|
||||||
|
let a:state.fold_re = '\v'
|
||||||
|
\ . '\\%(begin|end)>'
|
||||||
|
\ . '|^\s*\%'
|
||||||
|
\ . '|^\s*\]\s*%(\{|$)'
|
||||||
|
\ . '|^\s*}'
|
||||||
|
for l:name in [
|
||||||
|
\ 'preamble',
|
||||||
|
\ 'cmd_single',
|
||||||
|
\ 'cmd_single_opt',
|
||||||
|
\ 'cmd_multi',
|
||||||
|
\ 'cmd_addplot',
|
||||||
|
\ 'sections',
|
||||||
|
\ 'markers',
|
||||||
|
\ 'comments',
|
||||||
|
\ 'envs',
|
||||||
|
\ 'env_options',
|
||||||
|
\]
|
||||||
|
let l:type = get(a:state.fold_types_dict, l:name, {})
|
||||||
|
if !empty(l:type)
|
||||||
|
call add(a:state.fold_types_ordered, l:type)
|
||||||
|
if exists('l:type.re.fold_re')
|
||||||
|
let a:state.fold_re .= '|' . l:type.re.fold_re
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#fold#refresh(map) abort " {{{1
|
||||||
|
setlocal foldmethod=expr
|
||||||
|
execute 'normal!' a:map
|
||||||
|
setlocal foldmethod=manual
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#fold#level(lnum) abort " {{{1
|
||||||
|
let l:line = getline(a:lnum)
|
||||||
|
|
||||||
|
" Filter out lines that do not start any folds (optimization)
|
||||||
|
if l:line !~# b:vimtex.fold_re | return '=' | endif
|
||||||
|
|
||||||
|
" Never fold \begin|end{document}
|
||||||
|
if l:line =~# '^\s*\\\%(begin\|end\){document}'
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:type in b:vimtex.fold_types_ordered
|
||||||
|
let l:value = l:type.level(l:line, a:lnum)
|
||||||
|
if !empty(l:value) | return l:value | endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Return foldlevel of previous line
|
||||||
|
return '='
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#fold#text() abort " {{{1
|
||||||
|
let l:line = getline(v:foldstart)
|
||||||
|
let l:level = v:foldlevel > 1
|
||||||
|
\ ? repeat('-', v:foldlevel-2) . g:vimtex_fold_levelmarker
|
||||||
|
\ : ''
|
||||||
|
|
||||||
|
for l:type in b:vimtex.fold_types_ordered
|
||||||
|
if l:line =~# l:type.re.start
|
||||||
|
let l:text = l:type.text(l:line, l:level)
|
||||||
|
if !empty(l:text) | return l:text | endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
function! s:foldmethod_in_modeline() abort " {{{1
|
||||||
|
let l:cursor_pos = vimtex#pos#get_cursor()
|
||||||
|
let l:fdm_modeline = 'vim:.*\%(foldmethod\|fdm\)'
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(1, 1)
|
||||||
|
let l:check_top = search(l:fdm_modeline, 'cn', &modelines)
|
||||||
|
|
||||||
|
normal! G$
|
||||||
|
let l:check_btm = search(l:fdm_modeline, 'b', line('$') + 1 - &modelines)
|
||||||
|
|
||||||
|
call vimtex#pos#set_cursor(l:cursor_pos)
|
||||||
|
return l:check_top || l:check_btm
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
51
autoload/vimtex/fold/cmd_addplot.vim
Normal file
51
autoload/vimtex/fold/cmd_addplot.vim
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#cmd_addplot#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'cmd_addplot',
|
||||||
|
\ 're' : {},
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\ 'cmds' : [],
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
let l:re = '\v^\s*\\%(' . join(self.cmds, '|') . ')\s*%(\[[^\]]*\])?'
|
||||||
|
|
||||||
|
let self.re.start = l:re . '\s*\w+\s*%(\[[^\]]*\])?\s*\ze\{\s*%($|\%)'
|
||||||
|
let self.re.end = '^\s*}'
|
||||||
|
let self.re.fold_re = '\\%(' . join(self.cmds, '|') . ')'
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let self.opened = 1
|
||||||
|
return 'a1'
|
||||||
|
elseif self.opened && a:line =~# self.re.end
|
||||||
|
let self.opened = 0
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
return matchstr(a:line, self.re.start) . '{...}'
|
||||||
|
\ . substitute(getline(v:foldend), self.re.end, '', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
51
autoload/vimtex/fold/cmd_multi.vim
Normal file
51
autoload/vimtex/fold/cmd_multi.vim
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#cmd_multi#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'cmd_multi',
|
||||||
|
\ 're' : {},
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\ 'cmds' : [],
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
let l:re = '\v^\s*\\%(' . join(self.cmds, '|') . ')\*?'
|
||||||
|
|
||||||
|
let self.re.start = l:re . '.*(\{|\[)\s*(\%.*)?$'
|
||||||
|
let self.re.end = '\v^\s*%(\}\s*\{)*\}\s*%(\%|$)'
|
||||||
|
let self.re.text = l:re . '\{[^}]*\}'
|
||||||
|
let self.re.fold_re = '\\%(' . join(self.cmds, '|') . ')'
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let self.opened += 1
|
||||||
|
return 'a1'
|
||||||
|
elseif self.opened > 0 && a:line =~# self.re.end
|
||||||
|
let self.opened -= 1
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
return a:line
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
52
autoload/vimtex/fold/cmd_single.vim
Normal file
52
autoload/vimtex/fold/cmd_single.vim
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#cmd_single#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'cmd_single',
|
||||||
|
\ 're' : {},
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\ 'cmds' : [],
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
let l:re = '\v^\s*\\%(' . join(self.cmds, '|') . ')\*?\s*%(\[.*\])?'
|
||||||
|
|
||||||
|
let self.re.start = l:re . '\s*\{\s*%($|\%)'
|
||||||
|
let self.re.end = '^\s*}'
|
||||||
|
let self.re.text = l:re
|
||||||
|
let self.re.fold_re = '\\%(' . join(self.cmds, '|') . ')'
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let self.opened = 1
|
||||||
|
return 'a1'
|
||||||
|
elseif self.opened && a:line =~# self.re.end
|
||||||
|
let self.opened = 0
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
return matchstr(a:line, self.re.text) . '{...}'
|
||||||
|
\ . substitute(getline(v:foldend), self.re.end, '', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
53
autoload/vimtex/fold/cmd_single_opt.vim
Normal file
53
autoload/vimtex/fold/cmd_single_opt.vim
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#cmd_single_opt#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'cmd_single_opt',
|
||||||
|
\ 're' : {},
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\ 'cmds' : [],
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
let l:re = '\v^\s*\\%(' . join(self.cmds, '|') . ')\*?'
|
||||||
|
|
||||||
|
let self.re.start = l:re . '\s*\[\s*%($|\%)'
|
||||||
|
let self.re.end = '^\s*\]{'
|
||||||
|
let self.re.text = l:re
|
||||||
|
let self.re.fold_re = '\\%(' . join(self.cmds, '|') . ')'
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let self.opened = 1
|
||||||
|
return 'a1'
|
||||||
|
elseif self.opened && a:line =~# self.re.end
|
||||||
|
let self.opened = 0
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
let l:col = strlen(matchstr(a:line, '^\s*')) + 1
|
||||||
|
return matchstr(a:line, self.re.text) . '[...]{'
|
||||||
|
\ . vimtex#cmd#get_at(v:foldstart, l:col).args[0].text . '}'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
46
autoload/vimtex/fold/comments.vim
Normal file
46
autoload/vimtex/fold/comments.vim
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#comments#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'comments',
|
||||||
|
\ 're' : {'start' : '^\s*%'},
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\}
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if exists('b:vimtex.fold_types_dict.markers.opened')
|
||||||
|
\ && b:vimtex.fold_types_dict.markers.opened | return | endif
|
||||||
|
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let l:next = getline(a:lnum-1) !~# self.re.start
|
||||||
|
let l:prev = getline(a:lnum+1) !~# self.re.start
|
||||||
|
if l:next && !l:prev
|
||||||
|
let self.opened = 1
|
||||||
|
return 'a1'
|
||||||
|
elseif l:prev && !l:next
|
||||||
|
let self.opened = 0
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
let l:lines = map(getline(v:foldstart, v:foldend), 'matchstr(v:val, ''%\s*\zs.*\ze\s*'')')
|
||||||
|
return matchstr(a:line, '^.*\s*%') . join(l:lines, ' ')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
53
autoload/vimtex/fold/env_options.vim
Normal file
53
autoload/vimtex/fold/env_options.vim
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#env_options#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'envs with options',
|
||||||
|
\ 're' : {
|
||||||
|
\ 'start' : g:vimtex#re#not_comment . '\\begin\s*\{.{-}\}\[\s*($|\%)',
|
||||||
|
\ 'end' : '\s*\]\s*$',
|
||||||
|
\ },
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\}
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
return self.opened
|
||||||
|
\ ? self.fold_closed(a:line, a:lnum)
|
||||||
|
\ : self.fold_opened(a:line, a:lnum)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.fold_opened(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let self.opened = 1
|
||||||
|
return 'a1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.fold_closed(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.end
|
||||||
|
let self.opened = 0
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
return a:line . '...] '
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
188
autoload/vimtex/fold/envs.vim
Normal file
188
autoload/vimtex/fold/envs.vim
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#envs#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'environments',
|
||||||
|
\ 're' : {
|
||||||
|
\ 'start' : g:vimtex#re#not_comment . '\\begin\s*\{.{-}\}',
|
||||||
|
\ 'end' : g:vimtex#re#not_comment . '\\end\s*\{.{-}\}',
|
||||||
|
\ 'name' : g:vimtex#re#not_comment . '\\%(begin|end)\s*\{\zs.{-}\ze\}'
|
||||||
|
\ },
|
||||||
|
\ 'whitelist' : [],
|
||||||
|
\ 'blacklist' : [],
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
" Define the validator as simple as possible
|
||||||
|
if empty(self.whitelist) && empty(self.blacklist)
|
||||||
|
function! self.validate(env) abort dict
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
elseif empty(self.whitelist)
|
||||||
|
function! self.validate(env) abort dict
|
||||||
|
return index(self.blacklist, a:env) < 0
|
||||||
|
endfunction
|
||||||
|
elseif empty(self.blacklist)
|
||||||
|
function! self.validate(env) abort dict
|
||||||
|
return index(self.whitelist, a:env) >= 0
|
||||||
|
endfunction
|
||||||
|
else
|
||||||
|
function! self.validate(env) abort dict
|
||||||
|
return index(self.whitelist, a:env) >= 0 && index(self.blacklist, a:env) < 0
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
let l:env = matchstr(a:line, self.re.name)
|
||||||
|
|
||||||
|
if !empty(l:env) && self.validate(l:env)
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
if a:line !~# '\\end'
|
||||||
|
return 'a1'
|
||||||
|
endif
|
||||||
|
elseif a:line =~# self.re.end
|
||||||
|
if a:line !~# '\\begin'
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
let env = matchstr(a:line, self.re.name)
|
||||||
|
if !self.validate(env) | return | endif
|
||||||
|
|
||||||
|
" Set caption/label based on type of environment
|
||||||
|
if env ==# 'frame'
|
||||||
|
let label = ''
|
||||||
|
let caption = self.parse_caption_frame(a:line)
|
||||||
|
elseif env ==# 'table'
|
||||||
|
let label = self.parse_label()
|
||||||
|
let caption = self.parse_caption_table(a:line)
|
||||||
|
else
|
||||||
|
let label = self.parse_label()
|
||||||
|
let caption = self.parse_caption(a:line)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let width_ind = len(matchstr(a:line, '^\s*'))
|
||||||
|
let width = winwidth(0) - (&number ? &numberwidth : 0) - 4 - width_ind
|
||||||
|
|
||||||
|
let width_env = 19
|
||||||
|
let width_lab = len(label) + 2 > width - width_env
|
||||||
|
\ ? width - width_env
|
||||||
|
\ : len(label) + 2
|
||||||
|
let width_cap = width - width_env - width_lab
|
||||||
|
|
||||||
|
if !empty(label)
|
||||||
|
let label = printf('(%.*S)', width_lab, label)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !empty(caption)
|
||||||
|
if strchars(caption) > width_cap
|
||||||
|
let caption = strpart(caption, 0, width_cap - 4) . '...'
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
let width_env += width_cap
|
||||||
|
let width_cap = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if strlen(env) > width_env - 8
|
||||||
|
let env = strpart(env, 0, width_env - 11) . '...'
|
||||||
|
endif
|
||||||
|
let env = '\begin{' . env . '}'
|
||||||
|
|
||||||
|
let title = printf('%*S%-*S %-*S %*S',
|
||||||
|
\ width_ind, '',
|
||||||
|
\ width_env, env,
|
||||||
|
\ width_cap, caption,
|
||||||
|
\ width_lab, label)
|
||||||
|
|
||||||
|
return substitute(title, '\s\+$', '', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.parse_label() abort dict " {{{1
|
||||||
|
let i = v:foldend
|
||||||
|
while i >= v:foldstart
|
||||||
|
if getline(i) =~# '^\s*\\label'
|
||||||
|
return matchstr(getline(i), '^\s*\\label\%(\[.*\]\)\?{\zs.*\ze}')
|
||||||
|
end
|
||||||
|
let i -= 1
|
||||||
|
endwhile
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.parse_caption(line) abort dict " {{{1
|
||||||
|
let i = v:foldend
|
||||||
|
while i >= v:foldstart
|
||||||
|
if getline(i) =~# '^\s*\\caption'
|
||||||
|
return matchstr(getline(i),
|
||||||
|
\ '^\s*\\caption\(\[.*\]\)\?{\zs.\{-1,}\ze\(}\s*\)\?$')
|
||||||
|
end
|
||||||
|
let i -= 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" If no caption found, check for a caption comment
|
||||||
|
return matchstr(a:line,'\\begin\*\?{.*}\s*%\s*\zs.*')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.parse_caption_table(line) abort dict " {{{1
|
||||||
|
let i = v:foldstart
|
||||||
|
while i <= v:foldend
|
||||||
|
if getline(i) =~# '^\s*\\caption'
|
||||||
|
return matchstr(getline(i),
|
||||||
|
\ '^\s*\\caption\s*\(\[.*\]\)\?\s*{\zs.\{-1,}\ze\(}\s*\)\?$')
|
||||||
|
end
|
||||||
|
let i += 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" If no caption found, check for a caption comment
|
||||||
|
return matchstr(a:line,'\\begin\*\?{.*}\s*%\s*\zs.*')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.parse_caption_frame(line) abort dict " {{{1
|
||||||
|
" Test simple variants first
|
||||||
|
let caption1 = matchstr(a:line,'\\begin\*\?{.*}\(\[[^]]*\]\)\?{\zs.\+\ze}')
|
||||||
|
let caption2 = matchstr(a:line,'\\begin\*\?{.*}\(\[[^]]*\]\)\?{\zs.\+')
|
||||||
|
if !empty(caption1)
|
||||||
|
return caption1
|
||||||
|
elseif !empty(caption2)
|
||||||
|
return caption2
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Search for \frametitle command
|
||||||
|
let i = v:foldstart
|
||||||
|
while i <= v:foldend
|
||||||
|
if getline(i) =~# '^\s*\\frametitle'
|
||||||
|
return matchstr(getline(i),
|
||||||
|
\ '^\s*\\frametitle\(\[.*\]\)\?{\zs.\{-1,}\ze\(}\s*\)\?$')
|
||||||
|
end
|
||||||
|
let i += 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" If no caption found, check for a caption comment
|
||||||
|
return matchstr(a:line,'\\begin\*\?{.*}\s*%\s*\zs.*')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
60
autoload/vimtex/fold/markers.vim
Normal file
60
autoload/vimtex/fold/markers.vim
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#markers#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'markers',
|
||||||
|
\ 'open' : '{{{',
|
||||||
|
\ 'close' : '}}}',
|
||||||
|
\ 're' : {},
|
||||||
|
\ 'opened' : 0,
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
let self.re.start = '%.*' . self.open
|
||||||
|
let self.re.end = '%.*' . self.close
|
||||||
|
let self.re.text = [
|
||||||
|
\ [self.re.start . '\d\?\s*\zs.*', '% ' . self.open . ' '],
|
||||||
|
\ ['%\s*\zs.*\ze' . self.open, '% ' . self.open . ' '],
|
||||||
|
\ ['^.*\ze\s*%', ''],
|
||||||
|
\]
|
||||||
|
|
||||||
|
let self.re.fold_re = escape(self.open . '|' . self.close, '{}%+*.')
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
let s:self.opened = 1
|
||||||
|
return 'a1'
|
||||||
|
elseif a:line =~# self.re.end
|
||||||
|
let s:self.opened = 0
|
||||||
|
return 's1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
for [l:re, l:pre] in self.re.text
|
||||||
|
let l:text = matchstr(a:line, l:re)
|
||||||
|
if !empty(l:text) | return l:pre . l:text | endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return '% ' . self.open . ' ' . getline(v:foldstart + 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
36
autoload/vimtex/fold/preamble.vim
Normal file
36
autoload/vimtex/fold/preamble.vim
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#preamble#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'preamble',
|
||||||
|
\ 're' : {
|
||||||
|
\ 'start' : '^\s*\\documentclass',
|
||||||
|
\ 'fold_re' : '\\documentclass',
|
||||||
|
\ },
|
||||||
|
\}
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
if a:line =~# self.re.start
|
||||||
|
return '>1'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
return ' Preamble'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
180
autoload/vimtex/fold/sections.vim
Normal file
180
autoload/vimtex/fold/sections.vim
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fold#sections#new(config) abort " {{{1
|
||||||
|
return extend(deepcopy(s:folder), a:config).init()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:folder = {
|
||||||
|
\ 'name' : 'sections',
|
||||||
|
\ 'parse_levels' : 0,
|
||||||
|
\ 're' : {},
|
||||||
|
\ 'folds' : [],
|
||||||
|
\ 'sections' : [],
|
||||||
|
\ 'parts' : [],
|
||||||
|
\ 'time' : 0,
|
||||||
|
\}
|
||||||
|
function! s:folder.init() abort dict " {{{1
|
||||||
|
let self.re.parts = '\v^\s*\\%(' . join(self.parts, '|') . ')'
|
||||||
|
let self.re.sections = '\v^\s*\\%(' . join(self.sections, '|') . ')'
|
||||||
|
let self.re.fake_sections = '\v^\s*\% Fake%('
|
||||||
|
\ . join(self.sections, '|') . ').*'
|
||||||
|
let self.re.any_sections = '\v^\s*%(\\|\% Fake)%('
|
||||||
|
\ . join(self.sections, '|') . ').*'
|
||||||
|
|
||||||
|
let self.re.start = self.re.parts
|
||||||
|
\ . '|' . self.re.sections
|
||||||
|
\ . '|' . self.re.fake_sections
|
||||||
|
|
||||||
|
let self.re.secpat1 = self.re.sections . '\*?\s*\{\zs.*'
|
||||||
|
let self.re.secpat2 = self.re.sections . '\*?\s*\[\zs.*'
|
||||||
|
|
||||||
|
let self.re.fold_re = '\\%(' . join(self.parts + self.sections, '|') . ')'
|
||||||
|
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.level(line, lnum) abort dict " {{{1
|
||||||
|
call self.refresh()
|
||||||
|
|
||||||
|
" Fold chapters and sections
|
||||||
|
for [l:part, l:level] in self.folds
|
||||||
|
if a:line =~# l:part
|
||||||
|
return '>' . l:level
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.text(line, level) abort dict " {{{1
|
||||||
|
if a:line =~# '\\frontmatter'
|
||||||
|
let l:title = 'Frontmatter'
|
||||||
|
elseif a:line =~# '\\mainmatter'
|
||||||
|
let l:title = 'Mainmatter'
|
||||||
|
elseif a:line =~# '\\backmatter'
|
||||||
|
let l:title = 'Backmatter'
|
||||||
|
elseif a:line =~# '\\appendix'
|
||||||
|
let l:title = 'Appendix'
|
||||||
|
elseif a:line =~# self.re.secpat1
|
||||||
|
let l:title = self.parse_title(matchstr(a:line, self.re.secpat1), 0)
|
||||||
|
elseif a:line =~# self.re.secpat2
|
||||||
|
let l:title = self.parse_title(matchstr(a:line, self.re.secpat2), 1)
|
||||||
|
elseif a:line =~# self.re.fake_sections
|
||||||
|
let l:title = matchstr(a:line, self.re.fake_sections)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:level = self.parse_level(v:foldstart, a:level)
|
||||||
|
|
||||||
|
return printf('%-5s %-s', l:level,
|
||||||
|
\ substitute(strpart(l:title, 0, winwidth(0) - 7), '\s\+$', '', ''))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.parse_level(lnum, level) abort dict " {{{1
|
||||||
|
if !self.parse_levels | return a:level | endif
|
||||||
|
|
||||||
|
if !has_key(self, 'toc')
|
||||||
|
let self.toc = vimtex#toc#new({
|
||||||
|
\ 'name' : 'Fold text ToC',
|
||||||
|
\ 'layers' : ['content'],
|
||||||
|
\ 'refresh_always' : 0,
|
||||||
|
\})
|
||||||
|
let self.toc_updated = 0
|
||||||
|
let self.file_updated = {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:file = expand('%')
|
||||||
|
let l:ftime = getftime(l:file)
|
||||||
|
|
||||||
|
if l:ftime > get(self.file_updated, l:file)
|
||||||
|
\ || localtime() > self.toc_updated + 300
|
||||||
|
call self.toc.get_entries(1)
|
||||||
|
let self.toc_entries = filter(
|
||||||
|
\ self.toc.get_visible_entries(),
|
||||||
|
\ '!empty(v:val.number)')
|
||||||
|
let self.file_updated[l:file] = l:ftime
|
||||||
|
let self.toc_updated = localtime()
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:entries = filter(deepcopy(self.toc_entries), 'v:val.line == a:lnum')
|
||||||
|
if len(l:entries) > 1
|
||||||
|
call filter(l:entries, "v:val.file ==# expand('%:p')")
|
||||||
|
endif
|
||||||
|
|
||||||
|
return empty(l:entries) ? '' : self.toc.print_number(l:entries[0].number)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.parse_title(string, type) abort dict " {{{1
|
||||||
|
let l:idx = -1
|
||||||
|
let l:length = strlen(a:string)
|
||||||
|
let l:level = 1
|
||||||
|
while l:level >= 1
|
||||||
|
let l:idx += 1
|
||||||
|
if l:idx > l:length
|
||||||
|
break
|
||||||
|
elseif a:string[l:idx] ==# ['}',']'][a:type]
|
||||||
|
let l:level -= 1
|
||||||
|
elseif a:string[l:idx] ==# ['{','['][a:type]
|
||||||
|
let l:level += 1
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
let l:parsed = strpart(a:string, 0, l:idx)
|
||||||
|
return empty(l:parsed)
|
||||||
|
\ ? '<untitled>' : l:parsed
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:folder.refresh() abort dict " {{{1
|
||||||
|
"
|
||||||
|
" Parse current buffer to find which sections to fold and their levels. The
|
||||||
|
" patterns are predefined to optimize the folding.
|
||||||
|
"
|
||||||
|
" We ignore top level parts such as \frontmatter, \appendix, \part, and
|
||||||
|
" similar, unless there are at least two such commands in a document.
|
||||||
|
"
|
||||||
|
|
||||||
|
" Only refresh if file has been changed
|
||||||
|
let l:time = getftime(expand('%'))
|
||||||
|
if l:time == self.time | return | endif
|
||||||
|
let self.time = l:time
|
||||||
|
|
||||||
|
" Initialize
|
||||||
|
let self.folds = []
|
||||||
|
let level = 0
|
||||||
|
let buffer = getline(1,'$')
|
||||||
|
|
||||||
|
" Parse part commands (frontmatter, appendix, etc)
|
||||||
|
" Note: We want a minimum of two top level parts
|
||||||
|
let lines = filter(copy(buffer), 'v:val =~ ''' . self.re.parts . '''')
|
||||||
|
if len(lines) >= 2
|
||||||
|
let level += 1
|
||||||
|
call insert(self.folds, [self.re.parts, level])
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Parse section commands (part, chapter, [sub...]section)
|
||||||
|
let lines = filter(copy(buffer), 'v:val =~ ''' . self.re.any_sections . '''')
|
||||||
|
for part in self.sections
|
||||||
|
let partpattern = '^\s*\%(\\\|% Fake\)' . part . ':\?\>'
|
||||||
|
for line in lines
|
||||||
|
if line =~# partpattern
|
||||||
|
let level += 1
|
||||||
|
call insert(self.folds, [partpattern, level])
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
217
autoload/vimtex/format.vim
Normal file
217
autoload/vimtex/format.vim
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#format#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_format_enabled | return | endif
|
||||||
|
|
||||||
|
setlocal formatexpr=vimtex#format#formatexpr()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#format#formatexpr() abort " {{{1
|
||||||
|
if mode() =~# '[iR]' | return -1 | endif
|
||||||
|
|
||||||
|
" Temporary disable folds and save view
|
||||||
|
let l:save_view = winsaveview()
|
||||||
|
let l:foldenable = &l:foldenable
|
||||||
|
setlocal nofoldenable
|
||||||
|
|
||||||
|
let l:top = v:lnum
|
||||||
|
let l:bottom = v:lnum + v:count - 1
|
||||||
|
let l:lines_old = getline(l:top, l:bottom)
|
||||||
|
let l:tries = 5
|
||||||
|
let s:textwidth = &l:textwidth == 0 ? 79 : &l:textwidth
|
||||||
|
|
||||||
|
" This is a hack to make undo restore the correct position
|
||||||
|
if mode() !=# 'i'
|
||||||
|
normal! ix
|
||||||
|
normal! x
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Main formatting algorithm
|
||||||
|
while l:tries > 0
|
||||||
|
" Format the range of lines
|
||||||
|
let l:bottom = s:format(l:top, l:bottom)
|
||||||
|
|
||||||
|
" Ensure proper indentation
|
||||||
|
if l:top < l:bottom
|
||||||
|
silent! execute printf('normal! %sG=%sG', l:top+1, l:bottom)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Check if any lines have changed
|
||||||
|
let l:lines_new = getline(l:top, l:bottom)
|
||||||
|
let l:index = s:compare_lines(l:lines_new, l:lines_old)
|
||||||
|
let l:top += l:index
|
||||||
|
if l:top > l:bottom | break | endif
|
||||||
|
let l:lines_old = l:lines_new[l:index : -1]
|
||||||
|
let l:tries -= 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" Restore fold and view
|
||||||
|
let &l:foldenable = l:foldenable
|
||||||
|
call winrestview(l:save_view)
|
||||||
|
|
||||||
|
" Set cursor at appropriate position
|
||||||
|
execute 'normal!' l:bottom . 'G^'
|
||||||
|
|
||||||
|
" Don't change the text if the formatting algorithm failed
|
||||||
|
if l:tries == 0
|
||||||
|
silent! undo
|
||||||
|
call vimtex#log#warning('Formatting of selected text failed!')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:format(top, bottom) abort " {{{1
|
||||||
|
let l:bottom = a:bottom
|
||||||
|
let l:mark = a:bottom
|
||||||
|
for l:current in range(a:bottom, a:top, -1)
|
||||||
|
let l:line = getline(l:current)
|
||||||
|
|
||||||
|
if vimtex#util#in_mathzone(l:current, 1)
|
||||||
|
\ && vimtex#util#in_mathzone(l:current, col([l:current, '$']))
|
||||||
|
let l:mark = l:current - 1
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Skip all lines with comments
|
||||||
|
if l:line =~# '\v%(^|[^\\])\%'
|
||||||
|
if l:current < l:mark
|
||||||
|
let l:bottom += s:format_build_lines(l:current+1, l:mark)
|
||||||
|
endif
|
||||||
|
let l:mark = l:current - 1
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Handle long lines
|
||||||
|
if strdisplaywidth(l:line) > s:textwidth
|
||||||
|
let l:bottom += s:format_build_lines(l:current, l:mark)
|
||||||
|
let l:mark = l:current-1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:line =~# s:border_end
|
||||||
|
if l:current < l:mark
|
||||||
|
let l:bottom += s:format_build_lines(l:current+1, l:mark)
|
||||||
|
endif
|
||||||
|
let l:mark = l:current
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:line =~# s:border_beginning
|
||||||
|
if l:current < l:mark
|
||||||
|
let l:bottom += s:format_build_lines(l:current, l:mark)
|
||||||
|
endif
|
||||||
|
let l:mark = l:current-1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:line =~# '^\s*$'
|
||||||
|
let l:bottom += s:format_build_lines(l:current+1, l:mark)
|
||||||
|
let l:mark = l:current-1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if a:top <= l:mark
|
||||||
|
let l:bottom += s:format_build_lines(a:top, l:mark)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:bottom
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:format_build_lines(start, end) abort " {{{1
|
||||||
|
"
|
||||||
|
" Get the desired text to format as a list of words, but preserve the ending
|
||||||
|
" line spaces
|
||||||
|
"
|
||||||
|
let l:text = join(map(getline(a:start, a:end),
|
||||||
|
\ 'substitute(v:val, ''^\s*'', '''', '''')'), ' ')
|
||||||
|
let l:spaces = matchstr(l:text, '\s*$')
|
||||||
|
let l:words = split(l:text, ' ')
|
||||||
|
if empty(l:words) | return 0 | endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Add the words in properly indented and formatted lines
|
||||||
|
"
|
||||||
|
let l:lnum = a:start-1
|
||||||
|
let l:current = s:get_indents(indent(a:start))
|
||||||
|
for l:word in l:words
|
||||||
|
if strdisplaywidth(l:word) + strdisplaywidth(l:current) > s:textwidth
|
||||||
|
call append(l:lnum, substitute(l:current, '\s$', '', ''))
|
||||||
|
let l:lnum += 1
|
||||||
|
let l:current = s:get_indents(VimtexIndent(a:start))
|
||||||
|
endif
|
||||||
|
let l:current .= l:word . ' '
|
||||||
|
endfor
|
||||||
|
if l:current !~# '^\s*$'
|
||||||
|
call append(l:lnum, substitute(l:current, '\s$', '', ''))
|
||||||
|
let l:lnum += 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Append the ending line spaces
|
||||||
|
"
|
||||||
|
if !empty(l:spaces)
|
||||||
|
call setline(l:lnum, getline(l:lnum) . l:spaces)
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Remove old text
|
||||||
|
"
|
||||||
|
silent! execute printf('%s;+%s delete', l:lnum+1, a:end-a:start)
|
||||||
|
|
||||||
|
"
|
||||||
|
" Return the difference between number of lines of old and new text
|
||||||
|
"
|
||||||
|
return l:lnum - a:end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:compare_lines(new, old) abort " {{{1
|
||||||
|
let l:min_length = min([len(a:new), len(a:old)])
|
||||||
|
for l:i in range(l:min_length)
|
||||||
|
if a:new[l:i] !=# a:old[l:i]
|
||||||
|
return l:i
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return l:min_length
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_indents(number) abort " {{{1
|
||||||
|
return !&l:expandtab && &l:shiftwidth == &l:tabstop
|
||||||
|
\ ? repeat("\t", a:number/&l:tabstop)
|
||||||
|
\ : repeat(' ', a:number)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
" {{{1 Initialize module
|
||||||
|
|
||||||
|
let s:border_beginning = '\v^\s*%(' . join([
|
||||||
|
\ '\\item',
|
||||||
|
\ '\\begin',
|
||||||
|
\ '\\end',
|
||||||
|
\ '%(\\\[|\$\$)\s*$',
|
||||||
|
\], '|') . ')'
|
||||||
|
|
||||||
|
let s:border_end = '\v\\%(' . join([
|
||||||
|
\ '\\\*?',
|
||||||
|
\ 'clear%(double)?page',
|
||||||
|
\ 'linebreak',
|
||||||
|
\ 'new%(line|page)',
|
||||||
|
\ 'pagebreak',
|
||||||
|
\ '%(begin|end)\{[^}]*\}',
|
||||||
|
\ ], '|') . ')\s*$'
|
||||||
|
\ . '|^\s*%(\\\]|\$\$)\s*$'
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
114
autoload/vimtex/fzf.vim
Normal file
114
autoload/vimtex/fzf.vim
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#fzf#run(...) abort " {{{1
|
||||||
|
" Arguments: Two optional arguments
|
||||||
|
"
|
||||||
|
" First argument: ToC filter (default: 'ctli')
|
||||||
|
" This may be used to select certain entry types according to the different
|
||||||
|
" "layers" of vimtex-toc:
|
||||||
|
" c: content: This is the main part and the "real" ToC
|
||||||
|
" t: todo: This shows TODOs from comments and `\todo{...}` commands
|
||||||
|
" l: label: This shows `\label{...}` commands
|
||||||
|
" i: include: This shows included files
|
||||||
|
"
|
||||||
|
" Second argument: Custom options for fzf
|
||||||
|
" It should be an object containing the parameters passed to fzf#run().
|
||||||
|
|
||||||
|
" Note: The '--with-nth 3..' option hides the first two words from the fzf
|
||||||
|
" window. These words are the file name and line number and are used by
|
||||||
|
" the sink.
|
||||||
|
let l:opts = extend({
|
||||||
|
\ 'source': <sid>parse_toc(a:0 == 0 ? 'ctli' : a:1),
|
||||||
|
\ 'sink': function('vimtex#fzf#open_selection'),
|
||||||
|
\ 'options': '--ansi --with-nth 3..',
|
||||||
|
\}, a:0 > 1 ? a:2 : {})
|
||||||
|
|
||||||
|
call fzf#run(l:opts)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#fzf#open_selection(sel) abort " {{{1
|
||||||
|
let line = split(a:sel)[0]
|
||||||
|
let file = split(a:sel)[1]
|
||||||
|
let curr_file = expand('%:p')
|
||||||
|
|
||||||
|
if curr_file == file
|
||||||
|
execute 'normal! ' . line . 'gg'
|
||||||
|
else
|
||||||
|
execute printf('edit +%s %s', line, file)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
function! s:parse_toc(filter) abort " {{{1
|
||||||
|
" Parsing is mostly adapted from the Denite source
|
||||||
|
" (see rplugin/python3/denite/source/vimtex.py)
|
||||||
|
python3 << EOF
|
||||||
|
import vim
|
||||||
|
import json
|
||||||
|
|
||||||
|
def format_number(n):
|
||||||
|
if not n or not type(n) is dict or not 'chapter' in n:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
num = [str(n[k]) for k in [
|
||||||
|
'chapter',
|
||||||
|
'section',
|
||||||
|
'subsection',
|
||||||
|
'subsubsection',
|
||||||
|
'subsubsubsection'] if n[k] != '0']
|
||||||
|
|
||||||
|
if n['appendix'] != '0':
|
||||||
|
num[0] = chr(int(num[0]) + 64)
|
||||||
|
|
||||||
|
return '.'.join(num)
|
||||||
|
|
||||||
|
def colorize(e):
|
||||||
|
try:
|
||||||
|
from colorama import Fore, Style
|
||||||
|
color = {'content' : Fore.WHITE,
|
||||||
|
'include' : Fore.BLUE,
|
||||||
|
'label' : Fore.GREEN,
|
||||||
|
'todo' : Fore.RED}[e['type']]
|
||||||
|
return f"{color}{e['title']:65}{Style.RESET_ALL}"
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
import os
|
||||||
|
if os.name == 'nt':
|
||||||
|
# Colour support on Windows requires Colorama
|
||||||
|
return f"{e['title']:65}"
|
||||||
|
else:
|
||||||
|
color = {'content' : "\u001b[37m",
|
||||||
|
'include' : "\u001b[34m",
|
||||||
|
'label' : "\u001b[32m",
|
||||||
|
'todo' : "\u001b[31m"}[e['type']]
|
||||||
|
return f"{color}{e['title']:65}\u001b[0m"
|
||||||
|
|
||||||
|
def create_candidate(e, depth):
|
||||||
|
number = format_number(dict(e['number']))
|
||||||
|
return f"{e.get('line', 0)} {e['file']} {colorize(e)} {number}"
|
||||||
|
|
||||||
|
entries = vim.eval('vimtex#parser#toc()')
|
||||||
|
depth = max([int(e['level']) for e in entries])
|
||||||
|
filter = vim.eval("a:filter")
|
||||||
|
candidates = [create_candidate(e, depth)
|
||||||
|
for e in entries if e['type'][0] in filter]
|
||||||
|
|
||||||
|
# json.dumps will convert single quotes to double quotes
|
||||||
|
# so that vim understands the ansi escape sequences
|
||||||
|
vim.command(f"let candidates = {json.dumps(candidates)}")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
192
autoload/vimtex/imaps.vim
Normal file
192
autoload/vimtex/imaps.vim
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#imaps#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_imaps_enabled | return | endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Create imaps
|
||||||
|
"
|
||||||
|
let l:maps = g:vimtex_imaps_list
|
||||||
|
for l:disable in g:vimtex_imaps_disabled
|
||||||
|
let l:maps = filter(l:maps, 'v:val.lhs !=# ''' . l:disable . '''')
|
||||||
|
endfor
|
||||||
|
for l:map in l:maps + get(s:, 'custom_maps', [])
|
||||||
|
call s:create_map(l:map)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
"
|
||||||
|
" Add mappings and commands
|
||||||
|
"
|
||||||
|
command! -buffer VimtexImapsList call vimtex#imaps#list()
|
||||||
|
nnoremap <buffer> <plug>(vimtex-imaps-list) :call vimtex#imaps#list()<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#imaps#add_map(map) abort " {{{1
|
||||||
|
let s:custom_maps = get(s:, 'custom_maps', []) + [a:map]
|
||||||
|
|
||||||
|
if exists('s:created_maps')
|
||||||
|
call s:create_map(a:map)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#imaps#list() abort " {{{1
|
||||||
|
silent new vimtex\ imaps
|
||||||
|
|
||||||
|
for l:map in s:created_maps
|
||||||
|
call append('$', printf('%5S -> %-30S %S',
|
||||||
|
\ get(l:map, 'leader', get(g:, 'vimtex_imaps_leader', '`')) . l:map.lhs,
|
||||||
|
\ l:map.rhs,
|
||||||
|
\ get(l:map, 'wrapper', 'vimtex#imaps#wrap_math')))
|
||||||
|
endfor
|
||||||
|
0delete _
|
||||||
|
|
||||||
|
nnoremap <silent><nowait><buffer> q :bwipeout<cr>
|
||||||
|
nnoremap <silent><nowait><buffer> <esc> :bwipeout<cr>
|
||||||
|
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
setlocal buftype=nofile
|
||||||
|
setlocal concealcursor=nvic
|
||||||
|
setlocal conceallevel=0
|
||||||
|
setlocal cursorline
|
||||||
|
setlocal nobuflisted
|
||||||
|
setlocal nolist
|
||||||
|
setlocal nospell
|
||||||
|
setlocal noswapfile
|
||||||
|
setlocal nowrap
|
||||||
|
setlocal nonumber
|
||||||
|
setlocal norelativenumber
|
||||||
|
setlocal nomodifiable
|
||||||
|
|
||||||
|
syntax match VimtexImapsLhs /^.*\ze->/ nextgroup=VimtexImapsArrow
|
||||||
|
syntax match VimtexImapsArrow /->/ contained nextgroup=VimtexImapsRhs
|
||||||
|
syntax match VimtexImapsRhs /\s*\S*/ contained nextgroup=VimtexImapsWrapper
|
||||||
|
syntax match VimtexImapsWrapper /.*/ contained
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" The imap generator
|
||||||
|
"
|
||||||
|
function! s:create_map(map) abort " {{{1
|
||||||
|
if index(s:created_maps, a:map) >= 0 | return | endif
|
||||||
|
|
||||||
|
let l:leader = get(a:map, 'leader', get(g:, 'vimtex_imaps_leader', '`'))
|
||||||
|
if l:leader !=# '' && !hasmapto(l:leader, 'i')
|
||||||
|
silent execute 'inoremap <silent><nowait><buffer>' l:leader . l:leader l:leader
|
||||||
|
endif
|
||||||
|
let l:lhs = l:leader . a:map.lhs
|
||||||
|
|
||||||
|
let l:wrapper = get(a:map, 'wrapper', 'vimtex#imaps#wrap_math')
|
||||||
|
if ! exists('*' . l:wrapper)
|
||||||
|
echoerr 'vimtex error: imaps wrapper does not exist!'
|
||||||
|
echoerr ' ' . l:wrapper
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Some wrappers use a context which must be made available to the wrapper
|
||||||
|
" function at run time.
|
||||||
|
if has_key(a:map, 'context')
|
||||||
|
execute 'let l:key = "' . escape(l:lhs, '<') . '"'
|
||||||
|
let l:key .= a:map.rhs
|
||||||
|
if !exists('b:vimtex_context')
|
||||||
|
let b:vimtex_context = {}
|
||||||
|
endif
|
||||||
|
let b:vimtex_context[l:key] = a:map.context
|
||||||
|
endif
|
||||||
|
|
||||||
|
" The rhs may be evaluated before being passed to wrapper, unless expr is
|
||||||
|
" disabled (which it is by default)
|
||||||
|
if !get(a:map, 'expr')
|
||||||
|
let a:map.rhs = string(a:map.rhs)
|
||||||
|
endif
|
||||||
|
|
||||||
|
silent execute 'inoremap <expr><silent><nowait><buffer>' l:lhs
|
||||||
|
\ l:wrapper . '("' . escape(l:lhs, '\') . '", ' . a:map.rhs . ')'
|
||||||
|
|
||||||
|
let s:created_maps += [a:map]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Wrappers
|
||||||
|
"
|
||||||
|
function! vimtex#imaps#wrap_trivial(lhs, rhs) abort " {{{1
|
||||||
|
return a:rhs
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#imaps#wrap_math(lhs, rhs) abort " {{{1
|
||||||
|
return s:is_math() ? a:rhs : a:lhs
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#imaps#wrap_environment(lhs, rhs) abort " {{{1
|
||||||
|
let l:return = a:lhs
|
||||||
|
let l:cursor = vimtex#pos#val(vimtex#pos#get_cursor())
|
||||||
|
let l:value = 0
|
||||||
|
|
||||||
|
for l:context in b:vimtex_context[a:lhs . a:rhs]
|
||||||
|
if type(l:context) == type('')
|
||||||
|
let l:envs = [l:context]
|
||||||
|
let l:rhs = a:rhs
|
||||||
|
elseif type(l:context) == type({})
|
||||||
|
let l:envs = l:context.envs
|
||||||
|
let l:rhs = l:context.rhs
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:env in l:envs
|
||||||
|
let l:candidate_value = vimtex#pos#val(vimtex#env#is_inside(l:env))
|
||||||
|
if l:candidate_value > l:value
|
||||||
|
let l:value = l:candidate_value
|
||||||
|
let l:return = l:rhs
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
unlet l:context
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:return
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Special rhs styles
|
||||||
|
"
|
||||||
|
function! vimtex#imaps#style_math(command) " {{{1
|
||||||
|
return s:is_math()
|
||||||
|
\ ? '\' . a:command . '{' . nr2char(getchar()) . '}'
|
||||||
|
\ : ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Helpers
|
||||||
|
"
|
||||||
|
function! s:is_math() abort " {{{1
|
||||||
|
return match(map(synstack(line('.'), max([col('.') - 1, 1])),
|
||||||
|
\ 'synIDattr(v:val, ''name'')'), '^texMathZone') >= 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
" {{{1 Initialize module
|
||||||
|
|
||||||
|
let s:created_maps = []
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
147
autoload/vimtex/include.vim
Normal file
147
autoload/vimtex/include.vim
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#include#expr() abort " {{{1
|
||||||
|
call s:visited.timeout()
|
||||||
|
let l:fname = substitute(v:fname, '^\s*\|\s*$', '', 'g')
|
||||||
|
|
||||||
|
"
|
||||||
|
" Check if v:fname matches exactly
|
||||||
|
"
|
||||||
|
if filereadable(l:fname)
|
||||||
|
return s:visited.check(l:fname)
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Parse \include or \input style lines
|
||||||
|
"
|
||||||
|
let l:file = s:input(l:fname, 'tex')
|
||||||
|
for l:candidate in [l:file, l:file . '.tex']
|
||||||
|
if filereadable(l:candidate)
|
||||||
|
return s:visited.check(l:candidate)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
"
|
||||||
|
" Parse \bibliography or \addbibresource
|
||||||
|
"
|
||||||
|
let l:candidate = s:input(l:fname, 'bib')
|
||||||
|
if filereadable(l:candidate)
|
||||||
|
return s:visited.check(l:candidate)
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Check if v:fname matches in $TEXINPUTS
|
||||||
|
"
|
||||||
|
let l:candidate = s:search_candidates_texinputs(l:fname)
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return s:visited.check(l:candidate)
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Search for file with kpsewhich
|
||||||
|
"
|
||||||
|
if g:vimtex_include_search_enabled
|
||||||
|
let l:candidate = s:search_candidates_kpsewhich(l:fname)
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return s:visited.check(l:candidate)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return s:visited.check(l:fname)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:input(fname, type) abort " {{{1
|
||||||
|
let [l:lnum, l:cnum] = searchpos(g:vimtex#re#{a:type}_input, 'bcn', line('.'))
|
||||||
|
if l:lnum == 0 | return a:fname | endif
|
||||||
|
|
||||||
|
let l:cmd = vimtex#cmd#get_at(l:lnum, l:cnum)
|
||||||
|
let l:file = join(map(
|
||||||
|
\ get(l:cmd, 'args', [{}]),
|
||||||
|
\ "get(v:val, 'text', '')"),
|
||||||
|
\ '')
|
||||||
|
let l:file = substitute(l:file, '^\s*"\|"\s*$', '', 'g')
|
||||||
|
let l:file = substitute(l:file, '\\space', '', 'g')
|
||||||
|
|
||||||
|
if l:file[-3:] !=# a:type
|
||||||
|
let l:file .= '.' . a:type
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:file
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:search_candidates_texinputs(fname) abort " {{{1
|
||||||
|
for l:suffix in [''] + split(&l:suffixesadd, ',')
|
||||||
|
let l:candidates = glob(b:vimtex.root . '/**/' . a:fname . l:suffix, 0, 1)
|
||||||
|
if !empty(l:candidates)
|
||||||
|
return l:candidates[0]
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:search_candidates_kpsewhich(fname) abort " {{{1
|
||||||
|
" Split input list on commas, and if applicable, ensure that the entry that
|
||||||
|
" the cursor is on is placed first in the queue
|
||||||
|
let l:files = split(a:fname, '\s*,\s*')
|
||||||
|
let l:current = expand('<cword>')
|
||||||
|
let l:index = index(l:files, l:current)
|
||||||
|
if l:index >= 0
|
||||||
|
call remove(l:files, l:index)
|
||||||
|
let l:files = [l:current] + l:files
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Add file extensions to create the final list of candidate files
|
||||||
|
let l:candidates = []
|
||||||
|
for l:file in l:files
|
||||||
|
if !empty(fnamemodify(l:file, ':e'))
|
||||||
|
call add(l:candidates, l:file)
|
||||||
|
else
|
||||||
|
call extend(l:candidates, map(split(&l:suffixesadd, ','), 'l:file . v:val'))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
for l:file in l:candidates
|
||||||
|
let l:candidate = vimtex#kpsewhich#find(l:file)
|
||||||
|
if !empty(l:candidate) && filereadable(l:candidate) | return l:candidate | endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:visited = {
|
||||||
|
\ 'time' : 0,
|
||||||
|
\ 'list' : [],
|
||||||
|
\}
|
||||||
|
function! s:visited.timeout() abort dict " {{{1
|
||||||
|
if localtime() - self.time > 1
|
||||||
|
let self.time = localtime()
|
||||||
|
let self.list = [expand('%:p')]
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:visited.check(fname) abort dict " {{{1
|
||||||
|
if index(self.list, fnamemodify(a:fname, ':p')) < 0
|
||||||
|
call add(self.list, fnamemodify(a:fname, ':p'))
|
||||||
|
return a:fname
|
||||||
|
endif
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
222
autoload/vimtex/info.vim
Normal file
222
autoload/vimtex/info.vim
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#info#init_buffer() abort " {{{1
|
||||||
|
command! -buffer -bang VimtexInfo call vimtex#info#open(<q-bang> == '!')
|
||||||
|
|
||||||
|
nnoremap <buffer> <plug>(vimtex-info) :VimtexInfo<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-info-full) :VimtexInfo!<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#info#open(global) abort " {{{1
|
||||||
|
let s:info.global = a:global
|
||||||
|
call vimtex#scratch#new(s:info)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:info = {
|
||||||
|
\ 'name' : 'VimtexInfo',
|
||||||
|
\ 'global' : 0,
|
||||||
|
\}
|
||||||
|
function! s:info.print_content() abort dict " {{{1
|
||||||
|
for l:line in self.gather_system_info()
|
||||||
|
call append('$', l:line)
|
||||||
|
endfor
|
||||||
|
call append('$', '')
|
||||||
|
for l:line in self.gather_state_info()
|
||||||
|
call append('$', l:line)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:info.gather_system_info() abort dict " {{{1
|
||||||
|
let l:lines = [
|
||||||
|
\ 'System info',
|
||||||
|
\ ' OS: ' . s:get_os_info(),
|
||||||
|
\ ' Vim version: ' . s:get_vim_info(),
|
||||||
|
\]
|
||||||
|
|
||||||
|
if has('clientserver') || has('nvim')
|
||||||
|
call add(l:lines, ' Has clientserver: true')
|
||||||
|
call add(l:lines, ' Servername: '
|
||||||
|
\ . (empty(v:servername) ? 'undefined (vim started without --servername)' : v:servername))
|
||||||
|
else
|
||||||
|
call add(l:lines, ' Has clientserver: false')
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:lines
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:info.gather_state_info() abort dict " {{{1
|
||||||
|
if self.global
|
||||||
|
let l:lines = []
|
||||||
|
for l:data in vimtex#state#list_all()
|
||||||
|
let l:lines += s:get_info(l:data)
|
||||||
|
let l:lines += ['']
|
||||||
|
endfor
|
||||||
|
call remove(l:lines, -1)
|
||||||
|
else
|
||||||
|
let l:lines = s:get_info(b:vimtex)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:lines
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:info.syntax() abort dict " {{{1
|
||||||
|
syntax match VimtexInfoOther /.*/
|
||||||
|
syntax match VimtexInfoKey /^.*:/ nextgroup=VimtexInfoValue
|
||||||
|
syntax match VimtexInfoValue /.*/ contained
|
||||||
|
syntax match VimtexInfoTitle /vimtex project:/ nextgroup=VimtexInfoValue
|
||||||
|
syntax match VimtexInfoTitle /System info/
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Functions to parse the vimtex state data
|
||||||
|
"
|
||||||
|
function! s:get_info(item, ...) abort " {{{1
|
||||||
|
if empty(a:item) | return [] | endif
|
||||||
|
let l:indent = a:0 > 0 ? a:1 : 0
|
||||||
|
|
||||||
|
if type(a:item) == type({})
|
||||||
|
return s:parse_dict(a:item, l:indent)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if type(a:item) == type([])
|
||||||
|
let l:entries = []
|
||||||
|
for [l:title, l:Value] in a:item
|
||||||
|
if type(l:Value) == type({})
|
||||||
|
call extend(l:entries, s:parse_dict(l:Value, l:indent, l:title))
|
||||||
|
elseif type(l:Value) == type([])
|
||||||
|
call extend(l:entries, s:parse_list(l:Value, l:indent, l:title))
|
||||||
|
else
|
||||||
|
call add(l:entries,
|
||||||
|
\ repeat(' ', l:indent) . printf('%s: %s', l:title, l:Value))
|
||||||
|
endif
|
||||||
|
unlet l:Value
|
||||||
|
endfor
|
||||||
|
return l:entries
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_dict(dict, indent, ...) abort " {{{1
|
||||||
|
if empty(a:dict) | return [] | endif
|
||||||
|
let l:dict = a:dict
|
||||||
|
let l:indent = a:indent
|
||||||
|
let l:entries = []
|
||||||
|
|
||||||
|
if a:0 > 0
|
||||||
|
let l:title = a:1
|
||||||
|
let l:name = ''
|
||||||
|
if has_key(a:dict, 'name')
|
||||||
|
let l:dict = deepcopy(a:dict)
|
||||||
|
let l:name = remove(l:dict, 'name')
|
||||||
|
endif
|
||||||
|
call add(l:entries,
|
||||||
|
\ repeat(' ', l:indent) . printf('%s: %s', l:title, l:name))
|
||||||
|
let l:indent += 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:items = has_key(l:dict, 'pprint_items')
|
||||||
|
\ ? l:dict.pprint_items() : items(l:dict)
|
||||||
|
|
||||||
|
return extend(l:entries, s:get_info(l:items, l:indent))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_list(list, indent, title) abort " {{{1
|
||||||
|
if empty(a:list) | return [] | endif
|
||||||
|
|
||||||
|
let l:entries = []
|
||||||
|
let l:indent = repeat(' ', a:indent)
|
||||||
|
if type(a:list[0]) == type([])
|
||||||
|
let l:name = ''
|
||||||
|
let l:index = 0
|
||||||
|
|
||||||
|
" l:entry[0] == title
|
||||||
|
" l:entry[1] == value
|
||||||
|
for l:entry in a:list
|
||||||
|
if l:entry[0] ==# 'name'
|
||||||
|
let l:name = l:entry[1]
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
let l:index += 1
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if empty(l:name)
|
||||||
|
let l:list = a:list
|
||||||
|
else
|
||||||
|
let l:list = deepcopy(a:list)
|
||||||
|
call remove(l:list, l:index)
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:entries, l:indent . printf('%s: %s', a:title, l:name))
|
||||||
|
call extend(l:entries, s:get_info(l:list, a:indent+1))
|
||||||
|
else
|
||||||
|
call add(l:entries, l:indent . printf('%s:', a:title))
|
||||||
|
for l:value in a:list
|
||||||
|
call add(l:entries, l:indent . printf(' %s', l:value))
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:entries
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Other utility functions
|
||||||
|
"
|
||||||
|
function! s:get_os_info() abort " {{{1
|
||||||
|
let l:os = vimtex#util#get_os()
|
||||||
|
|
||||||
|
if l:os ==# 'linux'
|
||||||
|
let l:result = executable('lsb_release')
|
||||||
|
\ ? system('lsb_release -d')[12:-2]
|
||||||
|
\ : system('uname -sr')[:-2]
|
||||||
|
return substitute(l:result, '^\s*', '', '')
|
||||||
|
elseif l:os ==# 'mac'
|
||||||
|
let l:name = system('sw_vers -productName')[:-2]
|
||||||
|
let l:version = system('sw_vers -productVersion')[:-2]
|
||||||
|
let l:build = system('sw_vers -buildVersion')[:-2]
|
||||||
|
return l:name . ' ' . l:version . ' (' . l:build . ')'
|
||||||
|
else
|
||||||
|
if !exists('s:win_info')
|
||||||
|
let s:win_info = vimtex#process#capture('systeminfo')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:name = matchstr(s:win_info[1], ':\s*\zs.*')
|
||||||
|
let l:version = matchstr(s:win_info[2], ':\s*\zs.*')
|
||||||
|
return l:name . ' (' . l:version . ')'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_vim_info() abort " {{{1
|
||||||
|
let l:info = vimtex#util#command('version')
|
||||||
|
|
||||||
|
if has('nvim')
|
||||||
|
return l:info[0]
|
||||||
|
else
|
||||||
|
let l:version = 'VIM ' . strpart(l:info[0], 18, 3) . ' ('
|
||||||
|
let l:index = 2 - (l:info[1] =~# ':\s*\d')
|
||||||
|
let l:version .= matchstr(l:info[l:index], ':\s*\zs.*') . ')'
|
||||||
|
return l:version
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
53
autoload/vimtex/kpsewhich.vim
Normal file
53
autoload/vimtex/kpsewhich.vim
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#kpsewhich#find(file) abort " {{{1
|
||||||
|
return s:find_cached(a:file)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#kpsewhich#run(args) abort " {{{1
|
||||||
|
" kpsewhich should be run at the project root directory
|
||||||
|
if exists('b:vimtex.root')
|
||||||
|
call vimtex#paths#pushd(b:vimtex.root)
|
||||||
|
endif
|
||||||
|
let l:output = vimtex#process#capture('kpsewhich ' . a:args)
|
||||||
|
if exists('b:vimtex.root')
|
||||||
|
call vimtex#paths#popd()
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Remove warning lines from output
|
||||||
|
call filter(l:output, 'stridx(v:val, "kpsewhich: warning: ") == -1')
|
||||||
|
|
||||||
|
return l:output
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:find(file) abort " {{{1
|
||||||
|
let l:output = vimtex#kpsewhich#run(fnameescape(a:file))
|
||||||
|
if empty(l:output) | return '' | endif
|
||||||
|
|
||||||
|
let l:filename = l:output[0]
|
||||||
|
|
||||||
|
" Ensure absolute path
|
||||||
|
if !vimtex#paths#is_abs(l:filename) && exists('b:vimtex.root')
|
||||||
|
let l:filename = simplify(b:vimtex.root . '/' . l:filename)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:filename
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Use caching if possible (requires 'lambda' feature)
|
||||||
|
let s:find_cached = has('lambda')
|
||||||
|
\ ? vimtex#cache#wrap(function('s:find'), 'kpsewhich')
|
||||||
|
\ : function('s:find')
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
137
autoload/vimtex/log.vim
Normal file
137
autoload/vimtex/log.vim
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#log#init_buffer() abort " {{{1
|
||||||
|
command! -buffer -bang VimtexLog call vimtex#log#open()
|
||||||
|
|
||||||
|
nnoremap <buffer> <plug>(vimtex-log) :VimtexLog<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#log#info(...) abort " {{{1
|
||||||
|
call s:logger.add(a:000, 'info')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#log#warning(...) abort " {{{1
|
||||||
|
call s:logger.add(a:000, 'warning')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#log#error(...) abort " {{{1
|
||||||
|
call s:logger.add(a:000, 'error')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#log#get() abort " {{{1
|
||||||
|
return s:logger.entries
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#log#open() abort " {{{1
|
||||||
|
call vimtex#scratch#new(s:logger)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#log#toggle_verbose() abort " {{{1
|
||||||
|
if s:logger.verbose
|
||||||
|
let s:logger.verbose = 0
|
||||||
|
call vimtex#log#info('Logging is now quiet')
|
||||||
|
else
|
||||||
|
call vimtex#log#info('Logging is now verbose')
|
||||||
|
let s:logger.verbose = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:logger = {
|
||||||
|
\ 'name' : 'VimtexMessageLog',
|
||||||
|
\ 'entries' : [],
|
||||||
|
\ 'type_to_highlight' : {
|
||||||
|
\ 'info' : 'VimtexInfo',
|
||||||
|
\ 'warning' : 'VimtexWarning',
|
||||||
|
\ 'error' : 'VimtexError',
|
||||||
|
\ },
|
||||||
|
\ 'verbose' : get(g:, 'vimtex_log_verbose', 1),
|
||||||
|
\}
|
||||||
|
function! s:logger.add(msg_arg, type) abort dict " {{{1
|
||||||
|
let l:msg_list = []
|
||||||
|
for l:msg in a:msg_arg
|
||||||
|
if type(l:msg) == type('')
|
||||||
|
call add(l:msg_list, l:msg)
|
||||||
|
elseif type(l:msg) == type([])
|
||||||
|
call extend(l:msg_list, filter(l:msg, "type(v:val) == type('')"))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let l:entry = {}
|
||||||
|
let l:entry.type = a:type
|
||||||
|
let l:entry.time = strftime('%T')
|
||||||
|
let l:entry.callstack = vimtex#debug#stacktrace()[1:]
|
||||||
|
let l:entry.msg = l:msg_list
|
||||||
|
call add(self.entries, l:entry)
|
||||||
|
|
||||||
|
if !self.verbose | return | endif
|
||||||
|
|
||||||
|
" Ignore message
|
||||||
|
for l:re in get(g:, 'vimtex_log_ignore', [])
|
||||||
|
if join(l:msg_list) =~# l:re | return | endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call vimtex#echo#formatted([
|
||||||
|
\ [self.type_to_highlight[a:type], 'vimtex:'],
|
||||||
|
\ ' ' . l:msg_list[0]
|
||||||
|
\])
|
||||||
|
for l:line in l:msg_list[1:]
|
||||||
|
call vimtex#echo#echo(' ' . l:line)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:logger.print_content() abort dict " {{{1
|
||||||
|
for l:entry in self.entries
|
||||||
|
call append('$', printf('%s: %s', l:entry.time, l:entry.type))
|
||||||
|
for l:stack in l:entry.callstack
|
||||||
|
if l:stack.lnum > 0
|
||||||
|
call append('$', printf(' #%d %s:%d', l:stack.nr, l:stack.filename, l:stack.lnum))
|
||||||
|
else
|
||||||
|
call append('$', printf(' #%d %s', l:stack.nr, l:stack.filename))
|
||||||
|
endif
|
||||||
|
call append('$', printf(' In %s', l:stack.function))
|
||||||
|
if !empty(l:stack.text)
|
||||||
|
call append('$', printf(' %s', l:stack.text))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
for l:msg in l:entry.msg
|
||||||
|
call append('$', printf(' %s', l:msg))
|
||||||
|
endfor
|
||||||
|
call append('$', '')
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:logger.syntax() abort dict " {{{1
|
||||||
|
syntax match VimtexInfoOther /.*/
|
||||||
|
|
||||||
|
syntax include @VIM syntax/vim.vim
|
||||||
|
syntax match VimtexInfoVimCode /^ .*/ transparent contains=@VIM
|
||||||
|
|
||||||
|
syntax match VimtexInfoKey /^\S*:/ nextgroup=VimtexInfoValue
|
||||||
|
syntax match VimtexInfoKey /^ #\d\+/ nextgroup=VimtexInfoValue
|
||||||
|
syntax match VimtexInfoKey /^ In/ nextgroup=VimtexInfoValue
|
||||||
|
syntax match VimtexInfoValue /.*/ contained
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
111
autoload/vimtex/matchparen.vim
Normal file
111
autoload/vimtex/matchparen.vim
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#matchparen#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_matchparen_enabled | return | endif
|
||||||
|
|
||||||
|
call vimtex#matchparen#enable()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#matchparen#enable() abort " {{{1
|
||||||
|
call s:matchparen.enable()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#matchparen#disable() abort " {{{1
|
||||||
|
call s:matchparen.disable()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#matchparen#popup_check(...) abort " {{{1
|
||||||
|
if pumvisible()
|
||||||
|
call s:matchparen.highlight()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matchparen = {}
|
||||||
|
|
||||||
|
function! s:matchparen.enable() abort dict " {{{1
|
||||||
|
" vint: -ProhibitAutocmdWithNoGroup
|
||||||
|
|
||||||
|
execute 'augroup vimtex_matchparen' . bufnr('%')
|
||||||
|
autocmd!
|
||||||
|
autocmd CursorMoved <buffer> call s:matchparen.highlight()
|
||||||
|
autocmd CursorMovedI <buffer> call s:matchparen.highlight()
|
||||||
|
try
|
||||||
|
autocmd TextChangedP <buffer> call s:matchparen.highlight()
|
||||||
|
catch /E216/
|
||||||
|
silent! let self.timer =
|
||||||
|
\ timer_start(50, 'vimtex#matchparen#popup_check', {'repeat' : -1})
|
||||||
|
endtry
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
call self.highlight()
|
||||||
|
|
||||||
|
" vint: +ProhibitAutocmdWithNoGroup
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matchparen.disable() abort dict " {{{1
|
||||||
|
call self.clear()
|
||||||
|
execute 'autocmd! vimtex_matchparen' . bufnr('%')
|
||||||
|
silent! call timer_stop(self.timer)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matchparen.clear() abort dict " {{{1
|
||||||
|
silent! call matchdelete(w:vimtex_match_id1)
|
||||||
|
silent! call matchdelete(w:vimtex_match_id2)
|
||||||
|
unlet! w:vimtex_match_id1
|
||||||
|
unlet! w:vimtex_match_id2
|
||||||
|
endfunction
|
||||||
|
function! s:matchparen.highlight() abort dict " {{{1
|
||||||
|
call self.clear()
|
||||||
|
|
||||||
|
if vimtex#util#in_comment() | return | endif
|
||||||
|
|
||||||
|
" This is a hack to ensure that $ in visual block mode adhers to the rule
|
||||||
|
" specified in :help v_$
|
||||||
|
if mode() ==# "\<c-v>"
|
||||||
|
let l:pos = vimtex#pos#get_cursor()
|
||||||
|
if len(l:pos) == 5 && l:pos[-1] == 2147483647
|
||||||
|
call feedkeys('$', 'in')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:current = vimtex#delim#get_current('all', 'both')
|
||||||
|
if empty(l:current) | return | endif
|
||||||
|
|
||||||
|
let l:corresponding = vimtex#delim#get_matching(l:current)
|
||||||
|
if empty(l:corresponding) | return | endif
|
||||||
|
if empty(l:corresponding.match) | return | endif
|
||||||
|
|
||||||
|
let [l:open, l:close] = l:current.is_open
|
||||||
|
\ ? [l:current, l:corresponding]
|
||||||
|
\ : [l:corresponding, l:current]
|
||||||
|
|
||||||
|
if exists('*matchaddpos')
|
||||||
|
let w:vimtex_match_id1 = matchaddpos('MatchParen',
|
||||||
|
\ [[l:open.lnum, l:open.cnum, strlen(l:open.match)]])
|
||||||
|
let w:vimtex_match_id2 = matchaddpos('MatchParen',
|
||||||
|
\ [[l:close.lnum, l:close.cnum, strlen(l:close.match)]])
|
||||||
|
else
|
||||||
|
let w:vimtex_match_id1 = matchadd('MatchParen',
|
||||||
|
\ '\%' . l:open.lnum . 'l\%' . l:open.cnum . 'c' . l:open.re.this)
|
||||||
|
let w:vimtex_match_id2 = matchadd('MatchParen',
|
||||||
|
\ '\%' . l:close.lnum . 'l\%' . l:close.cnum . 'c' . l:close.re.this)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
158
autoload/vimtex/misc.vim
Normal file
158
autoload/vimtex/misc.vim
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#misc#init_buffer() abort " {{{1
|
||||||
|
command! -buffer VimtexReload call vimtex#misc#reload()
|
||||||
|
command! -buffer -bang -range=% VimtexCountWords
|
||||||
|
\ call vimtex#misc#wordcount_display({
|
||||||
|
\ 'range' : [<line1>, <line2>],
|
||||||
|
\ 'detailed' : <q-bang> == '!',
|
||||||
|
\ 'count_letters' : 0,
|
||||||
|
\ })
|
||||||
|
command! -buffer -bang -range=% VimtexCountLetters
|
||||||
|
\ call vimtex#misc#wordcount_display({
|
||||||
|
\ 'range' : [<line1>, <line2>],
|
||||||
|
\ 'detailed' : <q-bang> == '!',
|
||||||
|
\ 'count_letters' : 1,
|
||||||
|
\ })
|
||||||
|
|
||||||
|
nnoremap <buffer> <plug>(vimtex-reload) :VimtexReload<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#misc#get_graphicspath(fname) abort " {{{1
|
||||||
|
for l:root in b:vimtex.graphicspath + ['.']
|
||||||
|
let l:candidate = simplify(b:vimtex.root . '/' . l:root . '/' . a:fname)
|
||||||
|
for l:suffix in ['', '.jpg', '.png', '.pdf']
|
||||||
|
if filereadable(l:candidate . l:suffix)
|
||||||
|
return l:candidate . l:suffix
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return a:fname
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#misc#wordcount(...) abort " {{{1
|
||||||
|
let l:opts = a:0 > 0 ? a:1 : {}
|
||||||
|
|
||||||
|
let l:range = get(l:opts, 'range', [1, line('$')])
|
||||||
|
if l:range == [1, line('$')]
|
||||||
|
let l:file = b:vimtex
|
||||||
|
else
|
||||||
|
let l:file = vimtex#parser#selection_to_texfile('arg', l:range)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let cmd = 'cd ' . vimtex#util#shellescape(l:file.root)
|
||||||
|
let cmd .= has('win32') ? '& ' : '; '
|
||||||
|
let cmd .= 'texcount -nosub -sum '
|
||||||
|
let cmd .= get(l:opts, 'count_letters') ? '-letter ' : ''
|
||||||
|
let cmd .= get(l:opts, 'detailed') ? '-inc ' : '-q -1 -merge '
|
||||||
|
let cmd .= g:vimtex_texcount_custom_arg . ' '
|
||||||
|
let cmd .= vimtex#util#shellescape(l:file.base)
|
||||||
|
let lines = vimtex#process#capture(cmd)
|
||||||
|
|
||||||
|
if l:file.base !=# b:vimtex.base
|
||||||
|
call delete(l:file.tex)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(l:opts, 'detailed')
|
||||||
|
return lines
|
||||||
|
else
|
||||||
|
call filter(lines, 'v:val !~# ''ERROR\|^\s*$''')
|
||||||
|
return join(lines, '')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#misc#wordcount_display(opts) abort " {{{1
|
||||||
|
let output = vimtex#misc#wordcount(a:opts)
|
||||||
|
|
||||||
|
if !get(a:opts, 'detailed')
|
||||||
|
call vimtex#log#info('Counted '
|
||||||
|
\ . (get(a:opts, 'count_letters') ? 'letters: ' : 'words: ')
|
||||||
|
\ . output)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Create wordcount window
|
||||||
|
if bufnr('TeXcount') >= 0
|
||||||
|
bwipeout TeXcount
|
||||||
|
endif
|
||||||
|
split TeXcount
|
||||||
|
|
||||||
|
" Add lines to buffer
|
||||||
|
for line in output
|
||||||
|
call append('$', printf('%s', line))
|
||||||
|
endfor
|
||||||
|
0delete _
|
||||||
|
|
||||||
|
" Set mappings
|
||||||
|
nnoremap <buffer><nowait><silent> q :bwipeout<cr>
|
||||||
|
|
||||||
|
" Set buffer options
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
setlocal buftype=nofile
|
||||||
|
setlocal cursorline
|
||||||
|
setlocal nobuflisted
|
||||||
|
setlocal nolist
|
||||||
|
setlocal nospell
|
||||||
|
setlocal noswapfile
|
||||||
|
setlocal nowrap
|
||||||
|
setlocal tabstop=8
|
||||||
|
setlocal nomodifiable
|
||||||
|
|
||||||
|
" Set highlighting
|
||||||
|
syntax match TexcountText /^.*:.*/ contains=TexcountValue
|
||||||
|
syntax match TexcountValue /.*:\zs.*/
|
||||||
|
highlight link TexcountText VimtexMsg
|
||||||
|
highlight link TexcountValue Constant
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
" {{{1 function! vimtex#misc#reload()
|
||||||
|
if get(s:, 'reload_guard', 1)
|
||||||
|
function! vimtex#misc#reload() abort
|
||||||
|
let s:reload_guard = 0
|
||||||
|
|
||||||
|
for l:file in glob(fnamemodify(s:file, ':h') . '/../**/*.vim', 0, 1)
|
||||||
|
execute 'source' l:file
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Temporarily unset b:current_syntax (if active)
|
||||||
|
let l:reload_syntax = get(b:, 'current_syntax', '') ==# 'tex'
|
||||||
|
if l:reload_syntax
|
||||||
|
unlet b:current_syntax
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#init()
|
||||||
|
|
||||||
|
" Reload syntax
|
||||||
|
if l:reload_syntax
|
||||||
|
runtime! syntax/tex.vim
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Reload indent file
|
||||||
|
if exists('b:did_vimtex_indent')
|
||||||
|
unlet b:did_indent
|
||||||
|
runtime indent/tex.vim
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#log#info('The plugin has been reloaded!')
|
||||||
|
unlet s:reload_guard
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:file = expand('<sfile>')
|
||||||
|
|
||||||
|
endif
|
||||||
207
autoload/vimtex/motion.vim
Normal file
207
autoload/vimtex/motion.vim
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#motion#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_motion_enabled | return | endif
|
||||||
|
|
||||||
|
" Utility map to avoid conflict with "normal" command
|
||||||
|
nnoremap <buffer> <sid>(v) v
|
||||||
|
nnoremap <buffer> <sid>(V) V
|
||||||
|
|
||||||
|
" Matching pairs
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-%) :call vimtex#motion#find_matching_pair()<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-%) :<c-u>call vimtex#motion#find_matching_pair(1)<cr>
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-%) <sid>(vimtex-%)
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-%) :execute "normal \<sid>(v)\<sid>(vimtex-%)"<cr>
|
||||||
|
|
||||||
|
" Sections
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-]]) :<c-u>call vimtex#motion#section(0,0,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-][) :<c-u>call vimtex#motion#section(1,0,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-[]) :<c-u>call vimtex#motion#section(1,1,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-[[) :<c-u>call vimtex#motion#section(0,1,0)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-]]) :<c-u>call vimtex#motion#section(0,0,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-][) :<c-u>call vimtex#motion#section(1,0,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-[]) :<c-u>call vimtex#motion#section(1,1,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-[[) :<c-u>call vimtex#motion#section(0,1,1)<cr>
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-]]) <sid>(vimtex-]])
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-][) <sid>(vimtex-][)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-[]) <sid>(vimtex-[])
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-[[) <sid>(vimtex-[[)
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-]])
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-]])"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-][)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-][)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-[])
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-[])"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-[[)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-[[)"<cr>
|
||||||
|
|
||||||
|
" Environments
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-]m) :<c-u>call vimtex#motion#environment(1,0,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-]M) :<c-u>call vimtex#motion#environment(0,0,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-[m) :<c-u>call vimtex#motion#environment(1,1,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-[M) :<c-u>call vimtex#motion#environment(0,1,0)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-]m) :<c-u>call vimtex#motion#environment(1,0,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-]M) :<c-u>call vimtex#motion#environment(0,0,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-[m) :<c-u>call vimtex#motion#environment(1,1,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-[M) :<c-u>call vimtex#motion#environment(0,1,1)<cr>
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-]m) <sid>(vimtex-]m)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-]M) <sid>(vimtex-]M)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-[m) <sid>(vimtex-[m)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-[M) <sid>(vimtex-[M)
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-]m)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-]m)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-]M)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-]M)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-[m)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-[m)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-[M)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-[M)"<cr>
|
||||||
|
|
||||||
|
" Comments
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-]/) :<c-u>call vimtex#motion#comment(1,0,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-]*) :<c-u>call vimtex#motion#comment(0,0,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-[/) :<c-u>call vimtex#motion#comment(1,1,0)<cr>
|
||||||
|
nnoremap <silent><buffer> <plug>(vimtex-[*) :<c-u>call vimtex#motion#comment(0,1,0)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-]/) :<c-u>call vimtex#motion#comment(1,0,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-]*) :<c-u>call vimtex#motion#comment(0,0,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-[/) :<c-u>call vimtex#motion#comment(1,1,1)<cr>
|
||||||
|
xnoremap <silent><buffer> <sid>(vimtex-[*) :<c-u>call vimtex#motion#comment(0,1,1)<cr>
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-]/) <sid>(vimtex-]/)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-]*) <sid>(vimtex-]*)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-[/) <sid>(vimtex-[/)
|
||||||
|
xmap <silent><buffer> <plug>(vimtex-[*) <sid>(vimtex-[*)
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-]/)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-]/)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-]*)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-]*)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-[/)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-[/)"<cr>
|
||||||
|
onoremap <silent><buffer> <plug>(vimtex-[*)
|
||||||
|
\ :execute "normal \<sid>(V)" . v:count1 . "\<sid>(vimtex-[*)"<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#motion#find_matching_pair(...) abort " {{{1
|
||||||
|
if a:0 > 0
|
||||||
|
normal! gv
|
||||||
|
endif
|
||||||
|
|
||||||
|
let delim = vimtex#delim#get_current('all', 'both')
|
||||||
|
if empty(delim)
|
||||||
|
let delim = vimtex#delim#get_next('all', 'both')
|
||||||
|
if empty(delim) | return | endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let delim = vimtex#delim#get_matching(delim)
|
||||||
|
if empty(delim) | return | endif
|
||||||
|
if empty(delim.match) | return | endif
|
||||||
|
|
||||||
|
normal! m`
|
||||||
|
call vimtex#pos#set_cursor(delim.lnum,
|
||||||
|
\ (delim.is_open
|
||||||
|
\ ? delim.cnum
|
||||||
|
\ : delim.cnum + strlen(delim.match) - 1))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#motion#section(type, backwards, visual) abort " {{{1
|
||||||
|
let l:count = v:count1
|
||||||
|
if a:visual
|
||||||
|
normal! gv
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Check trivial cases
|
||||||
|
let l:top = search(s:re_sec, 'nbW') == 0
|
||||||
|
let l:bottom = search(a:type == 1 ? s:re_sec_t2 : s:re_sec, 'nW') == 0
|
||||||
|
if a:backwards && l:top
|
||||||
|
return vimtex#pos#set_cursor([1, 1])
|
||||||
|
elseif !a:backwards && l:bottom
|
||||||
|
return vimtex#pos#set_cursor([line('$'), 1])
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Define search pattern and search flag
|
||||||
|
let l:re = a:type == 0 ? s:re_sec : s:re_sec_t1
|
||||||
|
let l:flags = 'W'
|
||||||
|
if a:backwards
|
||||||
|
let l:flags .= 'b'
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:_ in range(l:count)
|
||||||
|
let l:save_pos = vimtex#pos#get_cursor()
|
||||||
|
|
||||||
|
if a:type == 1
|
||||||
|
call search('\S', 'W')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:bottom = search(s:re_sec_t2, 'nW') == 0
|
||||||
|
if a:type == 1 && !a:backwards && l:bottom
|
||||||
|
return vimtex#pos#set_cursor([line('$'), 1])
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:top = search(s:re_sec, 'ncbW') == 0
|
||||||
|
let l:lnum = search(l:re, l:flags)
|
||||||
|
|
||||||
|
if l:top && l:lnum > 0 && a:type == 1 && !a:backwards
|
||||||
|
let l:lnum = search(l:re, l:flags)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:type == 1
|
||||||
|
call search('\S\s*\n\zs', 'Wb')
|
||||||
|
|
||||||
|
" Move to start of file if cursor was moved to top part of document
|
||||||
|
if search(s:re_sec, 'ncbW') == 0
|
||||||
|
call vimtex#pos#set_cursor([1, 1])
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#motion#environment(begin, backwards, visual) abort " {{{1
|
||||||
|
let l:count = v:count1
|
||||||
|
if a:visual
|
||||||
|
normal! gv
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:re = g:vimtex#re#not_comment . (a:begin ? '\\begin\s*\{' : '\\end\s*\{')
|
||||||
|
let l:flags = 'W' . (a:backwards ? 'b' : '')
|
||||||
|
|
||||||
|
for l:_ in range(l:count)
|
||||||
|
call search(l:re, l:flags)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#motion#comment(begin, backwards, visual) abort " {{{1
|
||||||
|
let l:count = v:count1
|
||||||
|
if a:visual
|
||||||
|
normal! gv
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:re = a:begin
|
||||||
|
\ ? '\v%(^\s*\%.*\n)@<!\s*\%'
|
||||||
|
\ : '\v^\s*\%.*\n%(^\s*\%)@!'
|
||||||
|
let l:flags = 'W' . (a:backwards ? 'b' : '')
|
||||||
|
|
||||||
|
for l:_ in range(l:count)
|
||||||
|
call search(l:re, l:flags)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
" Patterns to match section/chapter/...
|
||||||
|
let s:re_sec = '\v^\s*\\%(%(sub)?paragraph|%(sub)*section|chapter|part|'
|
||||||
|
\ . 'appendi%(x|ces)|%(front|back|main)matter)>'
|
||||||
|
let s:re_sec_t1 = '\v%(' . s:re_sec . '|^\s*%(\\end\{document\}|%$))'
|
||||||
|
let s:re_sec_t2 = '\v%(' . s:re_sec . '|^\s*\\end\{document\})'
|
||||||
|
|
||||||
|
endif
|
||||||
144
autoload/vimtex/parser.vim
Normal file
144
autoload/vimtex/parser.vim
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#parser#tex(file, ...) abort " {{{1
|
||||||
|
return vimtex#parser#tex#parse(a:file, a:0 > 0 ? a:1 : {})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#preamble(file, ...) abort " {{{1
|
||||||
|
return vimtex#parser#tex#parse_preamble(a:file, a:0 > 0 ? a:1 : {})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#auxiliary(file) abort " {{{1
|
||||||
|
return vimtex#parser#auxiliary#parse(a:file)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#fls(file) abort " {{{1
|
||||||
|
return vimtex#parser#fls#parse(a:file)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#toc(...) abort " {{{1
|
||||||
|
let l:vimtex = a:0 > 0 ? a:1 : b:vimtex
|
||||||
|
|
||||||
|
let l:cache = vimtex#cache#open('parsertoc', {
|
||||||
|
\ 'persistent': 0,
|
||||||
|
\ 'default': {'entries': [], 'ftime': -1},
|
||||||
|
\})
|
||||||
|
let l:current = l:cache.get(l:vimtex.tex)
|
||||||
|
|
||||||
|
" Update cache if relevant
|
||||||
|
let l:ftime = l:vimtex.getftime()
|
||||||
|
if l:ftime > l:current.ftime
|
||||||
|
let l:cache.modified = 1
|
||||||
|
let l:current.ftime = l:ftime
|
||||||
|
let l:current.entries = vimtex#parser#toc#parse(l:vimtex.tex)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return deepcopy(l:current.entries)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#bib(file, ...) abort " {{{1
|
||||||
|
return vimtex#parser#bib#parse(a:file, a:0 > 0 ? a:1 : {})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#parser#get_externalfiles() abort " {{{1
|
||||||
|
let l:preamble = vimtex#parser#preamble(b:vimtex.tex)
|
||||||
|
|
||||||
|
let l:result = []
|
||||||
|
for l:line in filter(l:preamble, 'v:val =~# ''\\externaldocument''')
|
||||||
|
let l:name = matchstr(l:line, '{\zs[^}]*\ze}')
|
||||||
|
call add(l:result, {
|
||||||
|
\ 'tex' : l:name . '.tex',
|
||||||
|
\ 'aux' : l:name . '.aux',
|
||||||
|
\ 'opt' : matchstr(l:line, '\[\zs[^]]*\ze\]'),
|
||||||
|
\ })
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:result
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#selection_to_texfile(type, ...) range abort " {{{1
|
||||||
|
"
|
||||||
|
" Get selected lines. Method depends on type of selection, which may be
|
||||||
|
" either of
|
||||||
|
"
|
||||||
|
" 1. range from argument
|
||||||
|
" 2. Command range
|
||||||
|
" 3. Visual mapping
|
||||||
|
" 4. Operator mapping
|
||||||
|
"
|
||||||
|
if a:type ==# 'arg'
|
||||||
|
let l:lines = getline(a:1[0], a:1[1])
|
||||||
|
elseif a:type ==# 'cmd'
|
||||||
|
let l:lines = getline(a:firstline, a:lastline)
|
||||||
|
elseif a:type ==# 'visual'
|
||||||
|
let l:lines = getline(line("'<"), line("'>"))
|
||||||
|
else
|
||||||
|
let l:lines = getline(line("'["), line("']"))
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Use only the part of the selection that is within the
|
||||||
|
"
|
||||||
|
" \begin{document} ... \end{document}
|
||||||
|
"
|
||||||
|
" environment.
|
||||||
|
"
|
||||||
|
let l:start = 0
|
||||||
|
let l:end = len(l:lines)
|
||||||
|
for l:n in range(len(l:lines))
|
||||||
|
if l:lines[l:n] =~# '\\begin\s*{document}'
|
||||||
|
let l:start = l:n + 1
|
||||||
|
elseif l:lines[l:n] =~# '\\end\s*{document}'
|
||||||
|
let l:end = l:n - 1
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
"
|
||||||
|
" Check if the selection has any real content
|
||||||
|
"
|
||||||
|
if l:start >= len(l:lines)
|
||||||
|
\ || l:end < 0
|
||||||
|
\ || empty(substitute(join(l:lines[l:start : l:end], ''), '\s*', '', ''))
|
||||||
|
return {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Define the set of lines to compile
|
||||||
|
"
|
||||||
|
let l:lines = vimtex#parser#preamble(b:vimtex.tex)
|
||||||
|
\ + ['\begin{document}']
|
||||||
|
\ + l:lines[l:start : l:end]
|
||||||
|
\ + ['\end{document}']
|
||||||
|
|
||||||
|
"
|
||||||
|
" Write content to temporary file
|
||||||
|
"
|
||||||
|
let l:file = {}
|
||||||
|
let l:file.root = b:vimtex.root
|
||||||
|
let l:file.base = b:vimtex.name . '_vimtex_selected.tex'
|
||||||
|
let l:file.tex = l:file.root . '/' . l:file.base
|
||||||
|
let l:file.pdf = fnamemodify(l:file.tex, ':r') . '.pdf'
|
||||||
|
let l:file.log = fnamemodify(l:file.tex, ':r') . '.log'
|
||||||
|
call writefile(l:lines, l:file.tex)
|
||||||
|
|
||||||
|
return l:file
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
58
autoload/vimtex/parser/auxiliary.vim
Normal file
58
autoload/vimtex/parser/auxiliary.vim
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#parser#auxiliary#parse(file) abort " {{{1
|
||||||
|
return s:parse_recurse(a:file, [])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse_recurse(file, parsed) abort " {{{1
|
||||||
|
if !filereadable(a:file) || index(a:parsed, a:file) >= 0
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
call add(a:parsed, a:file)
|
||||||
|
|
||||||
|
let l:lines = []
|
||||||
|
for l:line in readfile(a:file)
|
||||||
|
call add(l:lines, l:line)
|
||||||
|
|
||||||
|
if l:line =~# '\\@input{'
|
||||||
|
let l:file = s:input_line_parser(l:line, a:file)
|
||||||
|
call extend(l:lines, s:parse_recurse(l:file, a:parsed))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:lines
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:input_line_parser(line, file) abort " {{{1
|
||||||
|
let l:file = matchstr(a:line, '\\@input{\zs[^}]\+\ze}')
|
||||||
|
|
||||||
|
" Remove extension to simplify the parsing (e.g. for "my file name".aux)
|
||||||
|
let l:file = substitute(l:file, '\.aux', '', '')
|
||||||
|
|
||||||
|
" Trim whitespaces and quotes from beginning/end of string, append extension
|
||||||
|
let l:file = substitute(l:file, '^\(\s\|"\)*', '', '')
|
||||||
|
let l:file = substitute(l:file, '\(\s\|"\)*$', '', '')
|
||||||
|
let l:file .= '.aux'
|
||||||
|
|
||||||
|
" Use absolute paths
|
||||||
|
if l:file !~# '\v^(\/|[A-Z]:)'
|
||||||
|
let l:file = fnamemodify(a:file, ':p:h') . '/' . l:file
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Only return filename if it is readable
|
||||||
|
return filereadable(l:file) ? l:file : ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
370
autoload/vimtex/parser/bib.vim
Normal file
370
autoload/vimtex/parser/bib.vim
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#parser#bib#parse(file, opts) abort " {{{1
|
||||||
|
if !filereadable(a:file) | return [] | endif
|
||||||
|
|
||||||
|
let l:backend = get(a:opts, 'backend', g:vimtex_parser_bib_backend)
|
||||||
|
|
||||||
|
if l:backend ==# 'bibtex'
|
||||||
|
if !executable('bibtex') | let l:backend = 'vim' | endif
|
||||||
|
elseif l:backend ==# 'bibparse'
|
||||||
|
if !executable('bibparse') | let l:backend = 'vim' | endif
|
||||||
|
else
|
||||||
|
let l:backend = 'vim'
|
||||||
|
endif
|
||||||
|
|
||||||
|
return s:parse_with_{l:backend}(a:file)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
function! s:parse_with_bibtex(file) abort " {{{1
|
||||||
|
call s:parse_with_bibtex_init()
|
||||||
|
if s:bibtex_not_executable | return [] | endif
|
||||||
|
|
||||||
|
" Define temporary files
|
||||||
|
let tmp = {
|
||||||
|
\ 'aux' : 'tmpfile.aux',
|
||||||
|
\ 'bbl' : 'tmpfile.bbl',
|
||||||
|
\ 'blg' : 'tmpfile.blg',
|
||||||
|
\ }
|
||||||
|
|
||||||
|
" Write temporary aux file
|
||||||
|
call writefile([
|
||||||
|
\ '\citation{*}',
|
||||||
|
\ '\bibstyle{' . s:bibtex_bstfile . '}',
|
||||||
|
\ '\bibdata{' . fnamemodify(a:file, ':r') . '}',
|
||||||
|
\ ], tmp.aux)
|
||||||
|
|
||||||
|
" Create the temporary bbl file
|
||||||
|
call vimtex#process#run('bibtex -terse ' . fnameescape(tmp.aux), {
|
||||||
|
\ 'background' : 0,
|
||||||
|
\ 'silent' : 1,
|
||||||
|
\})
|
||||||
|
|
||||||
|
" Parse temporary bbl file
|
||||||
|
let lines = join(readfile(tmp.bbl), "\n")
|
||||||
|
let lines = substitute(lines, '\n\n\@!\(\s\=\)\s*\|{\|}', '\1', 'g')
|
||||||
|
let lines = vimtex#util#tex2unicode(lines)
|
||||||
|
let lines = split(lines, "\n")
|
||||||
|
|
||||||
|
let l:entries = []
|
||||||
|
for line in lines
|
||||||
|
let matches = split(line, '||')
|
||||||
|
if empty(matches) || empty(matches[0]) | continue | endif
|
||||||
|
|
||||||
|
let l:entry = {
|
||||||
|
\ 'key': matches[0],
|
||||||
|
\ 'type': matches[1],
|
||||||
|
\}
|
||||||
|
|
||||||
|
if !empty(matches[2])
|
||||||
|
let l:entry.author = matches[2]
|
||||||
|
endif
|
||||||
|
if !empty(matches[3])
|
||||||
|
let l:entry.year = matches[3]
|
||||||
|
endif
|
||||||
|
if !empty(get(matches, 4, ''))
|
||||||
|
let l:entry.title = get(matches, 4, '')
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:entries, l:entry)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Clean up
|
||||||
|
call delete(tmp.aux)
|
||||||
|
call delete(tmp.bbl)
|
||||||
|
call delete(tmp.blg)
|
||||||
|
|
||||||
|
return l:entries
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_with_bibtex_init() abort " {{{1
|
||||||
|
if exists('s:bibtex_init_done') | return | endif
|
||||||
|
|
||||||
|
" Check if bibtex is executable
|
||||||
|
let s:bibtex_not_executable = !executable('bibtex')
|
||||||
|
if s:bibtex_not_executable
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'bibtex is not executable and may not be used to parse bib files!')
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Check if bstfile contains whitespace (not handled by vimtex)
|
||||||
|
if stridx(s:bibtex_bstfile, ' ') >= 0
|
||||||
|
let l:oldbst = s:bibtex_bstfile . '.bst'
|
||||||
|
let s:bibtex_bstfile = tempname()
|
||||||
|
call writefile(readfile(l:oldbst), s:bibtex_bstfile . '.bst')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:bibtex_init_done = 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:bibtex_bstfile = expand('<sfile>:p:h') . '/vimcomplete'
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse_with_bibparse(file) abort " {{{1
|
||||||
|
call s:parse_with_bibparse_init()
|
||||||
|
if s:bibparse_not_executable | return [] | endif
|
||||||
|
|
||||||
|
call vimtex#process#run('bibparse ' . fnameescape(a:file)
|
||||||
|
\ . ' >_vimtex_bibparsed.log', {'background' : 0, 'silent' : 1})
|
||||||
|
let l:lines = readfile('_vimtex_bibparsed.log')
|
||||||
|
call delete('_vimtex_bibparsed.log')
|
||||||
|
|
||||||
|
let l:current = {}
|
||||||
|
let l:entries = []
|
||||||
|
for l:line in l:lines
|
||||||
|
if l:line[0] ==# '@'
|
||||||
|
if !empty(l:current)
|
||||||
|
call add(l:entries, l:current)
|
||||||
|
let l:current = {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:index = stridx(l:line, ' ')
|
||||||
|
if l:index > 0
|
||||||
|
let l:type = l:line[1:l:index-1]
|
||||||
|
let l:current.type = l:type
|
||||||
|
let l:current.key = l:line[l:index+1:]
|
||||||
|
endif
|
||||||
|
elseif !empty(l:current)
|
||||||
|
let l:index = stridx(l:line, '=')
|
||||||
|
if l:index < 0 | continue | endif
|
||||||
|
|
||||||
|
let l:key = l:line[:l:index-1]
|
||||||
|
let l:value = l:line[l:index+1:]
|
||||||
|
let l:current[tolower(l:key)] = l:value
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if !empty(l:current)
|
||||||
|
call add(l:entries, l:current)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:entries
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_with_bibparse_init() abort " {{{1
|
||||||
|
if exists('s:bibparse_init_done') | return | endif
|
||||||
|
|
||||||
|
" Check if bibtex is executable
|
||||||
|
let s:bibparse_not_executable = !executable('bibparse')
|
||||||
|
if s:bibparse_not_executable
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'bibparse is not executable and may not be used to parse bib files!')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:bibparse_init_done = 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse_with_vim(file) abort " {{{1
|
||||||
|
" Adheres to the format description found here:
|
||||||
|
" http://www.bibtex.org/Format/
|
||||||
|
|
||||||
|
if !filereadable(a:file)
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:current = {}
|
||||||
|
let l:strings = {}
|
||||||
|
let l:entries = []
|
||||||
|
for l:line in filter(readfile(a:file), 'v:val !~# ''^\s*\%(%\|$\)''')
|
||||||
|
if empty(l:current)
|
||||||
|
if s:parse_type(l:line, l:current, l:strings)
|
||||||
|
let l:current = {}
|
||||||
|
endif
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:current.type ==# 'string'
|
||||||
|
if s:parse_string(l:line, l:current, l:strings)
|
||||||
|
let l:current = {}
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
if s:parse_entry(l:line, l:current, l:entries)
|
||||||
|
let l:current = {}
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return map(l:entries, 's:parse_entry_body(v:val, l:strings)')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse_type(line, current, strings) abort " {{{1
|
||||||
|
let l:matches = matchlist(a:line, '\v^\@(\w+)\s*\{\s*(.*)')
|
||||||
|
if empty(l:matches) | return 0 | endif
|
||||||
|
|
||||||
|
let l:type = tolower(l:matches[1])
|
||||||
|
if index(['preamble', 'comment'], l:type) >= 0 | return 0 | endif
|
||||||
|
|
||||||
|
let a:current.level = 1
|
||||||
|
let a:current.body = ''
|
||||||
|
|
||||||
|
if l:type ==# 'string'
|
||||||
|
return s:parse_string(l:matches[2], a:current, a:strings)
|
||||||
|
else
|
||||||
|
let a:current.type = l:type
|
||||||
|
let a:current.key = matchstr(l:matches[2], '.*\ze,\s*')
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_string(line, string, strings) abort " {{{1
|
||||||
|
let a:string.level += s:count(a:line, '{') - s:count(a:line, '}')
|
||||||
|
if a:string.level > 0
|
||||||
|
let a:string.body .= a:line
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
let a:string.body .= matchstr(a:line, '.*\ze}')
|
||||||
|
|
||||||
|
let l:matches = matchlist(a:string.body, '\v^\s*(\w+)\s*\=\s*"(.*)"\s*$')
|
||||||
|
if !empty(l:matches) && !empty(l:matches[1])
|
||||||
|
let a:strings[l:matches[1]] = l:matches[2]
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_entry(line, entry, entries) abort " {{{1
|
||||||
|
let a:entry.level += s:count(a:line, '{') - s:count(a:line, '}')
|
||||||
|
if a:entry.level > 0
|
||||||
|
let a:entry.body .= a:line
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
let a:entry.body .= matchstr(a:line, '.*\ze}')
|
||||||
|
|
||||||
|
call add(a:entries, a:entry)
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse_entry_body(entry, strings) abort " {{{1
|
||||||
|
unlet a:entry.level
|
||||||
|
|
||||||
|
let l:key = ''
|
||||||
|
let l:pos = matchend(a:entry.body, '^\s*')
|
||||||
|
while l:pos >= 0
|
||||||
|
if empty(l:key)
|
||||||
|
let [l:key, l:pos] = s:get_key(a:entry.body, l:pos)
|
||||||
|
else
|
||||||
|
let [l:value, l:pos] = s:get_value(a:entry.body, l:pos, a:strings)
|
||||||
|
let a:entry[l:key] = l:value
|
||||||
|
let l:key = ''
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
unlet a:entry.body
|
||||||
|
return a:entry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_key(body, head) abort " {{{1
|
||||||
|
" Parse the key part of a bib entry tag.
|
||||||
|
" Assumption: a:body is left trimmed and either empty or starts with a key.
|
||||||
|
" Returns: The key and the remaining part of the entry body.
|
||||||
|
|
||||||
|
let l:matches = matchlist(a:body, '^\v(\w+)\s*\=\s*', a:head)
|
||||||
|
return empty(l:matches)
|
||||||
|
\ ? ['', -1]
|
||||||
|
\ : [tolower(l:matches[1]), a:head + strlen(l:matches[0])]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_value(body, head, strings) abort " {{{1
|
||||||
|
" Parse the value part of a bib entry tag, until separating comma or end.
|
||||||
|
" Assumption: a:body is left trimmed and either empty or starts with a value.
|
||||||
|
" Returns: The value and the remaining part of the entry body.
|
||||||
|
"
|
||||||
|
" A bib entry value is either
|
||||||
|
" 1. A number.
|
||||||
|
" 2. A concatenation (with #s) of double quoted strings, curlied strings,
|
||||||
|
" and/or bibvariables,
|
||||||
|
"
|
||||||
|
if a:body[a:head] =~# '\d'
|
||||||
|
let l:value = matchstr(a:body, '^\d\+', a:head)
|
||||||
|
let l:head = matchend(a:body, '^\s*,\s*', a:head + len(l:value))
|
||||||
|
return [l:value, l:head]
|
||||||
|
else
|
||||||
|
return s:get_value_string(a:body, a:head, a:strings)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return ['s:get_value failed', -1]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_value_string(body, head, strings) abort " {{{1
|
||||||
|
if a:body[a:head] ==# '{'
|
||||||
|
let l:sum = 1
|
||||||
|
let l:i1 = a:head + 1
|
||||||
|
let l:i0 = l:i1
|
||||||
|
|
||||||
|
while l:sum > 0
|
||||||
|
let [l:match, l:_, l:i1] = matchstrpos(a:body, '[{}]', l:i1)
|
||||||
|
if l:i1 < 0 | break | endif
|
||||||
|
|
||||||
|
let l:i0 = l:i1
|
||||||
|
let l:sum += l:match ==# '{' ? 1 : -1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
let l:value = a:body[a:head+1:l:i0-2]
|
||||||
|
let l:head = matchend(a:body, '^\s*', l:i0)
|
||||||
|
elseif a:body[a:head] ==# '"'
|
||||||
|
let l:index = match(a:body, '\\\@<!"', a:head+1)
|
||||||
|
if l:index < 0
|
||||||
|
return ['s:get_value_string failed', '']
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:value = a:body[a:head+1:l:index-1]
|
||||||
|
let l:head = matchend(a:body, '^\s*', l:index+1)
|
||||||
|
return [l:value, l:head]
|
||||||
|
elseif a:body[a:head:] =~# '^\w'
|
||||||
|
let l:value = matchstr(a:body, '^\w\+', a:head)
|
||||||
|
let l:head = matchend(a:body, '^\s*', a:head + strlen(l:value))
|
||||||
|
let l:value = get(a:strings, l:value, '@(' . l:value . ')')
|
||||||
|
else
|
||||||
|
let l:head = a:head
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:body[l:head] ==# '#'
|
||||||
|
let l:head = matchend(a:body, '^\s*', l:head + 1)
|
||||||
|
let [l:vadd, l:head] = s:get_value_string(a:body, l:head, a:strings)
|
||||||
|
let l:value .= l:vadd
|
||||||
|
endif
|
||||||
|
|
||||||
|
return [l:value, matchend(a:body, '^,\s*', l:head)]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:count(container, item) abort " {{{1
|
||||||
|
" Necessary because in old Vim versions, count() does not work for strings
|
||||||
|
try
|
||||||
|
let l:count = count(a:container, a:item)
|
||||||
|
catch /E712/
|
||||||
|
let l:count = count(split(a:container, '\zs'), a:item)
|
||||||
|
endtry
|
||||||
|
|
||||||
|
return l:count
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
19
autoload/vimtex/parser/fls.vim
Normal file
19
autoload/vimtex/parser/fls.vim
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#parser#fls#parse(file) abort " {{{1
|
||||||
|
if !filereadable(a:file)
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
|
||||||
|
return readfile(a:file)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
205
autoload/vimtex/parser/tex.vim
Normal file
205
autoload/vimtex/parser/tex.vim
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#parser#tex#parse(file, opts) abort " {{{1
|
||||||
|
let l:opts = extend({
|
||||||
|
\ 'detailed': 1,
|
||||||
|
\ 'root' : exists('b:vimtex.root') ? b:vimtex.root : '',
|
||||||
|
\}, a:opts)
|
||||||
|
|
||||||
|
let l:cache = vimtex#cache#open('texparser', {
|
||||||
|
\ 'local': 1,
|
||||||
|
\ 'persistent': 0,
|
||||||
|
\ 'default': {'ftime': -2},
|
||||||
|
\})
|
||||||
|
|
||||||
|
let l:parsed = s:parse(a:file, l:opts, l:cache)
|
||||||
|
|
||||||
|
if !l:opts.detailed
|
||||||
|
call map(l:parsed, 'v:val[2]')
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:parsed
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#tex#parse_files(file, opts) abort " {{{1
|
||||||
|
let l:opts = extend({
|
||||||
|
\ 'root' : exists('b:vimtex.root') ? b:vimtex.root : '',
|
||||||
|
\}, a:opts)
|
||||||
|
|
||||||
|
let l:cache = vimtex#cache#open('texparser', {
|
||||||
|
\ 'local': 1,
|
||||||
|
\ 'persistent': 0,
|
||||||
|
\ 'default': {'ftime': -2},
|
||||||
|
\})
|
||||||
|
|
||||||
|
return vimtex#util#uniq_unsorted(
|
||||||
|
\ s:parse_files(a:file, l:opts, l:cache))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#tex#parse_preamble(file, opts) abort " {{{1
|
||||||
|
let l:opts = extend({
|
||||||
|
\ 'inclusive' : 0,
|
||||||
|
\ 'root' : exists('b:vimtex.root') ? b:vimtex.root : '',
|
||||||
|
\}, a:opts)
|
||||||
|
|
||||||
|
return s:parse_preamble(a:file, l:opts, [])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse(file, opts, cache) abort " {{{1
|
||||||
|
let l:current = a:cache.get(a:file)
|
||||||
|
let l:ftime = getftime(a:file)
|
||||||
|
if l:ftime > l:current.ftime
|
||||||
|
let l:current.ftime = l:ftime
|
||||||
|
call s:parse_current(a:file, a:opts, l:current)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:parsed = []
|
||||||
|
|
||||||
|
for l:val in l:current.lines
|
||||||
|
if type(l:val) == type([])
|
||||||
|
call add(l:parsed, l:val)
|
||||||
|
else
|
||||||
|
call extend(l:parsed, s:parse(l:val, a:opts, a:cache))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:parsed
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_files(file, opts, cache) abort " {{{1
|
||||||
|
let l:current = a:cache.get(a:file)
|
||||||
|
let l:ftime = getftime(a:file)
|
||||||
|
if l:ftime > l:current.ftime
|
||||||
|
let l:current.ftime = l:ftime
|
||||||
|
call s:parse_current(a:file, a:opts, l:current)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Only include existing files
|
||||||
|
if !filereadable(a:file) | return [] | endif
|
||||||
|
|
||||||
|
let l:files = [a:file]
|
||||||
|
for l:file in l:current.includes
|
||||||
|
let l:files += s:parse_files(l:file, a:opts, a:cache)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:files
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_current(file, opts, current) abort " {{{1
|
||||||
|
let a:current.lines = []
|
||||||
|
let a:current.includes = []
|
||||||
|
|
||||||
|
" Also load includes from glsentries
|
||||||
|
let l:re_input = g:vimtex#re#tex_input . '|^\s*\\loadglsentries'
|
||||||
|
|
||||||
|
if filereadable(a:file)
|
||||||
|
let l:lnum = 0
|
||||||
|
for l:line in readfile(a:file)
|
||||||
|
let l:lnum += 1
|
||||||
|
call add(a:current.lines, [a:file, l:lnum, l:line])
|
||||||
|
|
||||||
|
" Minor optimization: Avoid complex regex on "simple" lines
|
||||||
|
if stridx(l:line, '\') < 0 | continue | endif
|
||||||
|
|
||||||
|
if l:line =~# l:re_input
|
||||||
|
let l:file = s:input_parser(l:line, a:file, a:opts.root)
|
||||||
|
call add(a:current.lines, l:file)
|
||||||
|
call add(a:current.includes, l:file)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:parse_preamble(file, opts, parsed_files) abort " {{{1
|
||||||
|
if !filereadable(a:file) || index(a:parsed_files, a:file) >= 0
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
call add(a:parsed_files, a:file)
|
||||||
|
|
||||||
|
let l:lines = []
|
||||||
|
for l:line in readfile(a:file)
|
||||||
|
if l:line =~# '\\begin\s*{document}'
|
||||||
|
if a:opts.inclusive
|
||||||
|
call add(l:lines, l:line)
|
||||||
|
endif
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:lines, l:line)
|
||||||
|
|
||||||
|
if l:line =~# g:vimtex#re#tex_input
|
||||||
|
let l:file = s:input_parser(l:line, a:file, a:opts.root)
|
||||||
|
call extend(l:lines, s:parse_preamble(l:file, a:opts, a:parsed_files))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:lines
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:input_parser(line, current_file, root) abort " {{{1
|
||||||
|
" Handle \space commands
|
||||||
|
let l:file = substitute(a:line, '\\space\s*', ' ', 'g')
|
||||||
|
|
||||||
|
" Handle import package commands
|
||||||
|
if l:file =~# g:vimtex#re#tex_input_import
|
||||||
|
let l:root = l:file =~# '\\sub'
|
||||||
|
\ ? fnamemodify(a:current_file, ':p:h')
|
||||||
|
\ : a:root
|
||||||
|
|
||||||
|
let l:candidate = s:input_to_filename(
|
||||||
|
\ substitute(copy(l:file), '}\s*{', '', 'g'), l:root)
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return l:candidate
|
||||||
|
else
|
||||||
|
return s:input_to_filename(
|
||||||
|
\ substitute(copy(l:file), '{.{-}}', '', ''), l:root)
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
return s:input_to_filename(l:file, a:root)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:input_to_filename(input, root) abort " {{{1
|
||||||
|
let l:file = matchstr(a:input, '\zs[^{}]\+\ze}\s*\%(%\|$\)')
|
||||||
|
|
||||||
|
" Trim whitespaces and quotes from beginning/end of string
|
||||||
|
let l:file = substitute(l:file, '^\(\s\|"\)*', '', '')
|
||||||
|
let l:file = substitute(l:file, '\(\s\|"\)*$', '', '')
|
||||||
|
|
||||||
|
" Ensure that the file name has extension
|
||||||
|
if empty(fnamemodify(l:file, ':e'))
|
||||||
|
let l:file .= '.tex'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if vimtex#paths#is_abs(l:file)
|
||||||
|
return l:file
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:candidate = a:root . '/' . l:file
|
||||||
|
if filereadable(l:candidate)
|
||||||
|
return l:candidate
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:candidate = vimtex#kpsewhich#find(l:file)
|
||||||
|
return filereadable(l:candidate) ? l:candidate : l:file
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
778
autoload/vimtex/parser/toc.vim
Normal file
778
autoload/vimtex/parser/toc.vim
Normal file
@@ -0,0 +1,778 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
"
|
||||||
|
" Parses tex project for ToC-like entries. Each entry is a dictionary
|
||||||
|
" similar to the following:
|
||||||
|
"
|
||||||
|
" entry = {
|
||||||
|
" title : "Some title",
|
||||||
|
" number : "3.1.2",
|
||||||
|
" file : /path/to/file.tex,
|
||||||
|
" line : 142,
|
||||||
|
" rank : cumulative line number,
|
||||||
|
" level : 2,
|
||||||
|
" type : [content | label | todo | include],
|
||||||
|
" link : [0 | 1],
|
||||||
|
" }
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#parser#toc#parse(file) abort " {{{1
|
||||||
|
let l:entries = []
|
||||||
|
let l:content = vimtex#parser#tex(a:file)
|
||||||
|
|
||||||
|
let l:max_level = 0
|
||||||
|
for [l:file, l:lnum, l:line] in l:content
|
||||||
|
if l:line =~# s:matcher_sections.re
|
||||||
|
let l:max_level = max([
|
||||||
|
\ l:max_level,
|
||||||
|
\ s:sec_to_value[matchstr(l:line, s:matcher_sections.re_level)]
|
||||||
|
\])
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call s:level.reset('preamble', l:max_level)
|
||||||
|
|
||||||
|
" No more parsing if there is no content
|
||||||
|
if empty(l:content) | return l:entries | endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Begin parsing LaTeX files
|
||||||
|
"
|
||||||
|
let l:lnum_total = 0
|
||||||
|
let l:matchers = s:matchers_preamble
|
||||||
|
for [l:file, l:lnum, l:line] in l:content
|
||||||
|
let l:lnum_total += 1
|
||||||
|
let l:context = {
|
||||||
|
\ 'file' : l:file,
|
||||||
|
\ 'line' : l:line,
|
||||||
|
\ 'lnum' : l:lnum,
|
||||||
|
\ 'lnum_total' : l:lnum_total,
|
||||||
|
\ 'level' : s:level,
|
||||||
|
\ 'max_level' : l:max_level,
|
||||||
|
\ 'entry' : get(l:entries, -1, {}),
|
||||||
|
\ 'num_entries' : len(l:entries),
|
||||||
|
\}
|
||||||
|
|
||||||
|
" Detect end of preamble
|
||||||
|
if s:level.preamble && l:line =~# '\v^\s*\\begin\{document\}'
|
||||||
|
let s:level.preamble = 0
|
||||||
|
let l:matchers = s:matchers_content
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Handle multi-line entries
|
||||||
|
if exists('s:matcher_continue')
|
||||||
|
call s:matcher_continue.continue(l:context)
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Apply prefilter - this gives considerable speedup for large documents
|
||||||
|
if l:line !~# s:re_prefilter | continue | endif
|
||||||
|
|
||||||
|
" Apply the matchers
|
||||||
|
for l:matcher in l:matchers
|
||||||
|
if l:line =~# l:matcher.re
|
||||||
|
let l:entry = l:matcher.get_entry(l:context)
|
||||||
|
if type(l:entry) == type([])
|
||||||
|
call extend(l:entries, l:entry)
|
||||||
|
elseif !empty(l:entry)
|
||||||
|
call add(l:entries, l:entry)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
for l:matcher in s:matchers
|
||||||
|
try
|
||||||
|
call l:matcher.filter(l:entries)
|
||||||
|
catch /E716/
|
||||||
|
endtry
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:entries
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#toc#get_topmatters() abort " {{{1
|
||||||
|
let l:topmatters = s:level.frontmatter
|
||||||
|
let l:topmatters += s:level.mainmatter
|
||||||
|
let l:topmatters += s:level.appendix
|
||||||
|
let l:topmatters += s:level.backmatter
|
||||||
|
|
||||||
|
for l:level in get(s:level, 'old', [])
|
||||||
|
let l:topmatters += l:level.frontmatter
|
||||||
|
let l:topmatters += l:level.mainmatter
|
||||||
|
let l:topmatters += l:level.appendix
|
||||||
|
let l:topmatters += l:level.backmatter
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:topmatters
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#parser#toc#get_entry_general(context) abort dict " {{{1
|
||||||
|
return {
|
||||||
|
\ 'title' : self.title,
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'level' : 0,
|
||||||
|
\ 'type' : 'content',
|
||||||
|
\}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
" IMPORTANT: The following defines a prefilter for optimizing the toc parser.
|
||||||
|
" Any line that should be parsed has to be matched by this regexp!
|
||||||
|
" {{{1 let s:re_prefilter = ...
|
||||||
|
let s:re_prefilter = '\v%(\\' . join([
|
||||||
|
\ '%(front|main|back)matter',
|
||||||
|
\ 'add%(global|section)?bib',
|
||||||
|
\ 'appendix',
|
||||||
|
\ 'begin',
|
||||||
|
\ 'bibliography',
|
||||||
|
\ 'chapter',
|
||||||
|
\ 'documentclass',
|
||||||
|
\ 'import',
|
||||||
|
\ 'include',
|
||||||
|
\ 'includegraphics',
|
||||||
|
\ 'input',
|
||||||
|
\ 'label',
|
||||||
|
\ 'part',
|
||||||
|
\ 'printbib',
|
||||||
|
\ 'printindex',
|
||||||
|
\ 'paragraph',
|
||||||
|
\ 'section',
|
||||||
|
\ 'subfile',
|
||||||
|
\ 'tableofcontents',
|
||||||
|
\ 'todo',
|
||||||
|
\], '|') . ')'
|
||||||
|
\ . '|\%\s*%(' . join(g:vimtex_toc_todo_keywords, '|') . ')'
|
||||||
|
\ . '|\%\s*vimtex-include'
|
||||||
|
for s:m in g:vimtex_toc_custom_matchers
|
||||||
|
if has_key(s:m, 'prefilter')
|
||||||
|
let s:re_prefilter .= '|' . s:m.prefilter
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
" Adds entries for included files
|
||||||
|
let s:matcher_include = {
|
||||||
|
\ 're' : vimtex#re#tex_input . '\zs\f{-}\s*\ze\}',
|
||||||
|
\ 'in_preamble' : 1,
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_include.get_entry(context) abort dict " {{{1
|
||||||
|
let l:file = matchstr(a:context.line, self.re)
|
||||||
|
if !vimtex#paths#is_abs(l:file[0])
|
||||||
|
let l:file = b:vimtex.root . '/' . l:file
|
||||||
|
endif
|
||||||
|
let l:file = fnamemodify(l:file, ':~:.')
|
||||||
|
if !filereadable(l:file)
|
||||||
|
let l:file .= '.tex'
|
||||||
|
endif
|
||||||
|
return {
|
||||||
|
\ 'title' : 'tex incl: ' . (strlen(l:file) < 70
|
||||||
|
\ ? l:file
|
||||||
|
\ : l:file[0:30] . '...' . l:file[-36:]),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : l:file,
|
||||||
|
\ 'line' : 1,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'include',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
" Adds entries for included graphics files (filetype tikz, tex)
|
||||||
|
let s:matcher_include_graphics = {
|
||||||
|
\ 're' : '\v^\s*\\includegraphics\*?%(\s*\[[^]]*\]){0,2}\s*\{\zs[^}]*',
|
||||||
|
\ 'priority' : 1,
|
||||||
|
\}
|
||||||
|
function! s:matcher_include_graphics.get_entry(context) abort dict " {{{1
|
||||||
|
let l:file = matchstr(a:context.line, self.re)
|
||||||
|
if !vimtex#paths#is_abs(l:file)
|
||||||
|
let l:file = vimtex#misc#get_graphicspath(l:file)
|
||||||
|
endif
|
||||||
|
let l:file = fnamemodify(l:file, ':~:.')
|
||||||
|
let l:ext = fnamemodify(l:file, ':e')
|
||||||
|
|
||||||
|
return !filereadable(l:file) || index(['asy', 'tikz'], l:ext) < 0
|
||||||
|
\ ? {}
|
||||||
|
\ : {
|
||||||
|
\ 'title' : 'fig incl: ' . (strlen(l:file) < 70
|
||||||
|
\ ? l:file
|
||||||
|
\ : l:file[0:30] . '...' . l:file[-36:]),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : l:file,
|
||||||
|
\ 'line' : 1,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'include',
|
||||||
|
\ 'link' : 1,
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
" Adds entries for included files through vimtex specific syntax (this allows
|
||||||
|
" to add entries for any filetype or file)
|
||||||
|
let s:matcher_include_vimtex = {
|
||||||
|
\ 're' : '^\s*%\s*vimtex-include:\?\s\+\zs\f\+',
|
||||||
|
\ 'in_preamble' : 1,
|
||||||
|
\ 'priority' : 1,
|
||||||
|
\}
|
||||||
|
function! s:matcher_include_vimtex.get_entry(context) abort dict " {{{1
|
||||||
|
let l:file = matchstr(a:context.line, self.re)
|
||||||
|
if !vimtex#paths#is_abs(l:file)
|
||||||
|
let l:file = b:vimtex.root . '/' . l:file
|
||||||
|
endif
|
||||||
|
let l:file = fnamemodify(l:file, ':~:.')
|
||||||
|
return {
|
||||||
|
\ 'title' : 'vtx incl: ' . (strlen(l:file) < 70
|
||||||
|
\ ? l:file
|
||||||
|
\ : l:file[0:30] . '...' . l:file[-36:]),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : l:file,
|
||||||
|
\ 'line' : 1,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'include',
|
||||||
|
\ 'link' : 1,
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_include_bibtex = {
|
||||||
|
\ 're' : '\v^\s*\\bibliography\s*\{\zs[^}]+\ze\}',
|
||||||
|
\ 'in_preamble' : 1,
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_include_bibtex.get_entry(context) abort dict " {{{1
|
||||||
|
let l:entries = []
|
||||||
|
|
||||||
|
for l:file in split(matchstr(a:context.line, self.re), ',')
|
||||||
|
" Ensure that the file name has extension
|
||||||
|
if l:file !~# '\.bib$'
|
||||||
|
let l:file .= '.bib'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:entries, {
|
||||||
|
\ 'title' : printf('bib incl: %-.67s', fnamemodify(l:file, ':t')),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : vimtex#kpsewhich#find(l:file),
|
||||||
|
\ 'line' : 1,
|
||||||
|
\ 'level' : 0,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'include',
|
||||||
|
\ 'link' : 1,
|
||||||
|
\})
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:entries
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_include_biblatex = {
|
||||||
|
\ 're' : '\v^\s*\\add(bibresource|globalbib|sectionbib)\s*\{\zs[^}]+\ze\}',
|
||||||
|
\ 'in_preamble' : 1,
|
||||||
|
\ 'in_content' : 0,
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_include_biblatex.get_entry(context) abort dict " {{{1
|
||||||
|
let l:file = matchstr(a:context.line, self.re)
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'title' : printf('bib incl: %-.67s', fnamemodify(l:file, ':t')),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : vimtex#kpsewhich#find(l:file),
|
||||||
|
\ 'line' : 1,
|
||||||
|
\ 'level' : 0,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'include',
|
||||||
|
\ 'link' : 1,
|
||||||
|
\}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_preamble = {
|
||||||
|
\ 're' : '\v^\s*\\documentclass',
|
||||||
|
\ 'in_preamble' : 1,
|
||||||
|
\ 'in_content' : 0,
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_preamble.get_entry(context) abort " {{{1
|
||||||
|
return g:vimtex_toc_show_preamble
|
||||||
|
\ ? {
|
||||||
|
\ 'title' : 'Preamble',
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'level' : 0,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'content',
|
||||||
|
\ }
|
||||||
|
\ : {}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_parts = {
|
||||||
|
\ 're' : '\v^\s*\\\zs((front|main|back)matter|appendix)>',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_parts.get_entry(context) abort dict " {{{1
|
||||||
|
call a:context.level.reset(
|
||||||
|
\ matchstr(a:context.line, self.re),
|
||||||
|
\ a:context.max_level)
|
||||||
|
return {}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_sections = {
|
||||||
|
\ 're' : '\v^\s*\\%(part|chapter|%(sub)*section|%(sub)?paragraph)\*?\s*(\[|\{)',
|
||||||
|
\ 're_starred' : '\v^\s*\\%(part|chapter|%(sub)*section)\*',
|
||||||
|
\ 're_level' : '\v^\s*\\\zs%(part|chapter|%(sub)*section|%(sub)?paragraph)',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
let s:matcher_sections.re_title = s:matcher_sections.re . '\zs.{-}\ze\%?\s*$'
|
||||||
|
function! s:matcher_sections.get_entry(context) abort dict " {{{1
|
||||||
|
let level = matchstr(a:context.line, self.re_level)
|
||||||
|
let type = matchlist(a:context.line, self.re)[1]
|
||||||
|
let title = matchstr(a:context.line, self.re_title)
|
||||||
|
let number = ''
|
||||||
|
|
||||||
|
let [l:end, l:count] = s:find_closing(0, title, 1, type)
|
||||||
|
if l:count == 0
|
||||||
|
let title = self.parse_title(strpart(title, 0, l:end+1))
|
||||||
|
else
|
||||||
|
let self.type = type
|
||||||
|
let self.count = l:count
|
||||||
|
let s:matcher_continue = deepcopy(self)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:context.line !~# self.re_starred
|
||||||
|
call a:context.level.increment(level)
|
||||||
|
if a:context.line !~# '\v^\s*\\%(sub)?paragraph'
|
||||||
|
let number = deepcopy(a:context.level)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'title' : title,
|
||||||
|
\ 'number' : number,
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'content',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matcher_sections.parse_title(title) abort dict " {{{1
|
||||||
|
let l:title = substitute(a:title, '\v%(\]|\})\s*$', '', '')
|
||||||
|
return s:clear_texorpdfstring(l:title)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matcher_sections.continue(context) abort dict " {{{1
|
||||||
|
let [l:end, l:count] = s:find_closing(0, a:context.line, self.count, self.type)
|
||||||
|
if l:count == 0
|
||||||
|
let a:context.entry.title = self.parse_title(a:context.entry.title . strpart(a:context.line, 0, l:end+1))
|
||||||
|
unlet! s:matcher_continue
|
||||||
|
else
|
||||||
|
let a:context.entry.title .= a:context.line
|
||||||
|
let self.count = l:count
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_table_of_contents = {
|
||||||
|
\ 'title' : 'Table of contents',
|
||||||
|
\ 're' : '\v^\s*\\tableofcontents',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let s:matcher_index = {
|
||||||
|
\ 'title' : 'Alphabetical index',
|
||||||
|
\ 're' : '\v^\s*\\printindex\[?',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let s:matcher_titlepage = {
|
||||||
|
\ 'title' : 'Titlepage',
|
||||||
|
\ 're' : '\v^\s*\\begin\{titlepage\}',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
|
||||||
|
let s:matcher_bibliography = {
|
||||||
|
\ 'title' : 'Bibliography',
|
||||||
|
\ 're' : '\v^\s*\\%('
|
||||||
|
\ . 'printbib%(liography|heading)\s*(\{|\[)?'
|
||||||
|
\ . '|begin\s*\{\s*thebibliography\s*\}'
|
||||||
|
\ . '|bibliography\s*\{)',
|
||||||
|
\ 're_biblatex' : '\v^\s*\\printbib%(liography|heading)',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_bibliography.get_entry(context) abort dict " {{{1
|
||||||
|
let l:entry = call('vimtex#parser#toc#get_entry_general', [a:context], self)
|
||||||
|
|
||||||
|
if a:context.line !~# self.re_biblatex
|
||||||
|
return l:entry
|
||||||
|
endif
|
||||||
|
|
||||||
|
let self.options = matchstr(a:context.line, self.re_biblatex . '\s*\[\zs.*')
|
||||||
|
|
||||||
|
let [l:end, l:count] = s:find_closing(
|
||||||
|
\ 0, self.options, !empty(self.options), '[')
|
||||||
|
if l:count == 0
|
||||||
|
let self.options = strpart(self.options, 0, l:end)
|
||||||
|
call self.parse_options(a:context, l:entry)
|
||||||
|
else
|
||||||
|
let self.count = l:count
|
||||||
|
let s:matcher_continue = deepcopy(self)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:entry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matcher_bibliography.continue(context) abort dict " {{{1
|
||||||
|
let [l:end, l:count] = s:find_closing(0, a:context.line, self.count, '[')
|
||||||
|
if l:count == 0
|
||||||
|
let self.options .= strpart(a:context.line, 0, l:end)
|
||||||
|
unlet! s:matcher_continue
|
||||||
|
call self.parse_options(a:context, a:context.entry)
|
||||||
|
else
|
||||||
|
let self.options .= a:context.line
|
||||||
|
let self.count = l:count
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matcher_bibliography.parse_options(context, entry) abort dict " {{{1
|
||||||
|
" Parse the options
|
||||||
|
let l:opt_pairs = map(split(self.options, ','), 'split(v:val, ''='')')
|
||||||
|
let l:opts = {}
|
||||||
|
for [l:key, l:val] in l:opt_pairs
|
||||||
|
let l:key = substitute(l:key, '^\s*\|\s*$', '', 'g')
|
||||||
|
let l:val = substitute(l:val, '^\s*\|\s*$', '', 'g')
|
||||||
|
let l:val = substitute(l:val, '{\|}', '', 'g')
|
||||||
|
let l:opts[l:key] = l:val
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Check if entry should appear in the TOC
|
||||||
|
let l:heading = get(l:opts, 'heading')
|
||||||
|
let a:entry.added_to_toc = l:heading =~# 'intoc\|numbered'
|
||||||
|
|
||||||
|
" Check if entry should be numbered
|
||||||
|
if l:heading =~# '\v%(sub)?bibnumbered'
|
||||||
|
if a:context.level.chapter > 0
|
||||||
|
let l:levels = ['chapter', 'section']
|
||||||
|
else
|
||||||
|
let l:levels = ['section', 'subsection']
|
||||||
|
endif
|
||||||
|
call a:context.level.increment(l:levels[l:heading =~# '^sub'])
|
||||||
|
let a:entry.level = a:context.max_level - a:context.level.current
|
||||||
|
let a:entry.number = deepcopy(a:context.level)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Parse title
|
||||||
|
try
|
||||||
|
let a:entry.title = remove(l:opts, 'title')
|
||||||
|
catch /E716/
|
||||||
|
let a:entry.title = l:heading =~# '^sub' ? 'References' : 'Bibliography'
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matcher_bibliography.filter(entries) abort dict " {{{1
|
||||||
|
if !empty(
|
||||||
|
\ filter(deepcopy(a:entries), 'get(v:val, "added_to_toc")'))
|
||||||
|
call filter(a:entries, 'get(v:val, "added_to_toc", 1)')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_todos = {
|
||||||
|
\ 're' : g:vimtex#re#not_bslash . '\%\s+('
|
||||||
|
\ . join(g:vimtex_toc_todo_keywords, '|') . ')[ :]+\s*(.*)',
|
||||||
|
\ 'in_preamble' : 1,
|
||||||
|
\ 'priority' : 2,
|
||||||
|
\}
|
||||||
|
function! s:matcher_todos.get_entry(context) abort dict " {{{1
|
||||||
|
let [l:type, l:text] = matchlist(a:context.line, self.re)[1:2]
|
||||||
|
return {
|
||||||
|
\ 'title' : toupper(l:type) . ': ' . l:text,
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'todo',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_todonotes = {
|
||||||
|
\ 're' : g:vimtex#re#not_comment . '\\\w*todo\w*%(\[[^]]*\])?\{\zs.*',
|
||||||
|
\ 'priority' : 2,
|
||||||
|
\}
|
||||||
|
function! s:matcher_todonotes.get_entry(context) abort dict " {{{1
|
||||||
|
let title = matchstr(a:context.line, self.re)
|
||||||
|
|
||||||
|
let [l:end, l:count] = s:find_closing(0, title, 1, '{')
|
||||||
|
if l:count == 0
|
||||||
|
let title = strpart(title, 0, l:end)
|
||||||
|
else
|
||||||
|
let self.count = l:count
|
||||||
|
let s:matcher_continue = deepcopy(self)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'title' : 'TODO: ' . title,
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'todo',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:matcher_todonotes.continue(context) abort dict " {{{1
|
||||||
|
let [l:end, l:count] = s:find_closing(0, a:context.line, self.count, '{')
|
||||||
|
if l:count == 0
|
||||||
|
let a:context.entry.title .= strpart(a:context.line, 0, l:end)
|
||||||
|
unlet! s:matcher_continue
|
||||||
|
else
|
||||||
|
let a:context.entry.title .= a:context.line
|
||||||
|
let self.count = l:count
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_labels = {
|
||||||
|
\ 're' : g:vimtex#re#not_comment . '\\label\{\zs.{-}\ze\}',
|
||||||
|
\ 'priority' : 1,
|
||||||
|
\}
|
||||||
|
function! s:matcher_labels.get_entry(context) abort dict " {{{1
|
||||||
|
return {
|
||||||
|
\ 'title' : matchstr(a:context.line, self.re),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'label',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:matcher_beamer_frame = {
|
||||||
|
\ 're' : '^\s*\\begin{frame}',
|
||||||
|
\ 'priority' : 0,
|
||||||
|
\}
|
||||||
|
function! s:matcher_beamer_frame.get_entry(context) abort dict " {{{1
|
||||||
|
let l:title = vimtex#util#trim(
|
||||||
|
\ matchstr(a:context.line, self.re . '\s*{\zs.*\ze}\s*$'))
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'title' : 'Frame' . (empty(l:title) ? '' : ': ' . l:title),
|
||||||
|
\ 'number' : '',
|
||||||
|
\ 'file' : a:context.file,
|
||||||
|
\ 'line' : a:context.lnum,
|
||||||
|
\ 'level' : a:context.max_level - a:context.level.current,
|
||||||
|
\ 'rank' : a:context.lnum_total,
|
||||||
|
\ 'type' : 'content',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Utility functions
|
||||||
|
"
|
||||||
|
function! s:clear_texorpdfstring(title) abort " {{{1
|
||||||
|
let l:i1 = match(a:title, '\\texorpdfstring')
|
||||||
|
if l:i1 < 0 | return a:title | endif
|
||||||
|
|
||||||
|
" Find start of included part
|
||||||
|
let [l:i2, l:dummy] = s:find_closing(
|
||||||
|
\ match(a:title, '{', l:i1+1), a:title, 1, '{')
|
||||||
|
let l:i2 = match(a:title, '{', l:i2+1)
|
||||||
|
if l:i2 < 0 | return a:title | endif
|
||||||
|
|
||||||
|
" Find end of included part
|
||||||
|
let [l:i3, l:dummy] = s:find_closing(l:i2, a:title, 1, '{')
|
||||||
|
if l:i3 < 0 | return a:title | endif
|
||||||
|
|
||||||
|
return strpart(a:title, 0, l:i1)
|
||||||
|
\ . strpart(a:title, l:i2+1, l:i3-l:i2-1)
|
||||||
|
\ . s:clear_texorpdfstring(strpart(a:title, l:i3+1))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:find_closing(start, string, count, type) abort " {{{1
|
||||||
|
if a:type ==# '{'
|
||||||
|
let l:re = '{\|}'
|
||||||
|
let l:open = '{'
|
||||||
|
else
|
||||||
|
let l:re = '\[\|\]'
|
||||||
|
let l:open = '['
|
||||||
|
endif
|
||||||
|
let l:i2 = a:start-1
|
||||||
|
let l:count = a:count
|
||||||
|
while l:count > 0
|
||||||
|
let l:i2 = match(a:string, l:re, l:i2+1)
|
||||||
|
if l:i2 < 0 | break | endif
|
||||||
|
|
||||||
|
if a:string[l:i2] ==# l:open
|
||||||
|
let l:count += 1
|
||||||
|
else
|
||||||
|
let l:count -= 1
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return [l:i2, l:count]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:sort_by_priority(d1, d2) abort " {{{1
|
||||||
|
let l:p1 = get(a:d1, 'priority')
|
||||||
|
let l:p2 = get(a:d2, 'priority')
|
||||||
|
return l:p1 >= l:p2 ? l:p1 > l:p2 : -1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Section level counter
|
||||||
|
"
|
||||||
|
let s:level = {}
|
||||||
|
function! s:level.reset(part, level) abort dict " {{{1
|
||||||
|
if a:part ==# 'preamble'
|
||||||
|
let self.old = []
|
||||||
|
else
|
||||||
|
let self.old += [copy(self)]
|
||||||
|
endif
|
||||||
|
|
||||||
|
let self.preamble = 0
|
||||||
|
let self.frontmatter = 0
|
||||||
|
let self.mainmatter = 0
|
||||||
|
let self.appendix = 0
|
||||||
|
let self.backmatter = 0
|
||||||
|
let self.part = 0
|
||||||
|
let self.chapter = 0
|
||||||
|
let self.section = 0
|
||||||
|
let self.subsection = 0
|
||||||
|
let self.subsubsection = 0
|
||||||
|
let self.subsubsubsection = 0
|
||||||
|
let self.paragraph = 0
|
||||||
|
let self.subparagraph = 0
|
||||||
|
let self.current = a:level
|
||||||
|
let self[a:part] = 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:level.increment(level) abort dict " {{{1
|
||||||
|
let self.current = s:sec_to_value[a:level]
|
||||||
|
|
||||||
|
let self.part_toggle = 0
|
||||||
|
|
||||||
|
if a:level ==# 'part'
|
||||||
|
let self.part += 1
|
||||||
|
let self.part_toggle = 1
|
||||||
|
elseif a:level ==# 'chapter'
|
||||||
|
let self.chapter += 1
|
||||||
|
let self.section = 0
|
||||||
|
let self.subsection = 0
|
||||||
|
let self.subsubsection = 0
|
||||||
|
let self.subsubsubsection = 0
|
||||||
|
let self.paragraph = 0
|
||||||
|
let self.subparagraph = 0
|
||||||
|
elseif a:level ==# 'section'
|
||||||
|
let self.section += 1
|
||||||
|
let self.subsection = 0
|
||||||
|
let self.subsubsection = 0
|
||||||
|
let self.subsubsubsection = 0
|
||||||
|
let self.paragraph = 0
|
||||||
|
let self.subparagraph = 0
|
||||||
|
elseif a:level ==# 'subsection'
|
||||||
|
let self.subsection += 1
|
||||||
|
let self.subsubsection = 0
|
||||||
|
let self.subsubsubsection = 0
|
||||||
|
let self.paragraph = 0
|
||||||
|
let self.subparagraph = 0
|
||||||
|
elseif a:level ==# 'subsubsection'
|
||||||
|
let self.subsubsection += 1
|
||||||
|
let self.subsubsubsection = 0
|
||||||
|
let self.paragraph = 0
|
||||||
|
let self.subparagraph = 0
|
||||||
|
elseif a:level ==# 'subsubsubsection'
|
||||||
|
let self.subsubsubsection += 1
|
||||||
|
let self.paragraph = 0
|
||||||
|
let self.subparagraph = 0
|
||||||
|
elseif a:level ==# 'paragraph'
|
||||||
|
let self.paragraph += 1
|
||||||
|
let self.subparagraph = 0
|
||||||
|
elseif a:level ==# 'subparagraph'
|
||||||
|
let self.subparagraph += 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:sec_to_value = {
|
||||||
|
\ '_' : 0,
|
||||||
|
\ 'subparagraph' : 1,
|
||||||
|
\ 'paragraph' : 2,
|
||||||
|
\ 'subsubsubsection' : 3,
|
||||||
|
\ 'subsubsection' : 4,
|
||||||
|
\ 'subsection' : 5,
|
||||||
|
\ 'section' : 6,
|
||||||
|
\ 'chapter' : 7,
|
||||||
|
\ 'part' : 8,
|
||||||
|
\ }
|
||||||
|
|
||||||
|
"
|
||||||
|
" Create the lists of matchers
|
||||||
|
"
|
||||||
|
let s:matchers = map(
|
||||||
|
\ filter(items(s:), 'v:val[0] =~# ''^matcher_'''),
|
||||||
|
\ 'v:val[1]')
|
||||||
|
\ + g:vimtex_toc_custom_matchers
|
||||||
|
call sort(s:matchers, function('s:sort_by_priority'))
|
||||||
|
|
||||||
|
for s:m in s:matchers
|
||||||
|
if !has_key(s:m, 'get_entry')
|
||||||
|
let s:m.get_entry = function('vimtex#parser#toc#get_entry_general')
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
unlet! s:m
|
||||||
|
|
||||||
|
let s:matchers_preamble = filter(
|
||||||
|
\ deepcopy(s:matchers), "get(v:val, 'in_preamble')")
|
||||||
|
let s:matchers_content = filter(
|
||||||
|
\ deepcopy(s:matchers), "get(v:val, 'in_content', 1)")
|
||||||
|
|
||||||
|
endif
|
||||||
91
autoload/vimtex/paths.vim
Normal file
91
autoload/vimtex/paths.vim
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#paths#pushd(path) abort " {{{1
|
||||||
|
if empty(a:path) || getcwd() ==# fnamemodify(a:path, ':p')
|
||||||
|
let s:qpath += ['']
|
||||||
|
else
|
||||||
|
let s:qpath += [getcwd()]
|
||||||
|
execute s:cd fnameescape(a:path)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#paths#popd() abort " {{{1
|
||||||
|
let l:path = remove(s:qpath, -1)
|
||||||
|
if !empty(l:path)
|
||||||
|
execute s:cd fnameescape(l:path)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#paths#is_abs(path) abort " {{{1
|
||||||
|
return a:path =~# s:re_abs
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#paths#shorten_relative(path) abort " {{{1
|
||||||
|
" Input: An absolute path
|
||||||
|
" Output: Relative path with respect to the vimtex root, path relative to
|
||||||
|
" vimtex root (unless absolute path is shorter)
|
||||||
|
|
||||||
|
let l:relative = vimtex#paths#relative(a:path, b:vimtex.root)
|
||||||
|
return strlen(l:relative) < strlen(a:path)
|
||||||
|
\ ? l:relative : a:path
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#paths#relative(path, current) abort " {{{1
|
||||||
|
" Note: This algorithm is based on the one presented by @Offirmo at SO,
|
||||||
|
" http://stackoverflow.com/a/12498485/51634
|
||||||
|
|
||||||
|
let l:target = simplify(substitute(a:path, '\\', '/', 'g'))
|
||||||
|
let l:common = simplify(substitute(a:current, '\\', '/', 'g'))
|
||||||
|
|
||||||
|
" This only works on absolute paths
|
||||||
|
if !vimtex#paths#is_abs(l:target)
|
||||||
|
return substitute(a:path, '^\.\/', '', '')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:tries = 50
|
||||||
|
let l:result = ''
|
||||||
|
while stridx(l:target, l:common) != 0 && l:tries > 0
|
||||||
|
let l:common = fnamemodify(l:common, ':h')
|
||||||
|
let l:result = empty(l:result) ? '..' : '../' . l:result
|
||||||
|
let l:tries -= 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
if l:tries == 0 | return a:path | endif
|
||||||
|
|
||||||
|
if l:common ==# '/'
|
||||||
|
let l:result .= '/'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:forward = strpart(l:target, strlen(l:common))
|
||||||
|
if !empty(l:forward)
|
||||||
|
let l:result = empty(l:result)
|
||||||
|
\ ? l:forward[1:]
|
||||||
|
\ : l:result . l:forward
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:result
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:cd = exists('*haslocaldir') && haslocaldir()
|
||||||
|
\ ? 'lcd'
|
||||||
|
\ : exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd'
|
||||||
|
let s:qpath = get(s:, 'qpath', [])
|
||||||
|
|
||||||
|
let s:re_abs = has('win32') ? '^[A-Z]:[\\/]' : '^/'
|
||||||
|
|
||||||
|
endif
|
||||||
97
autoload/vimtex/pos.vim
Normal file
97
autoload/vimtex/pos.vim
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#pos#set_cursor(...) abort " {{{1
|
||||||
|
call cursor(s:parse_args(a:000))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#get_cursor() abort " {{{1
|
||||||
|
return exists('*getcurpos') ? getcurpos() : getpos('.')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#get_cursor_line() abort " {{{1
|
||||||
|
let l:pos = vimtex#pos#get_cursor()
|
||||||
|
return l:pos[1]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#pos#val(...) abort " {{{1
|
||||||
|
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000)
|
||||||
|
|
||||||
|
return 100000*l:lnum + min([l:cnum, 90000])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#next(...) abort " {{{1
|
||||||
|
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000)
|
||||||
|
|
||||||
|
return l:cnum < strlen(getline(l:lnum))
|
||||||
|
\ ? [0, l:lnum, l:cnum+1, 0]
|
||||||
|
\ : [0, l:lnum+1, 1, 0]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#prev(...) abort " {{{1
|
||||||
|
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000)
|
||||||
|
|
||||||
|
return l:cnum > 1
|
||||||
|
\ ? [0, l:lnum, l:cnum-1, 0]
|
||||||
|
\ : [0, max([l:lnum-1, 1]), strlen(getline(l:lnum-1)), 0]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#larger(pos1, pos2) abort " {{{1
|
||||||
|
return vimtex#pos#val(a:pos1) > vimtex#pos#val(a:pos2)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#equal(p1, p2) abort " {{{1
|
||||||
|
let l:pos1 = s:parse_args(a:p1)
|
||||||
|
let l:pos2 = s:parse_args(a:p2)
|
||||||
|
return l:pos1[:1] == l:pos2[:1]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#pos#smaller(pos1, pos2) abort " {{{1
|
||||||
|
return vimtex#pos#val(a:pos1) < vimtex#pos#val(a:pos2)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:parse_args(args) abort " {{{1
|
||||||
|
"
|
||||||
|
" The arguments should be in one of the following forms (when unpacked):
|
||||||
|
"
|
||||||
|
" [lnum, cnum]
|
||||||
|
" [bufnum, lnum, cnum, ...]
|
||||||
|
" {'lnum' : lnum, 'cnum' : cnum}
|
||||||
|
"
|
||||||
|
|
||||||
|
if len(a:args) > 1
|
||||||
|
return s:parse_args([a:args])
|
||||||
|
elseif len(a:args) == 1
|
||||||
|
if type(a:args[0]) == type({})
|
||||||
|
return [get(a:args[0], 'lnum'), get(a:args[0], 'cnum')]
|
||||||
|
else
|
||||||
|
if len(a:args[0]) == 2
|
||||||
|
return a:args[0]
|
||||||
|
else
|
||||||
|
return a:args[0][1:]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
return a:args
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
233
autoload/vimtex/process.vim
Normal file
233
autoload/vimtex/process.vim
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#process#new(...) abort " {{{1
|
||||||
|
let l:opts = a:0 > 0 ? a:1 : {}
|
||||||
|
return extend(deepcopy(s:process), l:opts)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#process#run(cmd, ...) abort " {{{1
|
||||||
|
let l:opts = a:0 > 0 ? a:1 : {}
|
||||||
|
let l:opts.cmd = a:cmd
|
||||||
|
let l:process = vimtex#process#new(l:opts)
|
||||||
|
|
||||||
|
return l:process.run()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#process#capture(cmd) abort " {{{1
|
||||||
|
return vimtex#process#run(a:cmd, {'capture': 1})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#process#start(cmd, ...) abort " {{{1
|
||||||
|
let l:opts = a:0 > 0 ? a:1 : {}
|
||||||
|
let l:opts.continuous = 1
|
||||||
|
return vimtex#process#run(a:cmd, l:opts)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:process = {
|
||||||
|
\ 'cmd' : '',
|
||||||
|
\ 'pid' : 0,
|
||||||
|
\ 'background' : 1,
|
||||||
|
\ 'continuous' : 0,
|
||||||
|
\ 'output' : '',
|
||||||
|
\ 'workdir' : '',
|
||||||
|
\ 'silent' : 1,
|
||||||
|
\ 'capture' : 0,
|
||||||
|
\ 'result' : '',
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:process.run() abort dict " {{{1
|
||||||
|
if self._do_not_run() | return | endif
|
||||||
|
|
||||||
|
call self._pre_run()
|
||||||
|
call self._prepare()
|
||||||
|
call self._execute()
|
||||||
|
call self._restore()
|
||||||
|
call self._post_run()
|
||||||
|
|
||||||
|
return self.capture ? self.result : self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process.stop() abort dict " {{{1
|
||||||
|
if !self.pid | return | endif
|
||||||
|
|
||||||
|
let l:cmd = has('win32')
|
||||||
|
\ ? 'taskkill /PID ' . self.pid . ' /T /F'
|
||||||
|
\ : 'kill ' . self.pid
|
||||||
|
call vimtex#process#run(l:cmd, {'background': 0})
|
||||||
|
|
||||||
|
let self.pid = 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process.pprint_items() abort dict " {{{1
|
||||||
|
let l:list = [
|
||||||
|
\ ['pid', self.pid ? self.pid : '-'],
|
||||||
|
\ ['cmd', get(self, 'prepared_cmd', self.cmd)],
|
||||||
|
\]
|
||||||
|
|
||||||
|
return l:list
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:process._do_not_run() abort dict " {{{1
|
||||||
|
if empty(self.cmd)
|
||||||
|
call vimtex#log#warning('Can''t run empty command')
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
if self.pid
|
||||||
|
call vimtex#log#warning('Process already running!')
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process._pre_run() abort dict " {{{1
|
||||||
|
if self.capture
|
||||||
|
let self.silent = 0
|
||||||
|
let self.background = 0
|
||||||
|
elseif empty(self.output) && self.background
|
||||||
|
let self.output = 'null'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#paths#pushd(self.workdir)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process._execute() abort dict " {{{1
|
||||||
|
if self.capture
|
||||||
|
let self.result = split(system(self.prepared_cmd), '\n')
|
||||||
|
elseif self.silent
|
||||||
|
silent call system(self.prepared_cmd)
|
||||||
|
elseif self.background
|
||||||
|
silent execute '!' . self.prepared_cmd
|
||||||
|
if !has('gui_running')
|
||||||
|
redraw!
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
execute '!' . self.prepared_cmd
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Capture the pid if relevant
|
||||||
|
if has_key(self, 'set_pid') && self.continuous
|
||||||
|
call self.set_pid()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process._post_run() abort dict " {{{1
|
||||||
|
call vimtex#paths#popd()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
if has('win32')
|
||||||
|
function! s:process._prepare() abort dict " {{{1
|
||||||
|
if &shell !~? 'cmd'
|
||||||
|
let self.win32_restore_shell = 1
|
||||||
|
let self.win32_saved_shell = [
|
||||||
|
\ &shell,
|
||||||
|
\ &shellcmdflag,
|
||||||
|
\ &shellxquote,
|
||||||
|
\ &shellxescape,
|
||||||
|
\ &shellquote,
|
||||||
|
\ &shellpipe,
|
||||||
|
\ &shellredir,
|
||||||
|
\ &shellslash
|
||||||
|
\]
|
||||||
|
set shell& shellcmdflag& shellxquote& shellxescape&
|
||||||
|
set shellquote& shellpipe& shellredir& shellslash&
|
||||||
|
else
|
||||||
|
let self.win32_restore_shell = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:cmd = self.cmd
|
||||||
|
|
||||||
|
if self.background
|
||||||
|
if !empty(self.output)
|
||||||
|
let l:cmd .= self.output ==# 'null'
|
||||||
|
\ ? ' >nul'
|
||||||
|
\ : ' >' . self.output
|
||||||
|
let l:cmd = 'cmd /s /c "' . l:cmd . '"'
|
||||||
|
else
|
||||||
|
let l:cmd = 'cmd /c "' . l:cmd . '"'
|
||||||
|
endif
|
||||||
|
let l:cmd = 'start /b ' . cmd
|
||||||
|
endif
|
||||||
|
|
||||||
|
if self.silent && self.output ==# 'null'
|
||||||
|
let self.prepared_cmd = '"' . l:cmd . '"'
|
||||||
|
else
|
||||||
|
let self.prepared_cmd = l:cmd
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process._restore() abort dict " {{{1
|
||||||
|
if self.win32_restore_shell
|
||||||
|
let [ &shell,
|
||||||
|
\ &shellcmdflag,
|
||||||
|
\ &shellxquote,
|
||||||
|
\ &shellxescape,
|
||||||
|
\ &shellquote,
|
||||||
|
\ &shellpipe,
|
||||||
|
\ &shellredir,
|
||||||
|
\ &shellslash] = self.win32_saved_shell
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process.get_pid() abort dict " {{{1
|
||||||
|
let self.pid = 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
else
|
||||||
|
function! s:process._prepare() abort dict " {{{1
|
||||||
|
let l:cmd = self.cmd
|
||||||
|
|
||||||
|
if self.background
|
||||||
|
if !empty(self.output)
|
||||||
|
let l:cmd .= ' >'
|
||||||
|
\ . (self.output ==# 'null'
|
||||||
|
\ ? '/dev/null'
|
||||||
|
\ : shellescape(self.output))
|
||||||
|
\ . ' 2>&1'
|
||||||
|
endif
|
||||||
|
let l:cmd .= ' &'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !self.silent
|
||||||
|
let l:cmd = escape(l:cmd, '%#')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let self.prepared_cmd = l:cmd
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process._restore() abort dict " {{{1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:process.get_pid() abort dict " {{{1
|
||||||
|
let self.pid = 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
125
autoload/vimtex/profile.vim
Normal file
125
autoload/vimtex/profile.vim
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#profile#start() abort " {{{1
|
||||||
|
profile start prof.log
|
||||||
|
profile func *
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#profile#stop() abort " {{{1
|
||||||
|
profile stop
|
||||||
|
call s:fix_sids()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
"
|
||||||
|
function! vimtex#profile#open() abort " {{{1
|
||||||
|
source ~/.vim/vimrc
|
||||||
|
silent edit prof.log
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#profile#print() abort " {{{1
|
||||||
|
for l:line in readfile('prof.log')
|
||||||
|
echo l:line
|
||||||
|
endfor
|
||||||
|
echo ''
|
||||||
|
quit!
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#profile#file(filename) abort " {{{1
|
||||||
|
call vimtex#profile#start()
|
||||||
|
|
||||||
|
execute 'silent edit' a:filename
|
||||||
|
|
||||||
|
call vimtex#profile#stop()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#profile#command(cmd) abort " {{{1
|
||||||
|
call vimtex#profile#start()
|
||||||
|
|
||||||
|
execute a:cmd
|
||||||
|
|
||||||
|
call vimtex#profile#stop()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#profile#filter(sections) abort " {{{1
|
||||||
|
let l:lines = readfile('prof.log')
|
||||||
|
" call filter(l:lines, 'v:val !~# ''FTtex''')
|
||||||
|
" call filter(l:lines, 'v:val !~# ''LoadFTPlugin''')
|
||||||
|
|
||||||
|
let l:new = []
|
||||||
|
for l:sec in a:sections
|
||||||
|
call extend(l:new, s:get_section(l:sec, l:lines))
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call writefile(l:new, 'prof.log')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:fix_sids() abort " {{{1
|
||||||
|
let l:lines = readfile('prof.log')
|
||||||
|
let l:new = []
|
||||||
|
for l:line in l:lines
|
||||||
|
let l:sid = matchstr(l:line, '\v\<SNR\>\zs\d+\ze_')
|
||||||
|
if !empty(l:sid)
|
||||||
|
let l:filename = map(
|
||||||
|
\ vimtex#util#command('scriptnames'),
|
||||||
|
\ 'split(v:val, "\\v:=\\s+")[1]')[l:sid-1]
|
||||||
|
if l:filename =~# 'vimtex'
|
||||||
|
let l:filename = substitute(l:filename, '^.*autoload\/', '', '')
|
||||||
|
let l:filename = substitute(l:filename, '\.vim$', '#s:', '')
|
||||||
|
let l:filename = substitute(l:filename, '\/', '#', 'g')
|
||||||
|
else
|
||||||
|
let l:filename .= ':'
|
||||||
|
endif
|
||||||
|
call add(l:new, substitute(l:line, '\v\<SNR\>\d+_', l:filename, 'g'))
|
||||||
|
else
|
||||||
|
call add(l:new, substitute(l:line, '\s\+$', '', ''))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
call writefile(l:new, 'prof.log')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_section(name, lines) abort " {{{1
|
||||||
|
let l:active = 0
|
||||||
|
let l:section = []
|
||||||
|
for l:line in a:lines
|
||||||
|
if l:active
|
||||||
|
if l:line =~# '^FUNCTION' && l:line !~# a:name
|
||||||
|
let l:active = 0
|
||||||
|
else
|
||||||
|
call add(l:section, l:line)
|
||||||
|
endif
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:line =~# a:name
|
||||||
|
call add(l:section, l:line)
|
||||||
|
let l:active = 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if l:active
|
||||||
|
call add(l:section, ' ')
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:section
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
245
autoload/vimtex/qf.vim
Normal file
245
autoload/vimtex/qf.vim
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#qf#init_buffer() abort " {{{1
|
||||||
|
if !g:vimtex_quickfix_enabled | return | endif
|
||||||
|
|
||||||
|
command! -buffer VimtexErrors call vimtex#qf#toggle()
|
||||||
|
|
||||||
|
nnoremap <buffer> <plug>(vimtex-errors) :call vimtex#qf#toggle()<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#qf#init_state(state) abort " {{{1
|
||||||
|
if !g:vimtex_quickfix_enabled | return | endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:qf = vimtex#qf#{g:vimtex_quickfix_method}#new()
|
||||||
|
call l:qf.init(a:state)
|
||||||
|
unlet l:qf.init
|
||||||
|
let a:state.qf = l:qf
|
||||||
|
catch /vimtex: Requirements not met/
|
||||||
|
call vimtex#log#warning(
|
||||||
|
\ 'Quickfix state not initialized!',
|
||||||
|
\ 'Please see :help g:vimtex_quickfix_method')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#qf#toggle() abort " {{{1
|
||||||
|
if vimtex#qf#is_open()
|
||||||
|
cclose
|
||||||
|
else
|
||||||
|
call vimtex#qf#open(1)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#qf#open(force) abort " {{{1
|
||||||
|
if !exists('b:vimtex.qf.addqflist') | return | endif
|
||||||
|
|
||||||
|
try
|
||||||
|
call vimtex#qf#setqflist()
|
||||||
|
catch /Vimtex: No log file found/
|
||||||
|
if a:force
|
||||||
|
call vimtex#log#warning('No log file found')
|
||||||
|
endif
|
||||||
|
if g:vimtex_quickfix_mode > 0
|
||||||
|
cclose
|
||||||
|
endif
|
||||||
|
return
|
||||||
|
catch
|
||||||
|
call vimtex#log#error('Something went wrong when parsing log files!')
|
||||||
|
if g:vimtex_quickfix_mode > 0
|
||||||
|
cclose
|
||||||
|
endif
|
||||||
|
return
|
||||||
|
endtry
|
||||||
|
|
||||||
|
if empty(getqflist())
|
||||||
|
if a:force
|
||||||
|
call vimtex#log#info('No errors!')
|
||||||
|
endif
|
||||||
|
if g:vimtex_quickfix_mode > 0
|
||||||
|
cclose
|
||||||
|
endif
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" There are two options that determine when to open the quickfix window. If
|
||||||
|
" forced, the quickfix window is always opened when there are errors or
|
||||||
|
" warnings (forced typically imply that the functions is called from the
|
||||||
|
" normal mode mapping). Else the behaviour is based on the settings.
|
||||||
|
"
|
||||||
|
let l:errors_or_warnings = s:qf_has_errors()
|
||||||
|
\ || g:vimtex_quickfix_open_on_warning
|
||||||
|
|
||||||
|
if a:force || (g:vimtex_quickfix_mode > 0 && l:errors_or_warnings)
|
||||||
|
call s:window_save()
|
||||||
|
botright cwindow
|
||||||
|
if g:vimtex_quickfix_mode == 2
|
||||||
|
call s:window_restore()
|
||||||
|
endif
|
||||||
|
if g:vimtex_quickfix_autoclose_after_keystrokes > 0
|
||||||
|
augroup vimtex_qf_autoclose
|
||||||
|
autocmd!
|
||||||
|
autocmd CursorMoved,CursorMovedI * call s:qf_autoclose_check()
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
redraw
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#qf#setqflist(...) abort " {{{1
|
||||||
|
if !exists('b:vimtex.qf.addqflist') | return | endif
|
||||||
|
|
||||||
|
if a:0 > 0
|
||||||
|
let l:tex = a:1
|
||||||
|
let l:log = fnamemodify(l:tex, ':r') . '.log'
|
||||||
|
let l:blg = fnamemodify(l:tex, ':r') . '.blg'
|
||||||
|
let l:jump = 0
|
||||||
|
else
|
||||||
|
let l:tex = b:vimtex.tex
|
||||||
|
let l:log = b:vimtex.log()
|
||||||
|
let l:blg = b:vimtex.ext('blg')
|
||||||
|
let l:jump = g:vimtex_quickfix_autojump
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
" Initialize the quickfix list
|
||||||
|
" Note: Only create new list if the current list is not a vimtex qf list
|
||||||
|
if get(getqflist({'title': 1}), 'title') =~# 'Vimtex'
|
||||||
|
call setqflist([], 'r')
|
||||||
|
else
|
||||||
|
call setqflist([])
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Parse LaTeX errors
|
||||||
|
call b:vimtex.qf.addqflist(l:tex, l:log)
|
||||||
|
|
||||||
|
" Parse bibliography errors
|
||||||
|
if has_key(b:vimtex.packages, 'biblatex')
|
||||||
|
call vimtex#qf#biblatex#addqflist(l:blg)
|
||||||
|
else
|
||||||
|
call vimtex#qf#bibtex#addqflist(l:blg)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Ignore entries if desired
|
||||||
|
if !empty(g:vimtex_quickfix_ignore_filters)
|
||||||
|
let l:qflist = getqflist()
|
||||||
|
for l:re in g:vimtex_quickfix_ignore_filters
|
||||||
|
call filter(l:qflist, 'v:val.text !~# l:re')
|
||||||
|
endfor
|
||||||
|
call setqflist(l:qflist, 'r')
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Set title if supported
|
||||||
|
try
|
||||||
|
call setqflist([], 'r', {'title': 'Vimtex errors (' . b:vimtex.qf.name . ')'})
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
|
||||||
|
" Jump to first error if wanted
|
||||||
|
if l:jump
|
||||||
|
cfirst
|
||||||
|
endif
|
||||||
|
catch /Vimtex: No log file found/
|
||||||
|
throw 'Vimtex: No log file found'
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#qf#inquire(file) abort " {{{1
|
||||||
|
try
|
||||||
|
call vimtex#qf#setqflist(a:file)
|
||||||
|
return s:qf_has_errors()
|
||||||
|
catch
|
||||||
|
return 0
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#qf#is_open() abort " {{{1
|
||||||
|
redir => l:bufstring
|
||||||
|
silent! ls!
|
||||||
|
redir END
|
||||||
|
|
||||||
|
let l:buflist = filter(split(l:bufstring, '\n'), 'v:val =~# ''Quickfix''')
|
||||||
|
|
||||||
|
for l:line in l:buflist
|
||||||
|
let l:bufnr = str2nr(matchstr(l:line, '^\s*\zs\d\+'))
|
||||||
|
if bufwinnr(l:bufnr) >= 0
|
||||||
|
\ && getbufvar(l:bufnr, '&buftype', '') ==# 'quickfix'
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:window_save() abort " {{{1
|
||||||
|
if exists('*win_gotoid')
|
||||||
|
let s:previous_window = win_getid()
|
||||||
|
else
|
||||||
|
let w:vimtex_remember_window = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:window_restore() abort " {{{1
|
||||||
|
if exists('*win_gotoid')
|
||||||
|
call win_gotoid(s:previous_window)
|
||||||
|
else
|
||||||
|
for l:winnr in range(1, winnr('$'))
|
||||||
|
if getwinvar(l:winnr, 'vimtex_remember_window')
|
||||||
|
execute l:winnr . 'wincmd p'
|
||||||
|
unlet! w:vimtex_remember_window
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:qf_has_errors() abort " {{{1
|
||||||
|
return len(filter(getqflist(), 'v:val.type ==# ''E''')) > 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
"
|
||||||
|
function! s:qf_autoclose_check() abort " {{{1
|
||||||
|
if get(s:, 'keystroke_counter') == 0
|
||||||
|
let s:keystroke_counter = g:vimtex_quickfix_autoclose_after_keystrokes
|
||||||
|
endif
|
||||||
|
|
||||||
|
redir => l:bufstring
|
||||||
|
silent! ls!
|
||||||
|
redir END
|
||||||
|
|
||||||
|
if empty(filter(split(l:bufstring, '\n'), 'v:val =~# ''%a- .*Quickfix'''))
|
||||||
|
let s:keystroke_counter -= 1
|
||||||
|
else
|
||||||
|
let s:keystroke_counter = g:vimtex_quickfix_autoclose_after_keystrokes + 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if s:keystroke_counter == 0
|
||||||
|
cclose
|
||||||
|
autocmd! vimtex_qf_autoclose
|
||||||
|
augroup! vimtex_qf_autoclose
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
250
autoload/vimtex/qf/biblatex.vim
Normal file
250
autoload/vimtex/qf/biblatex.vim
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#qf#biblatex#addqflist(blg) abort " {{{1
|
||||||
|
if get(g:vimtex_quickfix_blgparser, 'disable') | return | endif
|
||||||
|
|
||||||
|
try
|
||||||
|
call s:biblatex.addqflist(a:blg)
|
||||||
|
catch /biblatex Aborted/
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:biblatex = {
|
||||||
|
\ 'file' : '',
|
||||||
|
\ 'types' : [],
|
||||||
|
\ 'db_files' : [],
|
||||||
|
\}
|
||||||
|
function! s:biblatex.addqflist(blg) abort " {{{1
|
||||||
|
let self.file = a:blg
|
||||||
|
let self.root = fnamemodify(a:blg, ':h')
|
||||||
|
if empty(self.file) | throw 'biblatex Aborted' | endif
|
||||||
|
|
||||||
|
let self.types = map(
|
||||||
|
\ filter(items(s:), 'v:val[0] =~# ''^type_'''),
|
||||||
|
\ 'v:val[1]')
|
||||||
|
let self.db_files = []
|
||||||
|
|
||||||
|
let self.errorformat_saved = &l:errorformat
|
||||||
|
setlocal errorformat=%+E%.%#\>\ ERROR%m
|
||||||
|
setlocal errorformat+=%+W%.%#\>\ WARN\ -\ Duplicate\ entry%m
|
||||||
|
setlocal errorformat+=%+W%.%#\>\ WARN\ -\ The\ entry%.%#cannot\ be\ encoded%m
|
||||||
|
setlocal errorformat+=%-G%.%#
|
||||||
|
execute 'caddfile' fnameescape(self.file)
|
||||||
|
let &l:errorformat = self.errorformat_saved
|
||||||
|
|
||||||
|
call self.fix_paths()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:biblatex.fix_paths() abort " {{{1
|
||||||
|
let l:qflist = getqflist()
|
||||||
|
try
|
||||||
|
let l:title = getqflist({'title': 1})
|
||||||
|
catch /E118/
|
||||||
|
let l:title = 'Vimtex errors'
|
||||||
|
endtry
|
||||||
|
|
||||||
|
for l:qf in l:qflist
|
||||||
|
for l:type in self.types
|
||||||
|
if l:type.fix(self, l:qf) | break | endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call setqflist(l:qflist, 'r')
|
||||||
|
|
||||||
|
" Set title if supported
|
||||||
|
try
|
||||||
|
call setqflist([], 'r', l:title)
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:biblatex.get_db_files() abort " {{{1
|
||||||
|
if empty(self.db_files)
|
||||||
|
let l:preamble = vimtex#parser#preamble(b:vimtex.tex, {
|
||||||
|
\ 'root' : b:vimtex.root,
|
||||||
|
\})
|
||||||
|
let l:files = map(
|
||||||
|
\ filter(l:preamble, 'v:val =~# ''\\addbibresource'''),
|
||||||
|
\ 'matchstr(v:val, ''{\zs.*\ze}'')')
|
||||||
|
let self.db_files = []
|
||||||
|
for l:file in l:files
|
||||||
|
if filereadable(l:file)
|
||||||
|
let self.db_files += [l:file]
|
||||||
|
elseif filereadable(expand(l:file))
|
||||||
|
let self.db_files += [expand(l:file)]
|
||||||
|
else
|
||||||
|
let l:cand = vimtex#kpsewhich#run(l:file)
|
||||||
|
if len(l:cand) == 1
|
||||||
|
let self.db_files += [l:cand[0]]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
return self.db_files
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:biblatex.get_filename(name) abort " {{{1
|
||||||
|
if !filereadable(a:name)
|
||||||
|
for l:root in [self.root, b:vimtex.root]
|
||||||
|
let l:candidate = fnamemodify(simplify(l:root . '/' . a:name), ':.')
|
||||||
|
if filereadable(l:candidate)
|
||||||
|
return l:candidate
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
return a:name
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:biblatex.get_key_pos(key) abort " {{{1
|
||||||
|
for l:file in self.get_db_files()
|
||||||
|
let l:lnum = self.get_key_lnum(a:key, l:file)
|
||||||
|
if l:lnum > 0
|
||||||
|
return [l:file, l:lnum]
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return []
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:biblatex.get_key_lnum(key, filename) abort " {{{1
|
||||||
|
if !filereadable(a:filename) | return 0 | endif
|
||||||
|
|
||||||
|
let l:lines = readfile(a:filename)
|
||||||
|
let l:lnums = range(len(l:lines))
|
||||||
|
let l:annotated_lines = map(l:lnums, '[v:val, l:lines[v:val]]')
|
||||||
|
let l:matches = filter(l:annotated_lines, 'v:val[1] =~# ''^\s*@\w*{\s*\V' . a:key . '''')
|
||||||
|
|
||||||
|
return len(l:matches) > 0 ? l:matches[-1][0]+1 : 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:biblatex.get_entry_key(filename, lnum) abort " {{{1
|
||||||
|
for l:file in self.get_db_files()
|
||||||
|
if fnamemodify(l:file, ':t') !=# a:filename | continue | endif
|
||||||
|
|
||||||
|
let l:entry = get(filter(readfile(l:file, 0, a:lnum), 'v:val =~# ''^@'''), -1)
|
||||||
|
if empty(l:entry) | continue | endif
|
||||||
|
|
||||||
|
return matchstr(l:entry, '{\v\zs.{-}\ze(,|$)')
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Parsers for the various warning types
|
||||||
|
"
|
||||||
|
|
||||||
|
let s:type_parse_error = {}
|
||||||
|
function! s:type_parse_error.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# 'ERROR - BibTeX subsystem.*expected end of entry'
|
||||||
|
let l:matches = matchlist(a:entry.text, '\v(\S*\.bib).*line (\d+)')
|
||||||
|
let a:entry.filename = a:ctx.get_filename(fnamemodify(l:matches[1], ':t'))
|
||||||
|
let a:entry.lnum = l:matches[2]
|
||||||
|
|
||||||
|
" Use filename and line number to get entry name
|
||||||
|
let l:key = a:ctx.get_entry_key(a:entry.filename, a:entry.lnum)
|
||||||
|
if !empty(l:key)
|
||||||
|
let a:entry.text = 'biblatex: Error parsing entry with key "' . l:key . '"'
|
||||||
|
endif
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_duplicate = {}
|
||||||
|
function! s:type_duplicate.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# 'WARN - Duplicate entry'
|
||||||
|
let l:matches = matchlist(a:entry.text, '\v: ''(\S*)'' in file ''(.{-})''')
|
||||||
|
let l:key = l:matches[1]
|
||||||
|
let a:entry.filename = a:ctx.get_filename(l:matches[2])
|
||||||
|
let a:entry.lnum = a:ctx.get_key_lnum(l:key, a:entry.filename)
|
||||||
|
let a:entry.text = 'biblatex: Duplicate entry key "' . l:key . '"'
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_no_driver = {}
|
||||||
|
function! s:type_no_driver.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# 'No driver for entry type'
|
||||||
|
let l:key = matchstr(a:entry.text, 'entry type ''\v\zs.{-}\ze''')
|
||||||
|
let a:entry.text = 'biblatex: Using fallback driver for ''' . l:key . ''''
|
||||||
|
|
||||||
|
let l:pos = a:ctx.get_key_pos(l:key)
|
||||||
|
if !empty(l:pos)
|
||||||
|
let a:entry.filename = a:ctx.get_filename(l:pos[0])
|
||||||
|
let a:entry.lnum = l:pos[1]
|
||||||
|
if has_key(a:entry, 'bufnr')
|
||||||
|
unlet a:entry.bufnr
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_not_found = {}
|
||||||
|
function! s:type_not_found.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# 'The following entry could not be found'
|
||||||
|
let l:key = split(a:entry.text, ' ')[-1]
|
||||||
|
let a:entry.text = 'biblatex: Entry with key ''' . l:key . ''' not found'
|
||||||
|
|
||||||
|
for [l:file, l:lnum, l:line] in vimtex#parser#tex(b:vimtex.tex)
|
||||||
|
if l:line =~# g:vimtex#re#not_comment . '\\\S*\V' . l:key
|
||||||
|
let a:entry.lnum = l:lnum
|
||||||
|
let a:entry.filename = l:file
|
||||||
|
unlet a:entry.bufnr
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_encoding = {}
|
||||||
|
function! s:type_encoding.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# 'The entry .* has characters which cannot'
|
||||||
|
let l:key = matchstr(a:entry.text, 'The entry ''\v\zs.{-}\ze''')
|
||||||
|
let a:entry.text = 'biblatex: Entry with key ''' . l:key . ''' has non-ascii characters'
|
||||||
|
|
||||||
|
let l:pos = a:ctx.get_key_pos(l:key)
|
||||||
|
if !empty(l:pos)
|
||||||
|
let a:entry.filename = a:ctx.get_filename(l:pos[0])
|
||||||
|
let a:entry.lnum = l:pos[1]
|
||||||
|
if has_key(a:entry, 'bufnr')
|
||||||
|
unlet a:entry.bufnr
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
187
autoload/vimtex/qf/bibtex.vim
Normal file
187
autoload/vimtex/qf/bibtex.vim
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#qf#bibtex#addqflist(blg) abort " {{{1
|
||||||
|
if get(g:vimtex_quickfix_blgparser, 'disable') | return | endif
|
||||||
|
|
||||||
|
try
|
||||||
|
call s:bibtex.addqflist(a:blg)
|
||||||
|
catch /BibTeX Aborted/
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:bibtex = {
|
||||||
|
\ 'file' : '',
|
||||||
|
\ 'types' : [],
|
||||||
|
\ 'db_files' : [],
|
||||||
|
\}
|
||||||
|
function! s:bibtex.addqflist(blg) abort " {{{1
|
||||||
|
let self.file = a:blg
|
||||||
|
if empty(self.file) || !filereadable(self.file) | throw 'BibTeX Aborted' | endif
|
||||||
|
|
||||||
|
let self.types = map(
|
||||||
|
\ filter(items(s:), 'v:val[0] =~# ''^type_'''),
|
||||||
|
\ 'v:val[1]')
|
||||||
|
let self.db_files = []
|
||||||
|
|
||||||
|
let self.errorformat_saved = &l:errorformat
|
||||||
|
setlocal errorformat=%+E%.%#---line\ %l\ of\ file\ %f
|
||||||
|
setlocal errorformat+=%+EI\ found\ %.%#---while\ reading\ file\ %f
|
||||||
|
setlocal errorformat+=%+WWarning--empty\ %.%#\ in\ %.%m
|
||||||
|
setlocal errorformat+=%+WWarning--entry\ type\ for%m
|
||||||
|
setlocal errorformat+=%-C--line\ %l\ of\ file\ %f
|
||||||
|
setlocal errorformat+=%-G%.%#
|
||||||
|
execute 'caddfile' fnameescape(self.file)
|
||||||
|
let &l:errorformat = self.errorformat_saved
|
||||||
|
|
||||||
|
call self.fix_paths()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:bibtex.fix_paths() abort " {{{1
|
||||||
|
let l:qflist = getqflist()
|
||||||
|
try
|
||||||
|
let l:title = getqflist({'title': 1})
|
||||||
|
catch /E118/
|
||||||
|
let l:title = 'Vimtex errors'
|
||||||
|
endtry
|
||||||
|
|
||||||
|
for l:qf in l:qflist
|
||||||
|
for l:type in self.types
|
||||||
|
if l:type.fix(self, l:qf) | break | endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call setqflist(l:qflist, 'r')
|
||||||
|
|
||||||
|
" Set title if supported
|
||||||
|
try
|
||||||
|
call setqflist([], 'r', l:title)
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:bibtex.get_db_files() abort " {{{1
|
||||||
|
if empty(self.db_files)
|
||||||
|
let l:build_dir = fnamemodify(b:vimtex.ext('log'), ':.:h') . '/'
|
||||||
|
for l:file in map(
|
||||||
|
\ filter(readfile(self.file), 'v:val =~# ''Database file #\d:'''),
|
||||||
|
\ 'matchstr(v:val, '': \zs.*'')')
|
||||||
|
if filereadable(l:file)
|
||||||
|
call add(self.db_files, l:file)
|
||||||
|
elseif filereadable(l:build_dir . l:file)
|
||||||
|
call add(self.db_files, l:build_dir . l:file)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
return self.db_files
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:bibtex.get_key_loc(key) abort " {{{1
|
||||||
|
for l:file in self.get_db_files()
|
||||||
|
let l:lines = readfile(l:file)
|
||||||
|
let l:lnum = 0
|
||||||
|
for l:line in l:lines
|
||||||
|
let l:lnum += 1
|
||||||
|
if l:line =~# '^\s*@\w*{\s*\V' . a:key
|
||||||
|
return [l:file, l:lnum]
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return []
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
"
|
||||||
|
" Parsers for the various warning types
|
||||||
|
"
|
||||||
|
|
||||||
|
let s:type_syn_error = {}
|
||||||
|
function! s:type_syn_error.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# '---line \d\+ of file'
|
||||||
|
let a:entry.text = split(a:entry.text, '---')[0]
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_empty = {
|
||||||
|
\ 're' : '\vWarning--empty (.*) in (\S*)',
|
||||||
|
\}
|
||||||
|
function! s:type_empty.fix(ctx, entry) abort " {{{1
|
||||||
|
let l:matches = matchlist(a:entry.text, self.re)
|
||||||
|
if empty(l:matches) | return 0 | endif
|
||||||
|
|
||||||
|
let l:type = l:matches[1]
|
||||||
|
let l:key = l:matches[2]
|
||||||
|
|
||||||
|
unlet a:entry.bufnr
|
||||||
|
let a:entry.text = printf('Missing "%s" in "%s"', l:type, l:key)
|
||||||
|
|
||||||
|
let l:loc = a:ctx.get_key_loc(l:key)
|
||||||
|
if !empty(l:loc)
|
||||||
|
let a:entry.filename = l:loc[0]
|
||||||
|
let a:entry.lnum = l:loc[1]
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_style_file_defined = {
|
||||||
|
\ 're' : '\vWarning--entry type for "(\w+)"',
|
||||||
|
\}
|
||||||
|
function! s:type_style_file_defined.fix(ctx, entry) abort " {{{1
|
||||||
|
let l:matches = matchlist(a:entry.text, self.re)
|
||||||
|
if empty(l:matches) | return 0 | endif
|
||||||
|
|
||||||
|
let l:key = l:matches[1]
|
||||||
|
|
||||||
|
unlet a:entry.bufnr
|
||||||
|
let a:entry.text = 'Entry type for "' . l:key . '" isn''t style-file defined'
|
||||||
|
|
||||||
|
let l:loc = a:ctx.get_key_loc(l:key)
|
||||||
|
if !empty(l:loc)
|
||||||
|
let a:entry.filename = l:loc[0]
|
||||||
|
let a:entry.lnum = l:loc[1]
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:type_no_bibstyle = {}
|
||||||
|
function! s:type_no_bibstyle.fix(ctx, entry) abort " {{{1
|
||||||
|
if a:entry.text =~# 'I found no \\bibstyle'
|
||||||
|
let a:entry.text = 'BibTeX found no \bibstyle command (missing \bibliographystyle?)'
|
||||||
|
let a:entry.filename = b:vimtex.tex
|
||||||
|
unlet a:entry.bufnr
|
||||||
|
for [l:file, l:lnum, l:line] in vimtex#parser#tex(b:vimtex.tex)
|
||||||
|
if l:line =~# g:vimtex#re#not_comment . '\\bibliography'
|
||||||
|
let a:entry.lnum = l:lnum
|
||||||
|
let a:entry.filename = l:file
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
209
autoload/vimtex/qf/latexlog.vim
Normal file
209
autoload/vimtex/qf/latexlog.vim
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#qf#latexlog#new() abort " {{{1
|
||||||
|
return deepcopy(s:qf)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:qf = {
|
||||||
|
\ 'name' : 'LaTeX logfile',
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:qf.init(state) abort dict "{{{1
|
||||||
|
let self.config = get(g:, 'vimtex_quickfix_latexlog', {})
|
||||||
|
let self.config.default = get(self.config, 'default', 1)
|
||||||
|
let self.config.packages = get(self.config, 'packages', {})
|
||||||
|
let self.config.packages.default = get(self.config.packages, 'default',
|
||||||
|
\ self.config.default)
|
||||||
|
|
||||||
|
let self.types = map(
|
||||||
|
\ filter(items(s:), 'v:val[0] =~# ''^type_'''),
|
||||||
|
\ 'v:val[1]')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:qf.set_errorformat() abort dict "{{{1
|
||||||
|
"
|
||||||
|
" Note: The errorformat assumes we're using the -file-line-error with
|
||||||
|
" [pdf]latex. For more info, see |errorformat-LaTeX|.
|
||||||
|
"
|
||||||
|
|
||||||
|
" Push file to file stack
|
||||||
|
setlocal errorformat=%-P**%f
|
||||||
|
setlocal errorformat+=%-P**\"%f\"
|
||||||
|
|
||||||
|
" Match errors
|
||||||
|
setlocal errorformat+=%E!\ LaTeX\ %trror:\ %m
|
||||||
|
setlocal errorformat+=%E%f:%l:\ %m
|
||||||
|
setlocal errorformat+=%E!\ %m
|
||||||
|
|
||||||
|
" More info for undefined control sequences
|
||||||
|
setlocal errorformat+=%Z<argument>\ %m
|
||||||
|
|
||||||
|
" More info for some errors
|
||||||
|
setlocal errorformat+=%Cl.%l\ %m
|
||||||
|
|
||||||
|
"
|
||||||
|
" Define general warnings
|
||||||
|
"
|
||||||
|
let l:default = self.config.default
|
||||||
|
if get(self.config, 'font', l:default)
|
||||||
|
setlocal errorformat+=%+WLaTeX\ Font\ Warning:\ %.%#line\ %l%.%#
|
||||||
|
setlocal errorformat+=%-CLaTeX\ Font\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-C(Font)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WLaTeX\ Font\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !get(self.config, 'references', l:default)
|
||||||
|
setlocal errorformat+=%-WLaTeX\ %.%#Warning:\ %.%#eference%.%#undefined%.%#line\ %l%.%#
|
||||||
|
setlocal errorformat+=%-WLaTeX\ %.%#Warning:\ %.%#undefined\ references.
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config, 'general', l:default)
|
||||||
|
setlocal errorformat+=%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#
|
||||||
|
setlocal errorformat+=%+WLaTeX\ %.%#Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config, 'overfull', l:default)
|
||||||
|
setlocal errorformat+=%+WOverfull\ %\\%\\hbox%.%#\ at\ lines\ %l--%*\\d
|
||||||
|
setlocal errorformat+=%+WOverfull\ %\\%\\hbox%.%#\ at\ line\ %l
|
||||||
|
setlocal errorformat+=%+WOverfull\ %\\%\\vbox%.%#\ at\ line\ %l
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config, 'underfull', l:default)
|
||||||
|
setlocal errorformat+=%+WUnderfull\ %\\%\\hbox%.%#\ at\ lines\ %l--%*\\d
|
||||||
|
setlocal errorformat+=%+WUnderfull\ %\\%\\vbox%.%#\ at\ line\ %l
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Define package related warnings
|
||||||
|
"
|
||||||
|
let l:default = self.config.packages.default
|
||||||
|
if get(self.config.packages, 'natbib', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ natbib\ Warning:\ %m\ on\ input\ line\ %l.
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ natbib\ Warning:\ %m\ on\ input\ line\ %l.
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'biblatex', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ biblatex\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-C(biblatex)%.%#in\ t%.%#
|
||||||
|
setlocal errorformat+=%-C(biblatex)%.%#Please\ v%.%#
|
||||||
|
setlocal errorformat+=%-C(biblatex)%.%#LaTeX\ a%.%#
|
||||||
|
setlocal errorformat+=%-C(biblatex)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ biblatex\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'babel', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ babel\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-Z(babel)%.%#input\ line\ %l.
|
||||||
|
setlocal errorformat+=%-C(babel)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ babel\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'hyperref', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ hyperref\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-C(hyperref)%m\ on\ input\ line\ %l.
|
||||||
|
setlocal errorformat+=%-C(hyperref)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ hyperref\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'scrreprt', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ scrreprt\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-C(scrreprt)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ scrreprt\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'fixltx2e', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ fixltx2e\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-C(fixltx2e)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ fixltx2e\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'titlesec', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ titlesec\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-C(titlesec)%m
|
||||||
|
else
|
||||||
|
setlocal errorformat+=%-WPackage\ titlesec\ Warning:\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(self.config.packages, 'general', l:default)
|
||||||
|
setlocal errorformat+=%+WPackage\ %.%#\ Warning:\ %m\ on\ input\ line\ %l.
|
||||||
|
setlocal errorformat+=%+WPackage\ %.%#\ Warning:\ %m
|
||||||
|
setlocal errorformat+=%-Z(%.%#)\ %m\ on\ input\ line\ %l.
|
||||||
|
setlocal errorformat+=%-C(%.%#)\ %m
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Ignore unmatched lines
|
||||||
|
setlocal errorformat+=%-G%.%#
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:qf.addqflist(tex, log) abort dict "{{{1
|
||||||
|
if empty(a:log) || !filereadable(a:log)
|
||||||
|
throw 'Vimtex: No log file found'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let self.errorformat_saved = &l:errorformat
|
||||||
|
call self.set_errorformat()
|
||||||
|
execute 'caddfile' fnameescape(a:log)
|
||||||
|
let &l:errorformat = self.errorformat_saved
|
||||||
|
|
||||||
|
" Apply some post processing of the quickfix list
|
||||||
|
let self.main = a:tex
|
||||||
|
let self.root = b:vimtex.root
|
||||||
|
call self.fix_paths()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:qf.pprint_items() abort dict " {{{1
|
||||||
|
return [[ 'config', self.config ]]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:qf.fix_paths() abort dict " {{{1
|
||||||
|
let l:qflist = getqflist()
|
||||||
|
|
||||||
|
for l:qf in l:qflist
|
||||||
|
" For errors and warnings that don't supply a file, the basename of the
|
||||||
|
" main file is used. However, if the working directory is not the root of
|
||||||
|
" the LaTeX project, than this results in bufnr = 0.
|
||||||
|
if l:qf.bufnr == 0
|
||||||
|
let l:qf.bufnr = bufnr(self.main)
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
" The buffer names of all file:line type errors are relative to the root of
|
||||||
|
" the main LaTeX file.
|
||||||
|
let l:file = fnamemodify(
|
||||||
|
\ simplify(self.root . '/' . bufname(l:qf.bufnr)), ':.')
|
||||||
|
if !filereadable(l:file) | continue | endif
|
||||||
|
|
||||||
|
if !bufexists(l:file)
|
||||||
|
execute 'badd' l:file
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:qf.filename = l:file
|
||||||
|
let l:qf.bufnr = bufnr(l:file)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call setqflist(l:qflist, 'r')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
98
autoload/vimtex/qf/pplatex.vim
Normal file
98
autoload/vimtex/qf/pplatex.vim
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" CreatedBy: Johannes Wienke (languitar@semipol.de)
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#qf#pplatex#new() abort " {{{1
|
||||||
|
return deepcopy(s:qf)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:qf = {
|
||||||
|
\ 'name' : 'LaTeX logfile using pplatex',
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:qf.init(state) abort dict "{{{1
|
||||||
|
if !executable('pplatex')
|
||||||
|
call vimtex#log#error('pplatex is not executable!')
|
||||||
|
throw 'vimtex: Requirements not met'
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Automatically remove the -file-line-error option if we use the latexmk
|
||||||
|
" backend (for convenience)
|
||||||
|
if a:state.compiler.name ==# 'latexmk'
|
||||||
|
let l:index = index(a:state.compiler.options, '-file-line-error')
|
||||||
|
if l:index >= 0
|
||||||
|
call remove(a:state.compiler.options, l:index)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:qf.set_errorformat() abort dict "{{{1
|
||||||
|
" Each new item starts with two asterics followed by the file, potentially
|
||||||
|
" a line number and sometimes even the message itself is on the same line.
|
||||||
|
" Please note that the trailing whitspaces in the error formats are
|
||||||
|
" intentional as pplatex produces these.
|
||||||
|
|
||||||
|
" Start of new items with file and line number, message on next line(s).
|
||||||
|
setlocal errorformat=%E**\ Error\ \ \ in\ %f\\,\ Line\ %l:%m
|
||||||
|
setlocal errorformat+=%W**\ Warning\ in\ %f\\,\ Line\ %l:%m
|
||||||
|
setlocal errorformat+=%I**\ BadBox\ \ in\ %f\\,\ Line\ %l:%m
|
||||||
|
|
||||||
|
" Start of items with with file, line and message on the same line. There are
|
||||||
|
" no BadBoxes reported this way.
|
||||||
|
setlocal errorformat+=%E**\ Error\ \ \ in\ %f\\,\ Line\ %l:%m
|
||||||
|
setlocal errorformat+=%W**\ Warning\ in\ %f\\,\ Line\ %l:%m
|
||||||
|
|
||||||
|
" Start of new items with only a file.
|
||||||
|
setlocal errorformat+=%E**\ Error\ \ \ in\ %f:%m
|
||||||
|
setlocal errorformat+=%W**\ Warning\ in\ %f:%m
|
||||||
|
setlocal errorformat+=%I**\ BadBox\ \ in\ %f:%m
|
||||||
|
|
||||||
|
" Start of items with with file and message on the same line. There are
|
||||||
|
" no BadBoxes reported this way.
|
||||||
|
setlocal errorformat+=%E**\ Error\ in\ %f:%m
|
||||||
|
setlocal errorformat+=%W**\ Warning\ in\ %f:%m
|
||||||
|
|
||||||
|
" Some errors are difficult even for pplatex
|
||||||
|
setlocal errorformat+=%E**\ Error\ \ :%m
|
||||||
|
|
||||||
|
" Anything that starts with three spaces is part of the message from a
|
||||||
|
" previously started multiline error item.
|
||||||
|
setlocal errorformat+=%C\ \ \ %m\ on\ input\ line\ %l.
|
||||||
|
setlocal errorformat+=%C\ \ \ %m
|
||||||
|
|
||||||
|
" Items are terminated with two newlines.
|
||||||
|
setlocal errorformat+=%-Z
|
||||||
|
|
||||||
|
" Skip statistical results at the bottom of the output.
|
||||||
|
setlocal errorformat+=%-GResult%.%#
|
||||||
|
setlocal errorformat+=%-G
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:qf.addqflist(tex, log) abort dict " {{{1
|
||||||
|
if empty(a:log) || !filereadable(a:log)
|
||||||
|
throw 'Vimtex: No log file found'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:tmp = fnameescape(fnamemodify(a:log, ':r') . '.pplatex')
|
||||||
|
let l:log = fnameescape(a:log)
|
||||||
|
|
||||||
|
silent call system(printf('pplatex -i %s >%s', l:log, l:tmp))
|
||||||
|
let self.errorformat_saved = &l:errorformat
|
||||||
|
call self.set_errorformat()
|
||||||
|
execute 'caddfile' l:tmp
|
||||||
|
let &l:errorformat = self.errorformat_saved
|
||||||
|
silent call system('rm ' . l:tmp)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
67
autoload/vimtex/qf/pulp.vim
Normal file
67
autoload/vimtex/qf/pulp.vim
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#qf#pulp#new() abort " {{{1
|
||||||
|
return deepcopy(s:qf)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:qf = {
|
||||||
|
\ 'name' : 'LaTeX logfile using pulp',
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:qf.init(state) abort dict "{{{1
|
||||||
|
if !executable('pulp')
|
||||||
|
call vimtex#log#error('pulp is not executable!')
|
||||||
|
throw 'vimtex: Requirements not met'
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Automatically remove the -file-line-error option if we use the latexmk
|
||||||
|
" backend (for convenience)
|
||||||
|
if a:state.compiler.name ==# 'latexmk'
|
||||||
|
let l:index = index(a:state.compiler.options, '-file-line-error')
|
||||||
|
if l:index >= 0
|
||||||
|
call remove(a:state.compiler.options, l:index)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:qf.set_errorformat() abort dict "{{{1
|
||||||
|
setlocal errorformat=
|
||||||
|
setlocal errorformat+=%-G%*[^\ ])\ %.%#
|
||||||
|
setlocal errorformat+=%-G%.%#For\ some\ reason%.%#
|
||||||
|
setlocal errorformat+=%W%f:%l-%*[0-9?]:\ %*[^\ ]\ warning:\ %m
|
||||||
|
setlocal errorformat+=%E%f:%l-%*[0-9?]:\ %*[^\ ]\ error:\ %m
|
||||||
|
setlocal errorformat+=%W%f:%l-%*[0-9?]:\ %m
|
||||||
|
setlocal errorformat+=%W%l-%*[0-9?]:\ %m
|
||||||
|
setlocal errorformat+=%-G%.%#
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:qf.addqflist(tex, log) abort dict " {{{1
|
||||||
|
if empty(a:log) || !filereadable(a:log)
|
||||||
|
call setqflist([])
|
||||||
|
throw 'Vimtex: No log file found'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:tmp = fnameescape(fnamemodify(a:log, ':r') . '.pulp')
|
||||||
|
let l:log = fnameescape(a:log)
|
||||||
|
|
||||||
|
silent call system(printf('pulp %s >%s', l:log, l:tmp))
|
||||||
|
let self.errorformat_saved = &l:errorformat
|
||||||
|
call self.set_errorformat()
|
||||||
|
execute 'caddfile' l:tmp
|
||||||
|
let &l:errorformat = self.errorformat_saved
|
||||||
|
silent call system('rm ' . l:tmp)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
110
autoload/vimtex/re.vim
Normal file
110
autoload/vimtex/re.vim
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
let g:vimtex#re#not_bslash = '\v%(\\@<!%(\\\\)*)@<='
|
||||||
|
let g:vimtex#re#not_comment = '\v%(' . g:vimtex#re#not_bslash . '\%.*)@<!'
|
||||||
|
|
||||||
|
let g:vimtex#re#tex_input_root =
|
||||||
|
\ '\v^\s*\%\s*!?\s*[tT][eE][xX]\s+[rR][oO][oO][tT]\s*\=\s*\zs.*\ze\s*$'
|
||||||
|
let g:vimtex#re#tex_input_latex = '\v\\%('
|
||||||
|
\ . join(get(g:, 'vimtex_include_indicators',
|
||||||
|
\ ['input', 'include', 'subfile', 'subfileinclude']),
|
||||||
|
\ '|') . ')\s*\{'
|
||||||
|
let g:vimtex#re#tex_input_import =
|
||||||
|
\ '\v\\%(sub)?%(import|%(input|include)from)\*?\{[^\}]*\}\{'
|
||||||
|
let g:vimtex#re#tex_input_package =
|
||||||
|
\ '\v\\%(usepackage|RequirePackage)%(\s*\[[^]]*\])?\s*\{\zs[^}]*\ze\}'
|
||||||
|
|
||||||
|
let g:vimtex#re#tex_input = '\v^\s*%(' . join([
|
||||||
|
\ g:vimtex#re#tex_input_latex,
|
||||||
|
\ g:vimtex#re#tex_input_import,
|
||||||
|
\ ], '|') . ')'
|
||||||
|
|
||||||
|
let g:vimtex#re#bib_input = '\v\\%(addbibresource|bibliography)>'
|
||||||
|
|
||||||
|
let g:vimtex#re#tex_include = g:vimtex#re#tex_input_root
|
||||||
|
\ . '|' . g:vimtex#re#tex_input . '\zs[^\}]*\ze\}?'
|
||||||
|
\ . '|' . g:vimtex#re#tex_input_package
|
||||||
|
|
||||||
|
" {{{1 Completion regexes
|
||||||
|
let g:vimtex#re#neocomplete =
|
||||||
|
\ '\v\\%('
|
||||||
|
\ . '\a*cite\a*%(\s*\[[^]]*\]){0,2}\s*\{[^}]*'
|
||||||
|
\ . '|%(text|block)cquote\*?%(\s*\[[^]]*\]){0,2}\s*\{[^}]*'
|
||||||
|
\ . '|%(for|hy)\w*cquote\*?\{[^}]*}%(\s*\[[^]]*\]){0,2}\s*\{[^}]*'
|
||||||
|
\ . '|\a*ref%(\s*\{[^}]*|range\s*\{[^,}]*%(}\{)?)'
|
||||||
|
\ . '|hyperref\s*\[[^]]*'
|
||||||
|
\ . '|includegraphics\*?%(\s*\[[^]]*\]){0,2}\s*\{[^}]*'
|
||||||
|
\ . '|%(include%(only)?|input|subfile)\s*\{[^}]*'
|
||||||
|
\ . '|([cpdr]?(gls|Gls|GLS)|acr|Acr|ACR)\a*\s*\{[^}]*'
|
||||||
|
\ . '|(ac|Ac|AC)\s*\{[^}]*'
|
||||||
|
\ . '|includepdf%(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|includestandalone%(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|%(usepackage|RequirePackage|PassOptionsToPackage)%(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|documentclass%(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|begin%(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|end%(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|\a*'
|
||||||
|
\ . ')'
|
||||||
|
|
||||||
|
let g:vimtex#re#deoplete = '\\(?:'
|
||||||
|
\ . '\w*cite\w*(?:\s*\[[^]]*\]){0,2}\s*{[^}]*'
|
||||||
|
\ . '|(text|block)cquote\*?(?:\s*\[[^]]*\]){0,2}\s*{[^}]*'
|
||||||
|
\ . '|(for|hy)\w*cquote\*?{[^}]*}(?:\s*\[[^]]*\]){0,2}\s*{[^}]*'
|
||||||
|
\ . '|\w*ref(?:\s*\{[^}]*|range\s*\{[^,}]*(?:}{)?)'
|
||||||
|
\ . '|hyperref\s*\[[^]]*'
|
||||||
|
\ . '|includegraphics\*?(?:\s*\[[^]]*\]){0,2}\s*\{[^}]*'
|
||||||
|
\ . '|(?:include(?:only)?|input|subfile)\s*\{[^}]*'
|
||||||
|
\ . '|([cpdr]?(gls|Gls|GLS)|acr|Acr|ACR)[a-zA-Z]*\s*\{[^}]*'
|
||||||
|
\ . '|(ac|Ac|AC)\s*\{[^}]*'
|
||||||
|
\ . '|includepdf(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|includestandalone(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|(usepackage|RequirePackage|PassOptionsToPackage)(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|documentclass(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|begin(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|end(\s*\[[^]]*\])?\s*\{[^}]*'
|
||||||
|
\ . '|\w*'
|
||||||
|
\ .')'
|
||||||
|
|
||||||
|
let g:vimtex#re#ncm2#cmds = [
|
||||||
|
\ '\\[A-Za-z]+',
|
||||||
|
\ '\\(usepackage|RequirePackage|PassOptionsToPackage)(\s*\[[^]]*\])?\s*\{[^}]*',
|
||||||
|
\ '\\documentclass(\s*\[[^]]*\])?\s*\{[^}]*',
|
||||||
|
\ '\\begin(\s*\[[^]]*\])?\s*\{[^}]*',
|
||||||
|
\ '\\end(\s*\[[^]]*\])?\s*\{[^}]*',
|
||||||
|
\]
|
||||||
|
let g:vimtex#re#ncm2#bibtex = [
|
||||||
|
\ '\\[A-Za-z]*cite[A-Za-z]*(\[[^]]*\]){0,2}{[^}]*',
|
||||||
|
\ '\\(text|block)cquote\*?(\[[^]]*\]){0,2}{[^}]*',
|
||||||
|
\ '\\(for|hy)[A-Za-z]*cquote\*?{[^}]*}(\[[^]]*\]){0,2}{[^}]*',
|
||||||
|
\]
|
||||||
|
let g:vimtex#re#ncm2#labels = [
|
||||||
|
\ '\\[A-Za-z]*ref({[^}]*|range{([^,{}]*(}{)?))',
|
||||||
|
\ '\\hyperref\[[^]]*',
|
||||||
|
\ '\\([cpdr]?(gls|Gls|GLS)|acr|Acr|ACR)[a-zA-Z]*\s*\{[^}]*',
|
||||||
|
\ '\\(ac|Ac|AC)\s*\{[^}]*',
|
||||||
|
\]
|
||||||
|
let g:vimtex#re#ncm2#files = [
|
||||||
|
\ '\\includegraphics\*?(\[[^]]*\]){0,2}{[^}]*',
|
||||||
|
\ '\\(include(only)?|input|subfile){[^}]*',
|
||||||
|
\ '\\includepdf(\s*\[[^]]*\])?\s*\{[^}]*',
|
||||||
|
\ '\\includestandalone(\s*\[[^]]*\])?\s*\{[^}]*',
|
||||||
|
\]
|
||||||
|
|
||||||
|
let g:vimtex#re#ncm2 = g:vimtex#re#ncm2#cmds +
|
||||||
|
\ g:vimtex#re#ncm2#bibtex +
|
||||||
|
\ g:vimtex#re#ncm2#labels +
|
||||||
|
\ g:vimtex#re#ncm2#files
|
||||||
|
|
||||||
|
let g:vimtex#re#ncm = copy(g:vimtex#re#ncm2)
|
||||||
|
|
||||||
|
let g:vimtex#re#youcompleteme = map(copy(g:vimtex#re#ncm), "'re!' . v:val")
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
72
autoload/vimtex/scratch.vim
Normal file
72
autoload/vimtex/scratch.vim
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#scratch#new(opts) abort " {{{1
|
||||||
|
let l:buf = extend(deepcopy(s:scratch), a:opts)
|
||||||
|
call l:buf.open()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
let s:scratch = {
|
||||||
|
\ 'name' : 'VimtexScratch'
|
||||||
|
\}
|
||||||
|
function! s:scratch.open() abort dict " {{{1
|
||||||
|
let l:bufnr = bufnr('')
|
||||||
|
let l:vimtex = get(b:, 'vimtex', {})
|
||||||
|
|
||||||
|
silent execute 'keepalt edit' escape(self.name, ' ')
|
||||||
|
|
||||||
|
let self.prev_bufnr = l:bufnr
|
||||||
|
let b:scratch = self
|
||||||
|
let b:vimtex = l:vimtex
|
||||||
|
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
setlocal buftype=nofile
|
||||||
|
setlocal concealcursor=nvic
|
||||||
|
setlocal conceallevel=0
|
||||||
|
setlocal nobuflisted
|
||||||
|
setlocal nolist
|
||||||
|
setlocal nospell
|
||||||
|
setlocal noswapfile
|
||||||
|
setlocal nowrap
|
||||||
|
setlocal tabstop=8
|
||||||
|
|
||||||
|
nnoremap <silent><nowait><buffer> q :call b:scratch.close()<cr>
|
||||||
|
nnoremap <silent><nowait><buffer> <esc> :call b:scratch.close()<cr>
|
||||||
|
nnoremap <silent><nowait><buffer> <c-6> :call b:scratch.close()<cr>
|
||||||
|
nnoremap <silent><nowait><buffer> <c-^> :call b:scratch.close()<cr>
|
||||||
|
nnoremap <silent><nowait><buffer> <c-e> :call b:scratch.close()<cr>
|
||||||
|
|
||||||
|
if has_key(self, 'syntax')
|
||||||
|
call self.syntax()
|
||||||
|
endif
|
||||||
|
|
||||||
|
call self.fill()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:scratch.close() abort dict " {{{1
|
||||||
|
silent execute 'keepalt buffer' self.prev_bufnr
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:scratch.fill() abort dict " {{{1
|
||||||
|
setlocal modifiable
|
||||||
|
%delete
|
||||||
|
|
||||||
|
call self.print_content()
|
||||||
|
|
||||||
|
0delete _
|
||||||
|
setlocal nomodifiable
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
endif
|
||||||
745
autoload/vimtex/state.vim
Normal file
745
autoload/vimtex/state.vim
Normal file
@@ -0,0 +1,745 @@
|
|||||||
|
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
||||||
|
|
||||||
|
" vimtex - LaTeX plugin for Vim
|
||||||
|
"
|
||||||
|
" Maintainer: Karl Yngve Lervåg
|
||||||
|
" Email: karl.yngve@gmail.com
|
||||||
|
"
|
||||||
|
|
||||||
|
function! vimtex#state#init_buffer() abort " {{{1
|
||||||
|
command! -buffer VimtexToggleMain call vimtex#state#toggle_main()
|
||||||
|
command! -buffer VimtexReloadState call vimtex#state#reload()
|
||||||
|
|
||||||
|
nnoremap <buffer> <plug>(vimtex-toggle-main) :VimtexToggleMain<cr>
|
||||||
|
nnoremap <buffer> <plug>(vimtex-reload-state) :VimtexReloadState<cr>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#init() abort " {{{1
|
||||||
|
let [l:main, l:main_type] = s:get_main()
|
||||||
|
let l:id = s:get_main_id(l:main)
|
||||||
|
|
||||||
|
if l:id >= 0
|
||||||
|
let b:vimtex_id = l:id
|
||||||
|
let b:vimtex = s:vimtex_states[l:id]
|
||||||
|
else
|
||||||
|
let b:vimtex_id = s:vimtex_next_id
|
||||||
|
let b:vimtex = s:vimtex.new(l:main, l:main_type, 0)
|
||||||
|
let s:vimtex_next_id += 1
|
||||||
|
let s:vimtex_states[b:vimtex_id] = b:vimtex
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#init_local() abort " {{{1
|
||||||
|
let l:filename = expand('%:p')
|
||||||
|
let l:preserve_root = get(s:, 'subfile_preserve_root')
|
||||||
|
unlet! s:subfile_preserve_root
|
||||||
|
|
||||||
|
if b:vimtex.tex ==# l:filename | return | endif
|
||||||
|
|
||||||
|
let l:vimtex_id = s:get_main_id(l:filename)
|
||||||
|
|
||||||
|
if l:vimtex_id < 0
|
||||||
|
let l:vimtex_id = s:vimtex_next_id
|
||||||
|
let l:vimtex = s:vimtex.new(l:filename, 'local file', l:preserve_root)
|
||||||
|
let s:vimtex_next_id += 1
|
||||||
|
let s:vimtex_states[l:vimtex_id] = l:vimtex
|
||||||
|
|
||||||
|
if !has_key(b:vimtex, 'subids')
|
||||||
|
let b:vimtex.subids = []
|
||||||
|
endif
|
||||||
|
call add(b:vimtex.subids, l:vimtex_id)
|
||||||
|
let l:vimtex.main_id = b:vimtex_id
|
||||||
|
endif
|
||||||
|
|
||||||
|
let b:vimtex_local = {
|
||||||
|
\ 'active' : 0,
|
||||||
|
\ 'main_id' : b:vimtex_id,
|
||||||
|
\ 'sub_id' : l:vimtex_id,
|
||||||
|
\}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#reload() abort " {{{1
|
||||||
|
let l:id = s:get_main_id(expand('%:p'))
|
||||||
|
if has_key(s:vimtex_states, l:id)
|
||||||
|
let l:vimtex = remove(s:vimtex_states, l:id)
|
||||||
|
call l:vimtex.cleanup()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(s:vimtex_states, get(b:, 'vimtex_id', -1))
|
||||||
|
let l:vimtex = remove(s:vimtex_states, b:vimtex_id)
|
||||||
|
call l:vimtex.cleanup()
|
||||||
|
endif
|
||||||
|
|
||||||
|
call vimtex#state#init()
|
||||||
|
call vimtex#state#init_local()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! vimtex#state#toggle_main() abort " {{{1
|
||||||
|
if exists('b:vimtex_local')
|
||||||
|
let b:vimtex_local.active = !b:vimtex_local.active
|
||||||
|
|
||||||
|
let b:vimtex_id = b:vimtex_local.active
|
||||||
|
\ ? b:vimtex_local.sub_id
|
||||||
|
\ : b:vimtex_local.main_id
|
||||||
|
let b:vimtex = vimtex#state#get(b:vimtex_id)
|
||||||
|
|
||||||
|
call vimtex#log#info('Changed to `' . b:vimtex.base . "' "
|
||||||
|
\ . (b:vimtex_local.active ? '[local]' : '[main]'))
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#list_all() abort " {{{1
|
||||||
|
return values(s:vimtex_states)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#exists(id) abort " {{{1
|
||||||
|
return has_key(s:vimtex_states, a:id)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#get(id) abort " {{{1
|
||||||
|
return s:vimtex_states[a:id]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#get_all() abort " {{{1
|
||||||
|
return s:vimtex_states
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! vimtex#state#cleanup(id) abort " {{{1
|
||||||
|
if !vimtex#state#exists(a:id) | return | endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Count the number of open buffers for the given blob
|
||||||
|
"
|
||||||
|
let l:buffers = filter(range(1, bufnr('$')), 'buflisted(v:val)')
|
||||||
|
let l:ids = map(l:buffers, 'getbufvar(v:val, ''vimtex_id'', -1)')
|
||||||
|
let l:count = count(l:ids, a:id)
|
||||||
|
|
||||||
|
"
|
||||||
|
" Don't clean up if there are more than one buffer connected to the current
|
||||||
|
" blob
|
||||||
|
"
|
||||||
|
if l:count > 1 | return | endif
|
||||||
|
let l:vimtex = vimtex#state#get(a:id)
|
||||||
|
|
||||||
|
"
|
||||||
|
" Handle possible subfiles properly
|
||||||
|
"
|
||||||
|
if has_key(l:vimtex, 'subids')
|
||||||
|
let l:subcount = 0
|
||||||
|
for l:sub_id in get(l:vimtex, 'subids', [])
|
||||||
|
let l:subcount += count(l:ids, l:sub_id)
|
||||||
|
endfor
|
||||||
|
if l:count + l:subcount > 1 | return | endif
|
||||||
|
|
||||||
|
for l:sub_id in get(l:vimtex, 'subids', [])
|
||||||
|
call remove(s:vimtex_states, l:sub_id).cleanup()
|
||||||
|
endfor
|
||||||
|
|
||||||
|
call remove(s:vimtex_states, a:id).cleanup()
|
||||||
|
else
|
||||||
|
call remove(s:vimtex_states, a:id).cleanup()
|
||||||
|
|
||||||
|
if has_key(l:vimtex, 'main_id')
|
||||||
|
let l:main = vimtex#state#get(l:vimtex.main_id)
|
||||||
|
|
||||||
|
let l:count_main = count(l:ids, l:vimtex.main_id)
|
||||||
|
for l:sub_id in get(l:main, 'subids', [])
|
||||||
|
let l:count_main += count(l:ids, l:sub_id)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if l:count_main + l:count <= 1
|
||||||
|
call remove(s:vimtex_states, l:vimtex.main_id).cleanup()
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
function! s:get_main_id(main) abort " {{{1
|
||||||
|
for [l:id, l:state] in items(s:vimtex_states)
|
||||||
|
if l:state.tex == a:main
|
||||||
|
return str2nr(l:id)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return -1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_main() abort " {{{1
|
||||||
|
if exists('s:disabled_modules')
|
||||||
|
unlet s:disabled_modules
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Use buffer variable if it exists
|
||||||
|
"
|
||||||
|
if exists('b:vimtex_main') && filereadable(b:vimtex_main)
|
||||||
|
return [fnamemodify(b:vimtex_main, ':p'), 'buffer variable']
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Search for TEX root specifier at the beginning of file. This is used by
|
||||||
|
" several other plugins and editors.
|
||||||
|
"
|
||||||
|
let l:candidate = s:get_main_from_texroot()
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return [l:candidate, 'texroot specifier']
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Check if the current file is a main file
|
||||||
|
"
|
||||||
|
if s:file_is_main(expand('%:p'))
|
||||||
|
return [expand('%:p'), 'current file verified']
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Support for subfiles package
|
||||||
|
"
|
||||||
|
let l:candidate = s:get_main_from_subfile()
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return [l:candidate, 'subfiles']
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Search for .latexmain-specifier
|
||||||
|
"
|
||||||
|
let l:candidate = s:get_main_latexmain(expand('%:p'))
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return [l:candidate, 'latexmain specifier']
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Search for .latexmkrc @default_files specifier
|
||||||
|
"
|
||||||
|
let l:candidate = s:get_main_latexmk()
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return [l:candidate, 'latexmkrc @default_files']
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Check if we are class or style file
|
||||||
|
"
|
||||||
|
if index(['cls', 'sty'], expand('%:e')) >= 0
|
||||||
|
let l:id = getbufvar('#', 'vimtex_id', -1)
|
||||||
|
if l:id >= 0 && has_key(s:vimtex_states, l:id)
|
||||||
|
return [s:vimtex_states[l:id].tex, 'cls/sty file (inherit from alternate)']
|
||||||
|
else
|
||||||
|
let s:disabled_modules = ['latexmk', 'view', 'toc']
|
||||||
|
return [expand('%:p'), 'cls/sty file']
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Search for main file recursively through include specifiers
|
||||||
|
"
|
||||||
|
if !get(g:, 'vimtex_disable_recursive_main_file_detection', 0)
|
||||||
|
let l:candidate = s:get_main_choose(s:get_main_recurse())
|
||||||
|
if !empty(l:candidate)
|
||||||
|
return [l:candidate, 'recursive search']
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Use fallback candidate or the current file
|
||||||
|
"
|
||||||
|
let l:candidate = get(s:, 'cand_fallback', expand('%:p'))
|
||||||
|
if exists('s:cand_fallback')
|
||||||
|
unlet s:cand_fallback
|
||||||
|
return [l:candidate, 'fallback']
|
||||||
|
else
|
||||||
|
return [l:candidate, 'current file']
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_main_from_texroot() abort " {{{1
|
||||||
|
for l:line in getline(1, 5)
|
||||||
|
let l:file_pattern = matchstr(l:line, g:vimtex#re#tex_input_root)
|
||||||
|
if empty(l:file_pattern) | continue | endif
|
||||||
|
|
||||||
|
if !vimtex#paths#is_abs(l:file_pattern)
|
||||||
|
let l:file_pattern = simplify(expand('%:p:h') . '/' . l:file_pattern)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:candidates = glob(l:file_pattern, 0, 1)
|
||||||
|
if len(l:candidates) > 1
|
||||||
|
return s:get_main_choose(l:candidates)
|
||||||
|
elseif len(l:candidates) == 1
|
||||||
|
return l:candidates[0]
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_main_from_subfile() abort " {{{1
|
||||||
|
for l:line in getline(1, 5)
|
||||||
|
let l:filename = matchstr(l:line,
|
||||||
|
\ '^\C\s*\\documentclass\[\zs.*\ze\]{subfiles}')
|
||||||
|
if len(l:filename) > 0
|
||||||
|
if l:filename !~# '\.tex$'
|
||||||
|
let l:filename .= '.tex'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if vimtex#paths#is_abs(l:filename)
|
||||||
|
" Specified path is absolute
|
||||||
|
if filereadable(l:filename) | return l:filename | endif
|
||||||
|
else
|
||||||
|
" Try specified path as relative to current file path
|
||||||
|
let l:candidate = simplify(expand('%:p:h') . '/' . l:filename)
|
||||||
|
if filereadable(l:candidate) | return l:candidate | endif
|
||||||
|
|
||||||
|
" Try specified path as relative to the project main file. This is
|
||||||
|
" difficult, since the main file is the one we are looking for. We
|
||||||
|
" therefore assume that the main file lives somewhere upwards in the
|
||||||
|
" directory tree.
|
||||||
|
let l:candidate = fnamemodify(findfile(l:filename, '.;'), ':p')
|
||||||
|
if filereadable(l:candidate)
|
||||||
|
\ && s:file_reaches_current(l:candidate)
|
||||||
|
let s:subfile_preserve_root = 1
|
||||||
|
return fnamemodify(candidate, ':p')
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Check the alternate buffer. This seems sensible e.g. in cases where one
|
||||||
|
" enters an "outer" subfile through a 'gf' motion from the main file.
|
||||||
|
let l:vimtex = getbufvar('#', 'vimtex', {})
|
||||||
|
for l:file in get(l:vimtex, 'sources', [])
|
||||||
|
if expand('%:p') ==# simplify(l:vimtex.root . '/' . l:file)
|
||||||
|
let s:subfile_preserve_root = 1
|
||||||
|
return l:vimtex.tex
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_main_latexmain(file) abort " {{{1
|
||||||
|
for l:cand in s:findfiles_recursive('*.latexmain', expand('%:p:h'))
|
||||||
|
let l:cand = fnamemodify(l:cand, ':p:r')
|
||||||
|
if s:file_reaches_current(l:cand)
|
||||||
|
return l:cand
|
||||||
|
else
|
||||||
|
let s:cand_fallback = l:cand
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_main_latexmk() abort " {{{1
|
||||||
|
let l:root = expand('%:p:h')
|
||||||
|
let l:results = vimtex#compiler#latexmk#get_rc_opt(
|
||||||
|
\ l:root, 'default_files', 2, [])
|
||||||
|
if l:results[1] < 1 | return '' | endif
|
||||||
|
|
||||||
|
for l:candidate in l:results[0]
|
||||||
|
let l:file = l:root . '/' . l:candidate
|
||||||
|
if filereadable(l:file)
|
||||||
|
return l:file
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_main_recurse(...) abort " {{{1
|
||||||
|
" Either start the search from the original file, or check if the supplied
|
||||||
|
" file is a main file (or invalid)
|
||||||
|
if a:0 == 0
|
||||||
|
let l:file = expand('%:p')
|
||||||
|
let l:tried = {}
|
||||||
|
else
|
||||||
|
let l:file = a:1
|
||||||
|
let l:tried = a:2
|
||||||
|
|
||||||
|
if s:file_is_main(l:file)
|
||||||
|
return [l:file]
|
||||||
|
elseif !filereadable(l:file)
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Create list of candidates that was already tried for the current file
|
||||||
|
if !has_key(l:tried, l:file)
|
||||||
|
let l:tried[l:file] = [l:file]
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Apply filters successively (minor optimization)
|
||||||
|
let l:re_filter1 = fnamemodify(l:file, ':t:r')
|
||||||
|
let l:re_filter2 = g:vimtex#re#tex_input . '\s*\f*' . l:re_filter1
|
||||||
|
|
||||||
|
" Search through candidates found recursively upwards in the directory tree
|
||||||
|
let l:results = []
|
||||||
|
for l:cand in s:findfiles_recursive('*.tex', fnamemodify(l:file, ':p:h'))
|
||||||
|
if index(l:tried[l:file], l:cand) >= 0 | continue | endif
|
||||||
|
call add(l:tried[l:file], l:cand)
|
||||||
|
|
||||||
|
if len(filter(filter(readfile(l:cand),
|
||||||
|
\ 'v:val =~# l:re_filter1'),
|
||||||
|
\ 'v:val =~# l:re_filter2')) > 0
|
||||||
|
let l:results += s:get_main_recurse(fnamemodify(l:cand, ':p'), l:tried)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:results
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:get_main_choose(list) abort " {{{1
|
||||||
|
let l:list = vimtex#util#uniq_unsorted(a:list)
|
||||||
|
|
||||||
|
if empty(l:list) | return '' | endif
|
||||||
|
if len(l:list) == 1 | return l:list[0] | endif
|
||||||
|
|
||||||
|
let l:all = map(copy(l:list), '[s:get_main_id(v:val), v:val]')
|
||||||
|
let l:new = map(filter(copy(l:all), 'v:val[0] < 0'), 'v:val[1]')
|
||||||
|
let l:existing = {}
|
||||||
|
for [l:key, l:val] in filter(copy(l:all), 'v:val[0] >= 0')
|
||||||
|
let l:existing[l:key] = l:val
|
||||||
|
endfor
|
||||||
|
let l:alternate_id = getbufvar('#', 'vimtex_id', -1)
|
||||||
|
|
||||||
|
if len(l:existing) == 1
|
||||||
|
return values(l:existing)[0]
|
||||||
|
elseif len(l:existing) > 1 && has_key(l:existing, l:alternate_id)
|
||||||
|
return l:existing[l:alternate_id]
|
||||||
|
elseif len(l:existing) < 1 && len(l:new) == 1
|
||||||
|
return l:new[0]
|
||||||
|
else
|
||||||
|
let l:choices = {}
|
||||||
|
for l:tex in l:list
|
||||||
|
let l:choices[l:tex] = vimtex#paths#relative(l:tex, getcwd())
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return vimtex#echo#choose(l:choices,
|
||||||
|
\ 'Please select an appropriate main file:')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:file_is_main(file) abort " {{{1
|
||||||
|
if !filereadable(a:file) | return 0 | endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" Check if a:file is a main file by looking for the \documentclass command,
|
||||||
|
" but ignore the following:
|
||||||
|
"
|
||||||
|
" \documentclass[...]{subfiles}
|
||||||
|
" \documentclass[...]{standalone}
|
||||||
|
"
|
||||||
|
let l:lines = readfile(a:file, 0, 50)
|
||||||
|
call filter(l:lines, 'v:val =~# ''\C\\documentclass\_\s*[\[{]''')
|
||||||
|
call filter(l:lines, 'v:val !~# ''{subfiles}''')
|
||||||
|
call filter(l:lines, 'v:val !~# ''{standalone}''')
|
||||||
|
if len(l:lines) == 0 | return 0 | endif
|
||||||
|
|
||||||
|
" A main file contains `\begin{document}`
|
||||||
|
let l:lines = vimtex#parser#preamble(a:file, {
|
||||||
|
\ 'inclusive' : 1,
|
||||||
|
\ 'root' : fnamemodify(a:file, ':p:h'),
|
||||||
|
\})
|
||||||
|
call filter(l:lines, 'v:val =~# ''\\begin\s*{document}''')
|
||||||
|
return len(l:lines) > 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:file_reaches_current(file) abort " {{{1
|
||||||
|
" Note: This function assumes that the input a:file is an absolute path
|
||||||
|
if !filereadable(a:file) | return 0 | endif
|
||||||
|
|
||||||
|
for l:line in filter(readfile(a:file), 'v:val =~# g:vimtex#re#tex_input')
|
||||||
|
let l:file = matchstr(l:line, g:vimtex#re#tex_input . '\zs\f+')
|
||||||
|
if empty(l:file) | continue | endif
|
||||||
|
|
||||||
|
if !vimtex#paths#is_abs(l:file)
|
||||||
|
let l:file = fnamemodify(a:file, ':h') . '/' . l:file
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:file !~# '\.tex$'
|
||||||
|
let l:file .= '.tex'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if expand('%:p') ==# l:file
|
||||||
|
\ || s:file_reaches_current(l:file)
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:findfiles_recursive(expr, path) abort " {{{1
|
||||||
|
let l:path = a:path
|
||||||
|
let l:dirs = l:path
|
||||||
|
while l:path != fnamemodify(l:path, ':h')
|
||||||
|
let l:path = fnamemodify(l:path, ':h')
|
||||||
|
let l:dirs .= ',' . l:path
|
||||||
|
endwhile
|
||||||
|
return split(globpath(fnameescape(l:dirs), a:expr), '\n')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
let s:vimtex = {}
|
||||||
|
|
||||||
|
function! s:vimtex.new(main, main_parser, preserve_root) abort dict " {{{1
|
||||||
|
let l:new = deepcopy(self)
|
||||||
|
let l:new.tex = a:main
|
||||||
|
let l:new.root = fnamemodify(l:new.tex, ':h')
|
||||||
|
let l:new.base = fnamemodify(l:new.tex, ':t')
|
||||||
|
let l:new.name = fnamemodify(l:new.tex, ':t:r')
|
||||||
|
let l:new.main_parser = a:main_parser
|
||||||
|
|
||||||
|
if a:preserve_root && exists('b:vimtex')
|
||||||
|
let l:new.root = b:vimtex.root
|
||||||
|
let l:new.base = vimtex#paths#relative(a:main, l:new.root)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists('s:disabled_modules')
|
||||||
|
let l:new.disabled_modules = s:disabled_modules
|
||||||
|
endif
|
||||||
|
|
||||||
|
"
|
||||||
|
" The preamble content is used to parse for the engine directive, the
|
||||||
|
" documentclass and the package list; we store it as a temporary shared
|
||||||
|
" object variable
|
||||||
|
"
|
||||||
|
let l:new.preamble = vimtex#parser#preamble(l:new.tex, {
|
||||||
|
\ 'root' : l:new.root,
|
||||||
|
\})
|
||||||
|
|
||||||
|
call l:new.parse_tex_program()
|
||||||
|
call l:new.parse_documentclass()
|
||||||
|
call l:new.parse_graphicspath()
|
||||||
|
call l:new.gather_sources()
|
||||||
|
|
||||||
|
call vimtex#view#init_state(l:new)
|
||||||
|
call vimtex#compiler#init_state(l:new)
|
||||||
|
call vimtex#qf#init_state(l:new)
|
||||||
|
call vimtex#toc#init_state(l:new)
|
||||||
|
call vimtex#fold#init_state(l:new)
|
||||||
|
|
||||||
|
" Parsing packages might depend on the compiler setting for build_dir
|
||||||
|
call l:new.parse_packages()
|
||||||
|
|
||||||
|
unlet l:new.preamble
|
||||||
|
unlet l:new.new
|
||||||
|
return l:new
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.cleanup() abort dict " {{{1
|
||||||
|
if exists('self.compiler.cleanup')
|
||||||
|
call self.compiler.cleanup()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists('#User#VimtexEventQuit')
|
||||||
|
if exists('b:vimtex')
|
||||||
|
let b:vimtex_tmp = b:vimtex
|
||||||
|
endif
|
||||||
|
let b:vimtex = self
|
||||||
|
doautocmd <nomodeline> User VimtexEventQuit
|
||||||
|
if exists('b:vimtex_tmp')
|
||||||
|
let b:vimtex = b:vimtex_tmp
|
||||||
|
unlet b:vimtex_tmp
|
||||||
|
else
|
||||||
|
unlet b:vimtex
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Close quickfix window
|
||||||
|
silent! cclose
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.parse_tex_program() abort dict " {{{1
|
||||||
|
let l:lines = copy(self.preamble[:20])
|
||||||
|
let l:tex_program_re =
|
||||||
|
\ '\v^\c\s*\%\s*\!?\s*tex\s+%(TS-)?program\s*\=\s*\zs.*\ze\s*$'
|
||||||
|
call map(l:lines, 'matchstr(v:val, l:tex_program_re)')
|
||||||
|
call filter(l:lines, '!empty(v:val)')
|
||||||
|
let self.tex_program = tolower(get(l:lines, -1, '_'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.parse_documentclass() abort dict " {{{1
|
||||||
|
let self.documentclass = ''
|
||||||
|
for l:line in self.preamble
|
||||||
|
let l:class = matchstr(l:line, '^\s*\\documentclass.*{\zs\w*\ze}')
|
||||||
|
if !empty(l:class)
|
||||||
|
let self.documentclass = l:class
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.parse_graphicspath() abort dict " {{{1
|
||||||
|
" Combine the preamble as one long string of commands
|
||||||
|
let l:preamble = join(map(copy(self.preamble),
|
||||||
|
\ 'substitute(v:val, ''\\\@<!%.*'', '''', '''')'))
|
||||||
|
|
||||||
|
" Extract the graphicspath command from this string
|
||||||
|
let l:graphicspath = matchstr(l:preamble,
|
||||||
|
\ g:vimtex#re#not_bslash
|
||||||
|
\ . '\\graphicspath\s*\{\s*\{\s*\zs.{-}\ze\s*\}\s*\}'
|
||||||
|
\)
|
||||||
|
|
||||||
|
" Add all parsed graphicspaths
|
||||||
|
let self.graphicspath = []
|
||||||
|
for l:path in split(l:graphicspath, '\s*}\s*{\s*')
|
||||||
|
let l:path = substitute(l:path, '\/\s*$', '', '')
|
||||||
|
call add(self.graphicspath, vimtex#paths#is_abs(l:path)
|
||||||
|
\ ? l:path
|
||||||
|
\ : simplify(self.root . '/' . l:path))
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.parse_packages() abort dict " {{{1
|
||||||
|
let self.packages = get(self, 'packages', {})
|
||||||
|
|
||||||
|
" Try to parse .fls file if present, as it is usually more complete. That is,
|
||||||
|
" it contains a generated list of all the packages that are used.
|
||||||
|
for l:line in vimtex#parser#fls(self.fls())
|
||||||
|
let l:package = matchstr(l:line, '^INPUT \zs.\+\ze\.sty$')
|
||||||
|
let l:package = fnamemodify(l:package, ':t')
|
||||||
|
if !empty(l:package)
|
||||||
|
let self.packages[l:package] = {}
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Now parse preamble as well for usepackage and RequirePackage
|
||||||
|
if !has_key(self, 'preamble') | return | endif
|
||||||
|
let l:usepackages = filter(copy(self.preamble), 'v:val =~# ''\v%(usep|RequireP)ackage''')
|
||||||
|
let l:pat = g:vimtex#re#not_comment . g:vimtex#re#not_bslash
|
||||||
|
\ . '\v\\%(usep|RequireP)ackage\s*%(\[[^[\]]*\])?\s*\{\s*\zs%([^{}]+)\ze\s*\}'
|
||||||
|
call map(l:usepackages, 'matchstr(v:val, l:pat)')
|
||||||
|
call map(l:usepackages, 'split(v:val, ''\s*,\s*'')')
|
||||||
|
|
||||||
|
for l:packages in l:usepackages
|
||||||
|
for l:package in l:packages
|
||||||
|
let self.packages[l:package] = {}
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.gather_sources() abort dict " {{{1
|
||||||
|
let self.sources = vimtex#parser#tex#parse_files(
|
||||||
|
\ self.tex, {'root' : self.root})
|
||||||
|
|
||||||
|
call map(self.sources, 'vimtex#paths#relative(v:val, self.root)')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.pprint_items() abort dict " {{{1
|
||||||
|
let l:items = [
|
||||||
|
\ ['name', self.name],
|
||||||
|
\ ['base', self.base],
|
||||||
|
\ ['root', self.root],
|
||||||
|
\ ['tex', self.tex],
|
||||||
|
\ ['out', self.out()],
|
||||||
|
\ ['log', self.log()],
|
||||||
|
\ ['aux', self.aux()],
|
||||||
|
\ ['fls', self.fls()],
|
||||||
|
\ ['main parser', self.main_parser],
|
||||||
|
\]
|
||||||
|
|
||||||
|
if self.tex_program !=# '_'
|
||||||
|
call add(l:items, ['tex program', self.tex_program])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if len(self.sources) >= 2
|
||||||
|
call add(l:items, ['source files', self.sources])
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:items, ['compiler', get(self, 'compiler', {})])
|
||||||
|
call add(l:items, ['viewer', get(self, 'viewer', {})])
|
||||||
|
call add(l:items, ['qf', get(self, 'qf', {})])
|
||||||
|
|
||||||
|
if exists('self.documentclass')
|
||||||
|
call add(l:items, ['document class', self.documentclass])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !empty(self.packages)
|
||||||
|
call add(l:items, ['packages', sort(keys(self.packages))])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return [['vimtex project', l:items]]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.log() abort dict " {{{1
|
||||||
|
return self.ext('log')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.aux() abort dict " {{{1
|
||||||
|
return self.ext('aux')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.fls() abort dict " {{{1
|
||||||
|
return self.ext('fls')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.out(...) abort dict " {{{1
|
||||||
|
return call(self.ext, ['pdf'] + a:000, self)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.ext(ext, ...) abort dict " {{{1
|
||||||
|
" First check build dir (latexmk -output_directory option)
|
||||||
|
if !empty(get(get(self, 'compiler', {}), 'build_dir', ''))
|
||||||
|
let cand = self.compiler.build_dir . '/' . self.name . '.' . a:ext
|
||||||
|
if !vimtex#paths#is_abs(self.compiler.build_dir)
|
||||||
|
let cand = self.root . '/' . cand
|
||||||
|
endif
|
||||||
|
if a:0 > 0 || filereadable(cand)
|
||||||
|
return fnamemodify(cand, ':p')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Next check for file in project root folder
|
||||||
|
let cand = self.root . '/' . self.name . '.' . a:ext
|
||||||
|
if a:0 > 0 || filereadable(cand)
|
||||||
|
return fnamemodify(cand, ':p')
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Finally return empty string if no entry is found
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
function! s:vimtex.getftime() abort dict " {{{1
|
||||||
|
return max(map(copy(self.sources), 'getftime(self.root . ''/'' . v:val)'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" }}}1
|
||||||
|
|
||||||
|
|
||||||
|
" Initialize module
|
||||||
|
let s:vimtex_states = {}
|
||||||
|
let s:vimtex_next_id = 0
|
||||||
|
|
||||||
|
endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user