call plug#begin('~/.local/share/nvim/site/plugged')

" airline
Plug 'https://github.com/bling/vim-airline.git'
Plug 'vim-airline/vim-airline-themes'
" git
Plug 'https://github.com/tpope/vim-fugitive.git'
" Shougos UI-Plugin
Plug 'Shougo/denite.nvim'
" Plug 'roxma/nvim-completion-manager'
" showing function-signatures/doc on completion
Plug 'Shougo/echodoc.vim'
" Tab-Completion
" Plug 'ervandew/supertab'

" vim-sourround
Plug 'https://github.com/tpope/vim-surround.git'
" theme
Plug 'https://github.com/morhetz/gruvbox.git'
Plug 'frankier/neovim-colors-solarized-truecolor-only'

" rainbow-parentethies
Plug 'luochen1990/rainbow'
" fuzzy finder
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'

" git-gutter (little + - and ~ left)
Plug 'https://github.com/airblade/vim-gitgutter.git'

" Tabular
Plug 'https://github.com/godlygeek/tabular.git'

" Multiline-Comments
Plug 'tomtom/tcomment_vim'

" Auto-Formatting
Plug 'Chiel92/vim-autoformat'

" show colors (#abc) with that background-color
Plug 'ap/vim-css-color'

" multiline-stuff
Plug 'terryma/vim-multiple-cursors'

" Icons
Plug 'ryanoasis/vim-devicons'

" Markdown-Support
Plug 'plasticboy/vim-markdown'
Plug 'dhruvasagar/vim-table-mode'
Plug 'suan/vim-instant-markdown'

" Code-Folds
Plug 'tmhedberg/SimpylFold'

" better closing
Plug 'mhinz/vim-sayonara'

" Session-Management
Plug 'xolox/vim-session' | Plug 'xolox/vim-misc'


" todo.txt
Plug 'freitass/todo.txt-vim'

" LSP
Plug 'williamboman/mason.nvim'
Plug 'williamboman/mason-lspconfig.nvim'
Plug 'neovim/nvim-lspconfig'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-path'
Plug 'hrsh7th/cmp-cmdline'
Plug 'hrsh7th/nvim-cmp'
Plug 'onsails/lspkind.nvim'

" For vsnip users.
Plug 'hrsh7th/cmp-vsnip'
Plug 'hrsh7th/vim-vsnip'

call plug#end()

" GENERAL VIM SETUP

" set leader to space
let mapleader= "\<SPACE>"
let maplocalleader= ";"

" autocmd InsertEnter * :set number
" autocmd InsertEnter * :set norelativenumber
" autocmd InsertLeave * :set relativenumber
" autocmd InsertLeave * :set nonumber
set relativenumber
set number

set shiftwidth=2
set tabstop=2

" show cmd - especially leader
set showcmd
" expand tabs with spaces
set expandtab

" Tell Vim which characters to show for expanded TABs,
" trailing whitespace, and end-of-lines. VERY useful!
if &listchars ==# 'eol:$'
  set listchars=tab:>\ ,trail:-,extends:>,precedes:<,nbsp:+
endif
set list                " Show problematic characters.

" Also highlight all tabs and trailing whitespace characters.
highlight ExtraWhitespace ctermbg=darkgreen guibg=darkgreen
match ExtraWhitespace /\s\+$\|\t/

set hlsearch            " Highlight search results.
set ignorecase          " Make searching case insensitive
set smartcase           " ... unless the query has capital letters.
set incsearch           " Incremental search.
set gdefault            " Use 'g' flag by default with :s/foo/bar/.
set magic               " Use 'magic' patterns (extended regular expressions).
set inccommand=nosplit  " Use live-preview of search/replace etc.
set conceallevel=2      " Allow things to be visually opressed (i.e. *foo* be italic)
set mouse=a             " enable mouse
set foldenable          " enable folding

set undofile            " enable undo over sessions
set undodir="$HOME/.VIM_UNDO_FILES" " save in this path
set laststatus=3 " only 1 statusline, not 1 per window
highlight WinSeperator guibg=None

set hidden

let g:loaded_perl_provider = 0

" Remember cursor position between vim sessions
autocmd BufReadPost *
            \ if line("'\"") > 0 && line ("'\"") <= line("$") |
            \   exe "normal! g'\"" |
            \ endif
            " center buffer around cursor when opening files
autocmd BufRead * normal zz

" use <C-J> to Jump to definition instead of <C-]> (default)
nmap <C-J> <C-]>

" c-d to delete line in insert-mode
inoremap <C-D> <esc>ddi

