scriptencoding utf-8

" ------------------------------------------------------------------------
" Settings initialization
" ------------------------------------------------------------------------
let s:deprecations = {
    \ 'get_definition_command':     'goto_definitions_command',
    \ 'pydoc':                      'documentation_command',
    \ 'related_names_command':      'usages_command',
    \ 'autocompletion_command':     'completions_command',
    \ 'show_function_definition':   'show_call_signatures',
\ }

let s:default_settings = {
    \ 'use_tabs_not_buffers': 0,
    \ 'use_splits_not_buffers': 1,
    \ 'auto_initialization': 1,
    \ 'auto_vim_configuration': 1,
    \ 'goto_command': "'<leader>d'",
    \ 'goto_assignments_command': "'<leader>g'",
    \ 'goto_definitions_command': "''",
    \ 'completions_command': "'<C-Space>'",
    \ 'call_signatures_command': "'<leader>n'",
    \ 'usages_command': "'<leader>n'",
    \ 'rename_command': "'<leader>r'",
    \ 'popup_on_dot': 1,
    \ 'documentation_command': "'K'",
    \ 'show_call_signatures': 1,
    \ 'show_call_signatures_delay': 500,
    \ 'call_signature_escape': "'=`='",
    \ 'auto_close_doc': 1,
    \ 'max_doc_height': 30,
    \ 'popup_select_first': 1,
    \ 'quickfix_window_height': 10,
    \ 'completions_enabled': 1,
    \ 'force_py_version': "'auto'",
    \ 'smart_auto_mappings': 1,
    \ 'use_tag_stack': 1
\ }

for [s:key, s:val] in items(s:deprecations)
    if exists('g:jedi#'.s:key)
        echom "'g:jedi#".s:key."' is deprecated. Please use 'g:jedi#".s:val."' instead. Sorry for the inconvenience."
        exe 'let g:jedi#'.s:val.' = g:jedi#'.s:key
    endif
endfor

for [s:key, s:val] in items(s:default_settings)
    if !exists('g:jedi#'.s:key)
        exe 'let g:jedi#'.s:key.' = '.s:val
    endif
endfor


" ------------------------------------------------------------------------
" Python initialization
" ------------------------------------------------------------------------
let s:script_path = fnameescape(expand('<sfile>:p:h:h'))

function! s:init_python()
    if g:jedi#force_py_version != 'auto'
        " Always use the user supplied version.
        try
            return jedi#force_py_version(g:jedi#force_py_version)
        catch
            throw "Could not setup g:jedi#force_py_version: ".v:exception
        endtry
    endif

    " Handle "auto" version.
    if has('nvim') || (has('python') && has('python3'))
        " Neovim usually has both python providers. Skipping the `has` check
        " avoids starting both of them.

        " Get default python version from interpreter in $PATH.
        let s:def_py = system('python -c '.shellescape('import sys; sys.stdout.write(str(sys.version_info[0]))'))
        if v:shell_error != 0 || !len(s:def_py)
            if !exists("g:jedi#squelch_py_warning")
                echohl WarningMsg
                echom "Warning: jedi-vim failed to get Python version from sys.version_info: " . s:def_py
                echom "Falling back to version 2."
                echohl None
            endif
            let s:def_py = 2
        elseif &verbose
            echom "jedi-vim: auto-detected Python: ".s:def_py
        endif

        " Make sure that the auto-detected version is available in Vim.
        if !has('nvim') || has('python'.(s:def_py == 2 ? '' : s:def_py))
            return jedi#force_py_version(s:def_py)
        endif

        " Add a warning in case the auto-detected version is not available,
        " usually because of a missing neovim module in a VIRTUAL_ENV.
        if has('nvim')
            echohl WarningMsg
            echom "jedi-vim: the detected Python version (".s:def_py.")"
                        \ "is not functional."
                        \ "Is the 'neovim' module installed?"
                        \ "While jedi-vim will work, it might not use the"
                        \ "expected Python path."
            echohl None
        endif
    endif

    if has('python')
        call jedi#setup_py_version(2)
    elseif has('python3')
        call jedi#setup_py_version(3)
    else
        throw "jedi-vim requires Vim with support for Python 2 or 3."
    endif
    return 1
