Newer
Older
invertedlogic / VimFiles / plugged / lldb.nvim / autoload / lldb / layout.vim
function! s:logs_clear()
  if input('Clear logs [y=yes]? ') == 'y'
    if expand('%') == '[lldb]logs'
      set ma
      norm! ggdG
      set noma
    endif
  endif
endfun

" Given the regex, extracts the match from the current line in the buffer.
" If there's no match, the fallback_str is returned.
function! s:matchstr_with_fallback(line, regex, fallback_str)
  let matched = matchstr(a:line, a:regex)
  if matched == ""
    return a:fallback_str
  else
    return matched
  endif
endfun

" Returns [thread_id, frame_id] corresponding to the line in the backtrace buffer.
" If any entry of the pair has no result, empty string will be used.
function! lldb#layout#backtrace_retrieve()
  let frame_idx_pattern = '^\s*\*\= frame #\zs\d\+'
  let thread_idx_pattern = '^\s*\*\= thread #\zs\d\+'
  let frame_id = matchstr(getline('.'), frame_idx_pattern)
  let line_offset = frame_id == '' ? -1 : +frame_id
  let thread_id = matchstr(getline(line('.') - line_offset - 1), thread_idx_pattern)
  if frame_id == '-1'
    let frame_id = ''
  endif
  return [thread_id, frame_id]
endfun

" Returns breakpoint id correnponding to the line in the breakpoint buffer.
" If the result is invalid, empty string will be returned.
function! lldb#layout#breakpoint_retrieve()
  let bp_idx_pattern = '^\s*\zs\d\+\.\=\d*'
  let frame_id = matchstr(getline('.'), bp_idx_pattern)
  return frame_id
endfun

function! lldb#layout#init_buffers()
  let s:buffers = [ 'backtrace', 'breakpoints', 'disassembly',
                  \ 'locals', 'logs', 'registers', 'threads' ]
  let s:buffer_map = {}
  let u_bnr = bufnr('%')
  for bname in s:buffers
    let bnr = bufnr('[lldb]' . bname, 1)
    call setbufvar(bnr, '&ft', 'lldb')
    call setbufvar(bnr, '&bt', 'nofile')
    call setbufvar(bnr, '&swf', 0)
    call setbufvar(bnr, '&ma', 0)
    call setbufvar(bnr, '&bl', 0)
    let s:buffer_map[bname] = bnr
  endfor
  exe 'silent b ' . u_bnr
  return s:buffer_map
endfun

function! lldb#layout#init_window(width, split, bnr)
  exe 'belowright ' . a:width . a:split . '+b' . a:bnr
  set nonu
  set nornu
  if s:buffer_map['logs'] == a:bnr
    nnoremap <buffer> i :call lldb#remote#stdin_prompt()<CR>
    nnoremap <silent> <buffer> <nowait> d :call <SID>logs_clear()<CR>
    nnoremap <silent> <buffer> <nowait> q :drop #<CR>
  elseif s:buffer_map['backtrace'] == a:bnr || s:buffer_map['threads'] == a:bnr
    if s:buffer_map['backtrace'] == a:bnr
      nnoremap <silent> <buffer> a :call lldb#remote#__notify("btswitch")<CR>
      nnoremap <silent> <buffer> t :drop [lldb]threads<CR>
    else
      nnoremap <silent> <buffer> a :drop [lldb]backtrace<CR>
    endif
    nnoremap <silent> <buffer> <CR>
            \ :call lldb#remote#__notify("select_thread_and_frame", lldb#layout#backtrace_retrieve())<CR>
  elseif s:buffer_map['breakpoints'] == a:bnr
    nnoremap <silent> <buffer> <nowait> x
            \ :call lldb#remote#__notify("breakdelete", lldb#layout#breakpoint_retrieve())<CR>
  endif
endfun

function! lldb#layout#setup(mode)
  if a:mode != 'debug'
    return
  endif
  if !exists('s:buffer_map') || empty(s:buffer_map)
    call lldb#layout#init_buffers()
  endif
  0tab sp
  let winw2 = winwidth(0)*2/5
  let winw3 = winwidth(0)*3/5
  let winh2 = winheight(0)*2/3
  call lldb#layout#init_window(winw3, 'vsp', s:buffer_map['threads'])
  call lldb#layout#init_window(winh2, 'sp', s:buffer_map['disassembly'])
  call lldb#layout#init_window(winw3/2, 'vsp', s:buffer_map['registers'])
  2wincmd h
  0tab sp
  call lldb#layout#init_window(winw2, 'vsp', s:buffer_map['backtrace'])
  call lldb#layout#init_window(winh2, 'sp', s:buffer_map['breakpoints'])
  call lldb#layout#init_window(winh2/2, 'sp', s:buffer_map['locals'])
  wincmd h
  call lldb#layout#init_window(winh2/2, 'sp', s:buffer_map['logs'])
  set cole=2 cocu=nc
  wincmd k
endfun

" tears down windows (and tabs) containing debug buffers
function! lldb#layout#teardown(...)
  if !exists('s:buffer_map') || empty(s:buffer_map)
    return
  endif
  let tabcount = tabpagenr('$')
  let bufnrs = values(s:buffer_map)
  for tabnr in range(tabcount, 1, -1)
    let blist = tabpagebuflist(tabnr)
    let bcount = len(blist)
    let bdcount = 0
    exe 'tabn ' . tabnr
    for bnr in blist
      if index(bufnrs, bnr) >= 0
        let bdcount += 1
        exe bufwinnr(bnr) . 'close'
      endif
    endfor
    if bcount < 2*bdcount && bcount > bdcount
      " close tab if majority of windows were lldb buffers
      tabc
    endif
  endfor
endfun

function! lldb#layout#signjump(bufnr, signid)
  if bufwinnr(a:bufnr) < 0
    let wnr = -1
    let ll_bufnrs = values(s:buffer_map)
    for i in range(winnr('$'))
      if index(ll_bufnrs, winbufnr(i+1)) < 0
        let wnr = i+1
        break
      endif
    endfor
    if wnr < 0
      return
    endif
    exe wnr . "wincmd w"
    exe a:bufnr . 'b'
  endif
  exe 'sign jump ' . a:signid . ' buffer=' . a:bufnr
endfun