" exit terminal-mode

tnoremap <C-t><C-t> <C-\><C-n>

" FANCY NEOVIM-MAGIC

" setup mason, language-server & nvim-cmp for completion
lua <<EOF

  require("mason").setup()
  require("mason-lspconfig").setup()

  local has_words_before = function()
    unpack = unpack or table.unpack
    local line, col = unpack(vim.api.nvim_win_get_cursor(0))
    return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
  end

  local feedkey = function(key, mode)
    vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true)
  end

  -- Set up nvim-cmp.
  local cmp = require'cmp'
  local lspkind = require'lspkind'

  cmp.setup({
    snippet = {
      -- REQUIRED - you must specify a snippet engine
      expand = function(args)
        vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
        -- require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
        -- require('snippy').expand_snippet(args.body) -- For `snippy` users.
        -- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
      end,
    formatting = {
        format = lspkind.cmp_format(),
      },
    },
    window = {
      -- completion = cmp.config.window.bordered(),
      -- documentation = cmp.config.window.bordered(),
    },
    mapping = cmp.mapping.preset.insert({
      ['<C-b>'] = cmp.mapping.scroll_docs(-4),
      ['<C-f>'] = cmp.mapping.scroll_docs(4),
      ['<C-Space>'] = cmp.mapping.complete(),
      ['<C-e>'] = cmp.mapping.abort(),
      ['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
      ["<Tab>"] = cmp.mapping(function(fallback)
        if cmp.visible() then
          if #cmp.get_entries() == 1 then
            cmp.confirm({ select = true })
          else
            cmp.select_next_item()
          end
        elseif vim.fn["vsnip#available"](1) == 1 then
          feedkey("<Plug>(vsnip-expand-or-jump)", "")
        elseif has_words_before() then
          cmp.complete()
          if #cmp.get_entries() == 1 then
            cmp.confirm({ select = true })
          end
        else
          fallback() -- The fallback function sends a already mapped key. In this case, it's probably `<Tab>`.
        end
      end, { "i", "s" }),

      ["<S-Tab>"] = cmp.mapping(function()
        if cmp.visible() then
          cmp.select_prev_item()
        elseif vim.fn["vsnip#jumpable"](-1) == 1 then
          feedkey("<Plug>(vsnip-jump-prev)", "")
        end
      end, { "i", "s" }),

    }),
    sources = cmp.config.sources({
      { name = 'nvim_lsp' },
      { name = 'vsnip' }, -- For vsnip users.
      -- { name = 'luasnip' }, -- For luasnip users.
      -- { name = 'ultisnips' }, -- For ultisnips users.
      -- { name = 'snippy' }, -- For snippy users.
    }, {
      { name = 'buffer' },
    })
  })

  -- Set configuration for specific filetype.
  cmp.setup.filetype('gitcommit', {
    sources = cmp.config.sources({
      { name = 'git' }, -- You can specify the `git` source if [you were installed it](https://github.com/petertriho/cmp-git).
    }, {
      { name = 'buffer' },
    })
  })

  -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
  cmp.setup.cmdline({ '/', '?' }, {
    mapping = cmp.mapping.preset.cmdline(),
    sources = {
      { name = 'buffer' }
    }
  })

  -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
  cmp.setup.cmdline(':', {
    mapping = cmp.mapping.preset.cmdline(),
    sources = cmp.config.sources({
      { name = 'path' }
    }, {
      { name = 'cmdline' }
    })
  })

  -- Set up lspconfig.
  local capabilities = require('cmp_nvim_lsp').default_capabilities()

  local on_attach = function(client, bufnr)
    local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
    local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

    buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
  end

  require("lspconfig").gopls.setup {
    cmd = {'gopls'},
    -- on_attach = on_attach,
    capabilities = capabilities,
    settings = {
      gopls = {
        experimentalPostfixCompletions = true,
        analyses = {
          unusedparams = true,
          shadow = true,
        },
        staticcheck = true,
      },
    },
    init_options = {
      usePlaceholders = true,
    }
  }
  require("lspconfig").eslint.setup {}
  require("lspconfig").jsonls.setup {}
  require("lspconfig").tsserver.setup {}
  require("lspconfig").ast_grep.setup {}
  require("lspconfig").golangci_lint_ls.setup {}

  function swallow_output(callback, ...) 
    local old_print = print
    print = function(...) end

    pcall(callback, arg)

    print = old_print
  end

  -- See `:help vim.diagnostic.*` for documentation on any of the below functions
  vim.keymap.set('n', '<space>e', vim.diagnostic.open_float)
  vim.keymap.set('n', '[d', vim.diagnostic.goto_prev)
  vim.keymap.set('n', ']d', vim.diagnostic.goto_next)
  vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist)

  -- Use LspAttach autocommand to only map the following keys
  -- after the language server attaches to the current buffer
  vim.api.nvim_create_autocmd('LspAttach', {
    group = vim.api.nvim_create_augroup('UserLspConfig', {}),
    callback = function(ev)

      -- Buffer local mappings.
      -- See `:help vim.lsp.*` for documentation on any of the below functions
      local opts = { buffer = ev.buf }
      vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts)
      vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
      vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
      vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
      vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, opts)
      vim.keymap.set('n', '<space>wa', vim.lsp.buf.add_workspace_folder, opts)
      vim.keymap.set('n', '<space>wr', vim.lsp.buf.remove_workspace_folder, opts)
      vim.keymap.set('n', '<space>wl', function()
        print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
      end, opts)
      vim.keymap.set('n', '<space>D', vim.lsp.buf.type_definition, opts)
      vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename, opts)
      vim.keymap.set({ 'n', 'v' }, '<space>ca', vim.lsp.buf.code_action, opts)
      vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
      vim.keymap.set('v', '<space>f', function()
        vim.lsp.buf.format { async = true }
      end, opts)
      vim.api.nvim_create_autocmd('BufWrite', {
        callback = function(ev)
          vim.lsp.buf.format { async = false }
        end
      })
    end,
  })