endfunction


function! jedi#reinit_python()
    unlet! s:_init_python
    call jedi#init_python()
endfunction


function! jedi#init_python()
    if !exists('s:_init_python')
        try
            let s:_init_python = s:init_python()
        catch
            if !exists("g:jedi#squelch_py_warning")
                echohl WarningMsg
                echom "Error: jedi-vim failed to initialize Python: ".v:exception." (in ".v:throwpoint.")"
                echohl None
            endif
            let s:_init_python = 0
        endtry
    endif
    return s:_init_python
endfunction


let s:python_version = 'null'
function! jedi#setup_py_version(py_version)
    if a:py_version == 2
        let cmd_init = 'pyfile'
        let cmd_exec = 'python'
        let s:python_version = 2
    elseif a:py_version == 3
        let cmd_init = 'py3file'
        let cmd_exec = 'python3'
        let s:python_version = 3
    else
        throw "jedi#setup_py_version: invalid py_version: ".a:py_version
    endif

    try
        execute cmd_init.' '.s:script_path.'/initialize.py'
        execute 'command! -nargs=1 PythonJedi '.cmd_exec.' <args>'
        return 1
    catch
        throw "jedi#setup_py_version: ".v:exception
    endtry
endfunction


function! jedi#debug_info()
    echom "Using Python version:" s:python_version
endfunction


function! jedi#force_py_version(py_version)
    let g:jedi#force_py_version = a:py_version
    return jedi#setup_py_version(a:py_version)
endfunction


function! jedi#force_py_version_switch()
    if g:jedi#force_py_version == 2
        call jedi#force_py_version(3)
    elseif g:jedi#force_py_version == 3
        call jedi#force_py_version(2)
    else
        throw "Don't know how to switch from ".g:jedi#force_py_version."!"
    endif
endfunction


" Helper function instead of `python vim.eval()`, and `.command()` because
" these also return error definitions.
function! jedi#_vim_exceptions(str, is_eval)
    let l:result = {}
    try
        if a:is_eval
            let l:result.result = eval(a:str)
        else
            execute a:str
            let l:result.result = ''
        endif
    catch
        let l:result.exception = v:exception
        let l:result.throwpoint = v:throwpoint
    endtry
    return l:result
endfunction


if !jedi#init_python()
    " Do not define any functions when Python initialization failed.
    finish
endif


" ------------------------------------------------------------------------
" functions that call python code
" ------------------------------------------------------------------------
function! jedi#goto()
    PythonJedi jedi_vim.goto(mode="goto")
endfunction

function! jedi#goto_assignments()
    PythonJedi jedi_vim.goto(mode="assignment")
endfunction

function! jedi#goto_definitions()
    PythonJedi jedi_vim.goto(mode="definition")
endfunction

function! jedi#usages()
    PythonJedi jedi_vim.goto(mode="related_name")
endfunction

function! jedi#rename(...)
    PythonJedi jedi_vim.rename()
endfunction

function! jedi#rename_visual(...)
    PythonJedi jedi_vim.rename_visual()
endfunction

function! jedi#completions(findstart, base)
    PythonJedi jedi_vim.completions()
endfunction

function! jedi#enable_speed_debugging()
    PythonJedi jedi_vim.jedi.set_debug_function(jedi_vim.print_to_stdout, speed=True, warnings=False, notices=False)
endfunction

function! jedi#enable_debugging()
    PythonJedi jedi_vim.jedi.set_debug_function(jedi_vim.print_to_stdout)
endfunction

function! jedi#disable_debugging()
    PythonJedi jedi_vim.jedi.set_debug_function(None)
endfunction

function! jedi#py_import(args)
    PythonJedi jedi_vim.py_import()
endfun

function! jedi#py_import_completions(argl, cmdl, pos)
    PythonJedi jedi_vim.py_import_completions()
endfun


" ------------------------------------------------------------------------
" show_documentation
" ------------------------------------------------------------------------
function! jedi#show_documentation()
    PythonJedi if jedi_vim.show_documentation() is None: vim.command('return')

    let bn = bufnr("__doc__")
    if bn > 0
        let wi=index(tabpagebuflist(tabpagenr()), bn)
        if wi >= 0
            " If the __doc__ buffer is open in the current tab, jump to it
            silent execute (wi+1).'wincmd w'
        else
            silent execute "sbuffer ".bn
        endif
    else
        split '__doc__'
    endif

    setlocal modifiable
    setlocal noswapfile
    setlocal buftype=nofile
    silent normal! ggdG
    silent $put=l:doc
    silent normal! 1Gdd
    setlocal nomodifiable
    setlocal nomodified
    setlocal filetype=rst

    if l:doc_lines > g:jedi#max_doc_height " max lines for plugin
        let l:doc_lines = g:jedi#max_doc_height
    endif
    execute "resize ".l:doc_lines

    " quit comands
    nnoremap <buffer> q ZQ
    execute "nnoremap <buffer> ".g:jedi#documentation_command." ZQ"

    " highlight python code within rst
    unlet! b:current_syntax
    syn include @rstPythonScript syntax/python.vim
    " 4 spaces
    syn region rstPythonRegion start=/^\v {4}/ end=/\v^( {4}|\n)@!/ contains=@rstPythonScript
    " >>> python code -> (doctests)
    syn region rstPythonRegion matchgroup=pythonDoctest start=/^>>>\s*/ end=/\n/ contains=@rstPythonScript
    let b:current_syntax = "rst"
endfunction

" ------------------------------------------------------------------------
" helper functions
" ------------------------------------------------------------------------