EOF

"" KEY-BINDINGS


noremap <leader>TM :TableModeToggle<CR>

" multi-cursor
let g:multi_cursor_next_key='<C-n>'
let g:multi_cursor_prev_key='<C-p>'
let g:multi_cursor_skip_key='<C-x>'
let g:multi_cursor_quit_key='<Esc>'

" Align blocks of text and keep them selected
vmap < <gv
vmap > >gv
nnoremap <leader>d "_d
vnoremap <leader>d "_d

" toggle comments
vnoremap <leader>/ :TComment<cr>

" Open file menu
nnoremap <Leader>o :Files<CR>
" Open buffer menu
nnoremap <Leader>b :Buffers<CR>
" Open most recently used files
nnoremap <Leader>f :GFiles<CR>
" Open Tag-Search
nnoremap <Leader>t :Tags<CR>

" Expand patterns in Haskell
"nnoremap <Leader>hc :GhcModSplitFunCase<CR>
" Expand function signatures in Haskell
"nnoremap <Leader>hs :GhcModSigCodegen<CR>
" Get Type-Info under Cursor
"nnoremap <Leader>ht :GhcModType<CR>

" " Copy to clipboard
vnoremap  <leader>y  "+y
nnoremap  <leader>Y  "+yg_
nnoremap  <leader>y  "+y
nnoremap  <leader>yy  "+yy

" " Paste from clipboard
nnoremap <leader>p "+p
nnoremap <leader>P "+P
vnoremap <leader>p "+p
vnoremap <leader>P "+P

" Clear stuff
nnoremap <Leader><Leader> :nohlsearch<CR>:cclose<CR>

" Clojure-Bindings
" Enable vim-iced's default key mapping
" This is recommended for newbies
let g:iced_enable_default_key_mappings = v:true
let g:sexp_enable_insert_mode_mappings = 0      " stop inserting brackets
let g:iced_enable_clj_kondo_analysis = v:true   " kondo analysis
let g:iced_enable_clj_kondo_local_analysis = v:true " also analyse local.
let g:iced_enable_auto_document = 'any'         " automatically open documentation

" THEME-RELATED STUFF

syntax enable
filetype plugin on
" enable true color
set termguicolors
" enable italics, load colorscheme
let g:gruvbox_italic=1
set background=dark
colorscheme gruvbox

let g:rainbow_active = 1
let &colorcolumn="80,".join(range(120,200),",")

" spell checking for markdown
autocmd BufRead,BufNewFile *.md setlocal spell complete+=kspell textwidth=80
autocmd BufRead,BufNewFile *.markdown setlocal spell complete+=kspell textwidth=80
autocmd BufRead,BufNewFile *.md hi SpellBad guibg=#582828 gui=none
autocmd BufRead,BufNewFile *.markdown hi SpellBad guibg=#582828 gui=none
" autocmd FileType markdown nnoremap <Leader>t :Toc<CR>

" set languages to english and german
set spelllang=de_de,en_us

let g:vim_markdown_toc_autofit = 0
let g:vim_markdown_emphasis_multiline = 1
let g:vim_markdown_math = 1
let g:vim_markdown_new_list_item_indent = 2
let g:vim_markdown_folding_level = 0

" disable instant-markdown-preview
let g:instant_markdown_autostart = 0
au FileType markdown setl shell=bash

let g:haskell_enable_quantification   = 1 " enable highlighting of forall
let g:haskell_enable_recursivedo      = 1 " enable highlighting of mdo and rec
let g:haskell_enable_arrowsyntax      = 1 " enable highlighting of proc
let g:haskell_enable_pattern_synonyms = 1 " enable highlighting of pattern
let g:haskell_enable_typeroles        = 1 " enable highlighting of type roles
let g:haskell_enable_static_pointers  = 1 " enable highlighting of static
let g:haskell_indent_if               = 3
let g:haskell_indent_case             = 2
let g:haskell_indent_let              = 4
let g:haskell_indent_where            = 6
let g:haskell_indent_do               = 3
let g:haskell_indent_in               = 1
let g:haskell_indent_guard            = 2


" SNIPPETS

" " Emmet customization
" " Enable Emmet in all modes
" " Remapping <C-y>, just doesn't cut it.
"   function! s:expand_html_tab()
" " try to determine if we're within quotes or tags.
" " if so, assume we're in an emmet fill area.
"    let line = getline('.')
"    if col('.') < len(line)
"      let line = matchstr(line, '[">][^<"]*\%'.col('.').'c[^>"]*[<"]')
"      if len(line) >= 2
"         return "\<C-n>"
"      endif
"    endif
" " expand anything emmet thinks is expandable.
"   if emmet#isExpandable()
"     return "\<C-y>,"
"   endif
" " return a regular tab character
"   return "\<tab>"
"   endfunction
"   autocmd FileType html,markdown imap <buffer><expr><tab> <sid>expand_html_tab()
"   let g:user_emmet_mode='a'
"   let g:user_emmet_complete_tag = 1
"   let g:user_emmet_install_global = 0
"   autocmd FileType html,css EmmetInstall

" AIRLINE
let g:airline#extensions#tabline#ignore_bufadd_pat = 'gundo|undotree|vimfiler|tagbar|netrw|startify|!'
let g:airline#extensions#tabline#enabled = 1
set hidden
let g:airline#extensions#tabline#fnamemod = ':t'
let g:airline#extensions#tabline#show_tab_nr = 1
let g:airline_powerline_fonts = 1
let g:airline_theme='understated'
" let g:airline_theme='base16_solarized'
cnoreabbrev <expr> x getcmdtype() == ":" && getcmdline() == 'x' ? 'Sayonara' : 'x'
nmap <leader>tt :term<cr>
nmap <leader>, :bnext<CR>
nmap <leader>. :bprevious<CR>
let g:airline#extensions#tabline#buffer_idx_mode = 1
nmap <leader>1 <Plug>AirlineSelectTab1
nmap <leader>2 <Plug>AirlineSelectTab2
nmap <leader>3 <Plug>AirlineSelectTab3
nmap <leader>4 <Plug>AirlineSelectTab4
nmap <leader>5 <Plug>AirlineSelectTab5
nmap <leader>6 <Plug>AirlineSelectTab6
nmap <leader>7 <Plug>AirlineSelectTab7
nmap <leader>8 <Plug>AirlineSelectTab8
nmap <leader>9 <Plug>AirlineSelectTab9
set guifont=Sauce\ Code\ Pro\ Nerd\ Font\ Complete:h13

" TABULARIZE

nmap <leader>t: :Tabularize /:: /l1c0l0<CR>
nmap <leader>t= :Tabularize /= /l1c0l0<CR>
nmap <leader>tp :Tabularize /\| /l1c0l0<CR>
nmap <leader>t, :Tabularize /, /l1c0l0<CR>

" Table mode

let g:table_mode_corner_corner="+"
let g:table_mode_header_fillchar="="

" Move between windows
nnoremap <M-Left>  <C-W><C-H>
nnoremap <M-Down>  <C-W><C-J>
nnoremap <M-Up>    <C-W><C-K>
nnoremap <M-Right> <C-W><C-L>
" Move between tabs
nnoremap <M-Home>  :bNext<CR>
nnoremap <M-End>   :bnext<CR>

" Session-Options

let g:session_autoload='yes'
let g:session_autosave='yes'

" Change background quickly
nmap <F9> :let &background = ( &background == "dark" ? "light" : "dark" )<CR>

" BUGFIX UNTIL #6997 gets meged.
set guicursor=