function! jedi#add_goto_window(len)
    set lazyredraw
    cclose
    let height = min([a:len, g:jedi#quickfix_window_height])
    execute 'belowright copen '.height
    set nolazyredraw
    if g:jedi#use_tabs_not_buffers == 1
        noremap <buffer> <CR> :call jedi#goto_window_on_enter()<CR>
    endif
    au WinLeave <buffer> q  " automatically leave, if an option is chosen
    redraw!
endfunction


function! jedi#goto_window_on_enter()
    let l:list = getqflist()
    let l:data = l:list[line('.') - 1]
    if l:data.bufnr
        " close goto_window buffer
        normal ZQ
        PythonJedi jedi_vim.new_buffer(vim.eval('bufname(l:data.bufnr)'))
        call cursor(l:data.lnum, l:data.col)
    else
        echohl WarningMsg | echo "Builtin module cannot be opened." | echohl None
    endif
endfunction


function! s:syn_stack()
    if !exists("*synstack")
        return []
    endif
    return map(synstack(line('.'), col('.') - 1), 'synIDattr(v:val, "name")')
endfunc


function! jedi#do_popup_on_dot_in_highlight()
    let highlight_groups = s:syn_stack()
    for a in highlight_groups
        if a == 'pythonDoctest'
            return 1
        endif
    endfor

    for a in highlight_groups
        for b in ['pythonString', 'pythonComment', 'pythonNumber']
            if a == b
                return 0 
            endif
        endfor
    endfor
    return 1
endfunc


let s:show_call_signatures_last = [0, 0, '']
function! jedi#show_call_signatures()
    let [line, col] = [line('.'), col('.')]
    let curline = getline(line)
    let reload_signatures = 1

    " Caching.  On the same line only.
    if line == s:show_call_signatures_last[0]
        " Check if the number of commas and parenthesis before or after the
        " cursor has not changed since the last call, which means that the
        " argument position was not changed and we can skip repainting.
        let prevcol = s:show_call_signatures_last[1]
        let prevline = s:show_call_signatures_last[2]
        if substitute(curline[:col-2], '[^,()]', '', 'g')
                    \ == substitute(prevline[:prevcol-2], '[^,()]', '', 'g')
                    \ && substitute(curline[(col-2):], '[^,()]', '', 'g')
                    \ == substitute(prevline[(prevcol-2):], '[^,()]', '', 'g')
            let reload_signatures = 0
        endif
    endif
    let s:show_call_signatures_last = [line, col, curline]

    if reload_signatures
        PythonJedi jedi_vim.show_call_signatures()
    endif
endfunction


function! jedi#clear_call_signatures()
    let s:show_call_signatures_last = [0, 0, '']
    PythonJedi jedi_vim.clear_call_signatures()
endfunction


function! jedi#configure_call_signatures()
    augroup jedi_call_signatures
    autocmd! * <buffer>
    if g:jedi#show_call_signatures == 2  " Command line call signatures
        autocmd InsertEnter <buffer> let g:jedi#first_col = s:save_first_col()
    endif
    autocmd InsertEnter <buffer> let s:show_call_signatures_last = [0, 0, '']
    autocmd InsertLeave <buffer> call jedi#clear_call_signatures()
    if g:jedi#show_call_signatures_delay > 0
        autocmd InsertEnter <buffer> let b:_jedi_orig_updatetime = &updatetime
                    \ | let &updatetime = g:jedi#show_call_signatures_delay
        autocmd InsertLeave <buffer> if exists('b:_jedi_orig_updatetime')
                    \ |   let &updatetime = b:_jedi_orig_updatetime
                    \ |   unlet b:_jedi_orig_updatetime
                    \ | endif
        autocmd CursorHoldI <buffer> call jedi#show_call_signatures()
    else
        autocmd CursorMovedI <buffer> call jedi#show_call_signatures()
    endif
    augroup END
endfunction


" Determine where the current window is on the screen for displaying call
" signatures in the correct column.
function! s:save_first_col()
    if bufname('%') ==# '[Command Line]' || winnr('$') == 1
        return 0
    endif

    let startwin = winnr()
    let winwidth = winwidth(0)
    if winwidth == &columns
        return 0
    elseif winnr('$') == 2
        return startwin == 1 ? 0 : (winwidth(1) + 1)
    elseif winnr('$') == 3
        if startwin == 1
            return 0
        endif
        let ww1 = winwidth(1)
        let ww2 = winwidth(2)
        let ww3 = winwidth(3)
        if ww1 + ww2 + ww3 + 2 == &columns
            if startwin == 2
                return ww1 + 1
            else
                return ww1 + ww2 + 2
            endif
        elseif startwin == 2
            if ww2 + ww3 + 1 == &columns
                return 0
            else
                return ww1 + 1
            endif
        else " startwin == 3
            if ww2 + ww3 + 1 == &columns
                return ww2 + 1
            else
                return ww1 + 1
            endif
        endif
    endif
    return 0
endfunction


function! jedi#complete_string(is_popup_on_dot)

    if a:is_popup_on_dot && !(g:jedi#popup_on_dot && jedi#do_popup_on_dot_in_highlight())
        return ''

    endif
    if pumvisible() && !a:is_popup_on_dot
        return "\<C-n>"
    else
        return "\<C-x>\<C-o>\<C-r>=jedi#complete_opened(".a:is_popup_on_dot.")\<CR>"
    endif
endfunction


function! jedi#complete_opened(is_popup_on_dot)
    if pumvisible()
        " Only go down if it is visible, user-enabled and the longest
        " option is set.
        if g:jedi#popup_select_first && stridx(&completeopt, 'longest') > -1
            return "\<Down>"
        endif
        if a:is_popup_on_dot
            if &completeopt !~ '\(noinsert\|noselect\)'
                " Prevent completion of the first entry with dot completion.
                return "\<C-p>"
            endif
        endif
    endif
    return ""
endfunction


function! jedi#smart_auto_mappings()
    " Auto put import statement after from module.name<space> and complete
    if search('^\s*from\s\+[A-Za-z0-9._]\{1,50}\%#\s*$', 'bcn', line('.'))
        " Enter character and start completion.
        return "\<space>import \<C-x>\<C-o>\<C-r>=jedi#complete_opened(1)\<CR>"
    endif
    return "\<space>"
endfunction


"PythonJedi jedi_vim.jedi.set_debug_function(jedi_vim.print_to_stdout, speed=True, warnings=False, notices=False)
"PythonJedi jedi_vim.jedi.set_debug_function(jedi_vim.print_to_stdout)

" vim: set et ts=4:
