diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/VimFiles/colors/colors.vim b/VimFiles/colors/colors.vim new file mode 100755 index 0000000..e9e1cb4 --- /dev/null +++ b/VimFiles/colors/colors.vim @@ -0,0 +1,236 @@ +" office-light, a vim colourscheme by nightsense +" +" generated with a theme template adapted from +" base16-vim (https://github.com/chriskempson/base16-vim) +" by Chris Kempson (http://chriskempson.com) + + +"=== SET COLOUR VARIABLES ===================================================== + +" GUI colours +let s:g0 = 'fffff0' +let s:g1 = 'f0f0e1' +let s:g2 = 'b5b5aa' +let s:g3 = '9e9e95' +let s:g4 = '8a8a81' +let s:g5 = '75756e' +let s:g6 = '3b3b37' +let s:g7 = '2b2b29' +let s:g8 = 'f55050' +let s:g9 = 'e06a26' +let s:gA = 'd4ac35' +let s:gB = '219e21' +let s:gC = '1b9e9e' +let s:gD = '468dd4' +let s:gE = 'a26fbf' +let s:gF = 'd46a84' + +" terminal colours +let s:t0 = '10' +let s:t3 = '08' +let s:t5 = '07' +let s:t7 = '15' +let s:t8 = '01' +let s:tA = '03' +let s:tB = '02' +let s:tC = '06' +let s:tD = '04' +let s:tE = '05' +let s:t1 = '10' +let s:t2 = '11' +let s:t4 = '12' +let s:t6 = '13' +let s:t9 = '09' +let s:tF = '14' + +" neovim colours +if has('nvim') + let g:terminal_color_0 = '#fffff0' + let g:terminal_color_1 = '#f55050' + let g:terminal_color_2 = '#219e21' + let g:terminal_color_3 = '#d4ac35' + let g:terminal_color_4 = '#468dd4' + let g:terminal_color_5 = '#a26fbf' + let g:terminal_color_6 = '#1b9e9e' + let g:terminal_color_7 = '#75756e' + let g:terminal_color_8 = '#9e9e95' + let g:terminal_color_9 = '#e06a26' + let g:terminal_color_10 = '#f0f0e1' + let g:terminal_color_11 = '#b5b5aa' + let g:terminal_color_12 = '#8a8a81' + let g:terminal_color_13 = '#3b3b37' + let g:terminal_color_14 = '#d46a84' + let g:terminal_color_15 = '#2b2b29' +endif + + +"=== OTHER PREPARATION ======================================================== + +" clear old theme +hi clear +syntax reset + +" set new theme +set background=light +augroup NightsenseThemeSet + autocmd! + autocmd CursorMoved * execute 'if !exists("colors_name") | + \ colorscheme office-light | endif' +augroup END +let colors_name = 'office-light' + +" highlighting function +fun! h(x, gf, gb, cf, cb, a, s) + if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif + if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif + if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif + if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif + if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif + if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif +endfun + + +"=== BASIC HIGHLIGHTING ======================================================= + +" cursor + status line + selected tab +cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) + +" line numbers +cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" basic text +cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) +cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) +cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) +cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) +cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) + +" commented-out text +cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) + +" highlighted background +cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) + +" muted text on highlighted background +cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" strongly highlighted background +cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) + +" selected menu item +cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) +cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) + +" solid lines +cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) +cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) +cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) + + +"=== ALERT/SYNTAX HIGHLIGHTING ================================================ + +" RED for warning elements +cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) +cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) +cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) +cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) + +" ORANGE for preliminary elements +cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) +cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) +cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) + +" YELLOW for highlighted elements +cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) + +" GREEN for action elements +cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) +cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) + +" TEAL for object types +cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) +cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) + +" BLUE for constants +cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) + +" PURPLE for special text +cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) +cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) + +" PINK for object names +cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) +cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) + + +"=== OPTIONS ================================================================== + +" disable highlighted CursorLineNr +if exists('g:office_light_CursorLineNr') +if g:office_light_CursorLineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +endif +endif + +" disable LineNr background altogether +if exists('g:office_light_LineNr') +if g:office_light_LineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +endif +endif diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/VimFiles/colors/colors.vim b/VimFiles/colors/colors.vim new file mode 100755 index 0000000..e9e1cb4 --- /dev/null +++ b/VimFiles/colors/colors.vim @@ -0,0 +1,236 @@ +" office-light, a vim colourscheme by nightsense +" +" generated with a theme template adapted from +" base16-vim (https://github.com/chriskempson/base16-vim) +" by Chris Kempson (http://chriskempson.com) + + +"=== SET COLOUR VARIABLES ===================================================== + +" GUI colours +let s:g0 = 'fffff0' +let s:g1 = 'f0f0e1' +let s:g2 = 'b5b5aa' +let s:g3 = '9e9e95' +let s:g4 = '8a8a81' +let s:g5 = '75756e' +let s:g6 = '3b3b37' +let s:g7 = '2b2b29' +let s:g8 = 'f55050' +let s:g9 = 'e06a26' +let s:gA = 'd4ac35' +let s:gB = '219e21' +let s:gC = '1b9e9e' +let s:gD = '468dd4' +let s:gE = 'a26fbf' +let s:gF = 'd46a84' + +" terminal colours +let s:t0 = '10' +let s:t3 = '08' +let s:t5 = '07' +let s:t7 = '15' +let s:t8 = '01' +let s:tA = '03' +let s:tB = '02' +let s:tC = '06' +let s:tD = '04' +let s:tE = '05' +let s:t1 = '10' +let s:t2 = '11' +let s:t4 = '12' +let s:t6 = '13' +let s:t9 = '09' +let s:tF = '14' + +" neovim colours +if has('nvim') + let g:terminal_color_0 = '#fffff0' + let g:terminal_color_1 = '#f55050' + let g:terminal_color_2 = '#219e21' + let g:terminal_color_3 = '#d4ac35' + let g:terminal_color_4 = '#468dd4' + let g:terminal_color_5 = '#a26fbf' + let g:terminal_color_6 = '#1b9e9e' + let g:terminal_color_7 = '#75756e' + let g:terminal_color_8 = '#9e9e95' + let g:terminal_color_9 = '#e06a26' + let g:terminal_color_10 = '#f0f0e1' + let g:terminal_color_11 = '#b5b5aa' + let g:terminal_color_12 = '#8a8a81' + let g:terminal_color_13 = '#3b3b37' + let g:terminal_color_14 = '#d46a84' + let g:terminal_color_15 = '#2b2b29' +endif + + +"=== OTHER PREPARATION ======================================================== + +" clear old theme +hi clear +syntax reset + +" set new theme +set background=light +augroup NightsenseThemeSet + autocmd! + autocmd CursorMoved * execute 'if !exists("colors_name") | + \ colorscheme office-light | endif' +augroup END +let colors_name = 'office-light' + +" highlighting function +fun! h(x, gf, gb, cf, cb, a, s) + if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif + if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif + if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif + if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif + if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif + if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif +endfun + + +"=== BASIC HIGHLIGHTING ======================================================= + +" cursor + status line + selected tab +cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) + +" line numbers +cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" basic text +cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) +cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) +cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) +cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) +cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) + +" commented-out text +cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) + +" highlighted background +cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) + +" muted text on highlighted background +cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" strongly highlighted background +cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) + +" selected menu item +cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) +cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) + +" solid lines +cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) +cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) +cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) + + +"=== ALERT/SYNTAX HIGHLIGHTING ================================================ + +" RED for warning elements +cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) +cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) +cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) +cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) + +" ORANGE for preliminary elements +cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) +cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) +cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) + +" YELLOW for highlighted elements +cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) + +" GREEN for action elements +cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) +cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) + +" TEAL for object types +cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) +cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) + +" BLUE for constants +cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) + +" PURPLE for special text +cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) +cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) + +" PINK for object names +cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) +cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) + + +"=== OPTIONS ================================================================== + +" disable highlighted CursorLineNr +if exists('g:office_light_CursorLineNr') +if g:office_light_CursorLineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +endif +endif + +" disable LineNr background altogether +if exists('g:office_light_LineNr') +if g:office_light_LineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +endif +endif diff --git a/VimFiles/colors/obsidian.vim b/VimFiles/colors/obsidian.vim new file mode 100755 index 0000000..a9d9dfa --- /dev/null +++ b/VimFiles/colors/obsidian.vim @@ -0,0 +1,23 @@ +set background=dark +hi clear + +if exists("syntax_on") + syntax reset +endif + +let g:colors_name="obsidian" + +hi PreProc ctermfg=5 cterm=bold +hi cDefine ctermfg=5 cterm=bold +hi cDefined ctermfg=4 cterm=bold +" hi Function ctermfg=1 cterm=bold +hi def cCustomFunc gui=bold guifg=#FF00FF ctermfg=4 cterm=bold +hi StorageClass ctermfg=5 cterm=bold +" hi Type ctermfg=7 cterm=bold +" hi Type ctermfg=5 cterm=bold +hi Type ctermfg=5 cterm=bold +hi cIncluded ctermfg=0 cterm=bold +hi Comment ctermfg=1 +hi Constant ctermfg=1 cterm=bold + + diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/VimFiles/colors/colors.vim b/VimFiles/colors/colors.vim new file mode 100755 index 0000000..e9e1cb4 --- /dev/null +++ b/VimFiles/colors/colors.vim @@ -0,0 +1,236 @@ +" office-light, a vim colourscheme by nightsense +" +" generated with a theme template adapted from +" base16-vim (https://github.com/chriskempson/base16-vim) +" by Chris Kempson (http://chriskempson.com) + + +"=== SET COLOUR VARIABLES ===================================================== + +" GUI colours +let s:g0 = 'fffff0' +let s:g1 = 'f0f0e1' +let s:g2 = 'b5b5aa' +let s:g3 = '9e9e95' +let s:g4 = '8a8a81' +let s:g5 = '75756e' +let s:g6 = '3b3b37' +let s:g7 = '2b2b29' +let s:g8 = 'f55050' +let s:g9 = 'e06a26' +let s:gA = 'd4ac35' +let s:gB = '219e21' +let s:gC = '1b9e9e' +let s:gD = '468dd4' +let s:gE = 'a26fbf' +let s:gF = 'd46a84' + +" terminal colours +let s:t0 = '10' +let s:t3 = '08' +let s:t5 = '07' +let s:t7 = '15' +let s:t8 = '01' +let s:tA = '03' +let s:tB = '02' +let s:tC = '06' +let s:tD = '04' +let s:tE = '05' +let s:t1 = '10' +let s:t2 = '11' +let s:t4 = '12' +let s:t6 = '13' +let s:t9 = '09' +let s:tF = '14' + +" neovim colours +if has('nvim') + let g:terminal_color_0 = '#fffff0' + let g:terminal_color_1 = '#f55050' + let g:terminal_color_2 = '#219e21' + let g:terminal_color_3 = '#d4ac35' + let g:terminal_color_4 = '#468dd4' + let g:terminal_color_5 = '#a26fbf' + let g:terminal_color_6 = '#1b9e9e' + let g:terminal_color_7 = '#75756e' + let g:terminal_color_8 = '#9e9e95' + let g:terminal_color_9 = '#e06a26' + let g:terminal_color_10 = '#f0f0e1' + let g:terminal_color_11 = '#b5b5aa' + let g:terminal_color_12 = '#8a8a81' + let g:terminal_color_13 = '#3b3b37' + let g:terminal_color_14 = '#d46a84' + let g:terminal_color_15 = '#2b2b29' +endif + + +"=== OTHER PREPARATION ======================================================== + +" clear old theme +hi clear +syntax reset + +" set new theme +set background=light +augroup NightsenseThemeSet + autocmd! + autocmd CursorMoved * execute 'if !exists("colors_name") | + \ colorscheme office-light | endif' +augroup END +let colors_name = 'office-light' + +" highlighting function +fun! h(x, gf, gb, cf, cb, a, s) + if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif + if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif + if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif + if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif + if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif + if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif +endfun + + +"=== BASIC HIGHLIGHTING ======================================================= + +" cursor + status line + selected tab +cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) + +" line numbers +cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" basic text +cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) +cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) +cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) +cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) +cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) + +" commented-out text +cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) + +" highlighted background +cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) + +" muted text on highlighted background +cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" strongly highlighted background +cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) + +" selected menu item +cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) +cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) + +" solid lines +cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) +cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) +cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) + + +"=== ALERT/SYNTAX HIGHLIGHTING ================================================ + +" RED for warning elements +cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) +cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) +cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) +cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) + +" ORANGE for preliminary elements +cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) +cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) +cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) + +" YELLOW for highlighted elements +cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) + +" GREEN for action elements +cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) +cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) + +" TEAL for object types +cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) +cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) + +" BLUE for constants +cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) + +" PURPLE for special text +cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) +cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) + +" PINK for object names +cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) +cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) + + +"=== OPTIONS ================================================================== + +" disable highlighted CursorLineNr +if exists('g:office_light_CursorLineNr') +if g:office_light_CursorLineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +endif +endif + +" disable LineNr background altogether +if exists('g:office_light_LineNr') +if g:office_light_LineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +endif +endif diff --git a/VimFiles/colors/obsidian.vim b/VimFiles/colors/obsidian.vim new file mode 100755 index 0000000..a9d9dfa --- /dev/null +++ b/VimFiles/colors/obsidian.vim @@ -0,0 +1,23 @@ +set background=dark +hi clear + +if exists("syntax_on") + syntax reset +endif + +let g:colors_name="obsidian" + +hi PreProc ctermfg=5 cterm=bold +hi cDefine ctermfg=5 cterm=bold +hi cDefined ctermfg=4 cterm=bold +" hi Function ctermfg=1 cterm=bold +hi def cCustomFunc gui=bold guifg=#FF00FF ctermfg=4 cterm=bold +hi StorageClass ctermfg=5 cterm=bold +" hi Type ctermfg=7 cterm=bold +" hi Type ctermfg=5 cterm=bold +hi Type ctermfg=5 cterm=bold +hi cIncluded ctermfg=0 cterm=bold +hi Comment ctermfg=1 +hi Constant ctermfg=1 cterm=bold + + diff --git a/VimFiles/doc/lldb.txt b/VimFiles/doc/lldb.txt new file mode 100755 index 0000000..5a369f8 --- /dev/null +++ b/VimFiles/doc/lldb.txt @@ -0,0 +1,173 @@ +*lldb.txt* A plugin that enables debugging from your favourite editor + + _ ____ ____ + _ __(_)___ ___ / / /___/ / /_ + | | / / / __ `__ \______/ / / __ / __ \ + | |/ / / / / / / /_____/ / / /_/ / /_/ / + |___/_/_/ /_/ /_/ /_/_/\__,_/_.___/ + + LLDB Debugger Ingegration For VIM + +============================================================================== + +CONTENTS *lldb-contents* + + 1. Introduction .................... |lldb-intro| + 2. Getting Started ................. |lldb-start| + 3. Commands ........................ |lldb-commands| + 4. Mappings ........................ |lldb-mappings| + 4. License ......................... |lldb-license| + 5. Bugs ............................ |lldb-bugs| + 6. Contributing .................... |lldb-contributing| + + +Maintainer : Tobias Pflug +Original Author: Daniel Malea +License: Same terms as Vim itself (see |license|) + +INTRODUCTION *lldb-intro* + +The plugin provides an interface to the lldb debugger allowing for +convenient debugging sessions inside your favorite editor including +features such as breakpoints, stepping, watchpoints etc. + +The original plugin can be found here: + +http://llvm.org/svn/llvm-project/lldb/trunk/utils/vim-lldb/ + +Credit for pretty much all current functionality goes to the original +authors. Currently only minor modifications have been made to the +original plugin. + + +GETTING STARTED *lldb-start* + +To quickly get started compile (don't forget to compile with debugging +symbols) and start some program. Then open a source file belonging to the +program in vim and execute ':Lattach .' Then select some +line in the source file and execute ':Lbreakpoint' to set a breakpint at +the current line. + +Once the program reaches the specified breakpoint you will be able to +inspect state and step through the proram using the commands described below. + +COMMANDS *lldb-commands* + +The LLDB command interpreter is exposed to Vim's command mode using the +':L' prefix. Tab-completion is available and will cycle through commands. +Some commands have modified behaviour in Vim; for example, :Lbreakpoint +with no arguments will set a breakpoint at the current cursor, rather than +printing the standard help information for the LLDB command 'breakpoint'. + + *lldb-windows* + +In addition to the standard commands available under the LLDB interpreter, +there are also commands to display or hide informational debugger panes. + +Windows can be shown or hidden using the ':Lhide ' or ':Lshow ' +commands. + *lldb-:Lhide* +:Lhide [windowname] Hide informational debugger pane named 'windowname'. + + *lldb-:Lshow* +:Lshow [windowname] Show informational debugger pane named 'windowname'. + +Possible window name arguments to the Lhide and Lshow commands include: + + * backtrace + * breakpoints + * disassembly + * locals + * registers + * threads + *lldb-:Lattach* +:Lattach Attach to a process by name. + + *lldb-:Ldetach* +:Ldetach Detach from the current process. + + *lldb-:Ltarget* +:Ltarget [[create] executable] + Create a target with the specified executable. If + run with a single argument, that argument is assumed + to be a path to the executable to be debugged. + Otherwise, all arguments are passed into LLDB's command + interpreter. + + *lldb-:Lstart* +:Lstart Create a process by executing the current target + and wait for LLDB to attach. + + *lldb-:Lrun* +:Lrun Create a process by executing the current target + without waiting for LLDB to attach. + + *lldb-:Lcontinue* +:Lcontinue Continue execution of the process until the next + breakpoint is hit or the process exits. + + *lldb-:Lthread* +:Lthread Passes through to LLDB. See :Lhelp thread. + + *lldb-:Lstep* +:Lstep Step into the current function call. + + *lldb-:Lstepin* +:Lstepin Step into the current function call. + + *lldb-:Lstepinst* +:Lstepinst Step one instruction. + + *lldb-:Lstepinstover* +:Lstepinstover Step one instruction, but skip over jump or call + instructions. + + *lldb-:Lnext* +:Lnext Step to the next line. + + *lldb-:Lfinish* +:Lfinish Step out of the current function. + + *lldb-:Lbreakpoint* +:Lbreakpoint [args] When arguments are provided, the lldb breakpoint + command is invoked. If no arguments are provided, + a breakpoint at the location under the cursor. + + *lldb-:Lprint* + *lldb-:Lpo* + *lldb-:LpO* +:Lprint Aliases to the lldb print and po commands. Cursor +:Lpo word (cursor WORD for LpO) will be used when +:LpO expression omitted. + +MAPPINGS *lldb-mappings* + +There are no default mappings defined by the plugin. All commands described +above can be mapped by defining a respective variable: + + let g:lldb_map_Lframe = "f" + +This will map the Lframe command to "f". Other commands can be +mapped accordingly using 'lldb_map_' + . + + +LICENSE *lldb-license* + +Same as Vim itself. + +BUGS *lldb-bugs* + +If you run into a bug use the github issue tracker to report it: +http://github.com/gilligan/vim-lldb/issues/ + +CONTRIBUTING *lldb-contributing* + +If you want to help out you are more then welcome to do so. In fact +I am sure there are plenty of people out there that will do a better +job with this plugin than me. My C skills are more than rusty. I mostly +wanted to make this nice plugin more public and host it in a way in which +it is easy to install with your favorite plugin manager. + +Long story short: Bring on your forks and pull requests. + + vim:tw=78:sw=4:ft=help:norl: diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/VimFiles/colors/colors.vim b/VimFiles/colors/colors.vim new file mode 100755 index 0000000..e9e1cb4 --- /dev/null +++ b/VimFiles/colors/colors.vim @@ -0,0 +1,236 @@ +" office-light, a vim colourscheme by nightsense +" +" generated with a theme template adapted from +" base16-vim (https://github.com/chriskempson/base16-vim) +" by Chris Kempson (http://chriskempson.com) + + +"=== SET COLOUR VARIABLES ===================================================== + +" GUI colours +let s:g0 = 'fffff0' +let s:g1 = 'f0f0e1' +let s:g2 = 'b5b5aa' +let s:g3 = '9e9e95' +let s:g4 = '8a8a81' +let s:g5 = '75756e' +let s:g6 = '3b3b37' +let s:g7 = '2b2b29' +let s:g8 = 'f55050' +let s:g9 = 'e06a26' +let s:gA = 'd4ac35' +let s:gB = '219e21' +let s:gC = '1b9e9e' +let s:gD = '468dd4' +let s:gE = 'a26fbf' +let s:gF = 'd46a84' + +" terminal colours +let s:t0 = '10' +let s:t3 = '08' +let s:t5 = '07' +let s:t7 = '15' +let s:t8 = '01' +let s:tA = '03' +let s:tB = '02' +let s:tC = '06' +let s:tD = '04' +let s:tE = '05' +let s:t1 = '10' +let s:t2 = '11' +let s:t4 = '12' +let s:t6 = '13' +let s:t9 = '09' +let s:tF = '14' + +" neovim colours +if has('nvim') + let g:terminal_color_0 = '#fffff0' + let g:terminal_color_1 = '#f55050' + let g:terminal_color_2 = '#219e21' + let g:terminal_color_3 = '#d4ac35' + let g:terminal_color_4 = '#468dd4' + let g:terminal_color_5 = '#a26fbf' + let g:terminal_color_6 = '#1b9e9e' + let g:terminal_color_7 = '#75756e' + let g:terminal_color_8 = '#9e9e95' + let g:terminal_color_9 = '#e06a26' + let g:terminal_color_10 = '#f0f0e1' + let g:terminal_color_11 = '#b5b5aa' + let g:terminal_color_12 = '#8a8a81' + let g:terminal_color_13 = '#3b3b37' + let g:terminal_color_14 = '#d46a84' + let g:terminal_color_15 = '#2b2b29' +endif + + +"=== OTHER PREPARATION ======================================================== + +" clear old theme +hi clear +syntax reset + +" set new theme +set background=light +augroup NightsenseThemeSet + autocmd! + autocmd CursorMoved * execute 'if !exists("colors_name") | + \ colorscheme office-light | endif' +augroup END +let colors_name = 'office-light' + +" highlighting function +fun! h(x, gf, gb, cf, cb, a, s) + if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif + if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif + if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif + if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif + if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif + if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif +endfun + + +"=== BASIC HIGHLIGHTING ======================================================= + +" cursor + status line + selected tab +cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) + +" line numbers +cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" basic text +cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) +cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) +cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) +cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) +cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) + +" commented-out text +cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) + +" highlighted background +cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) + +" muted text on highlighted background +cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" strongly highlighted background +cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) + +" selected menu item +cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) +cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) + +" solid lines +cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) +cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) +cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) + + +"=== ALERT/SYNTAX HIGHLIGHTING ================================================ + +" RED for warning elements +cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) +cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) +cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) +cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) + +" ORANGE for preliminary elements +cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) +cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) +cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) + +" YELLOW for highlighted elements +cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) + +" GREEN for action elements +cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) +cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) + +" TEAL for object types +cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) +cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) + +" BLUE for constants +cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) + +" PURPLE for special text +cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) +cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) + +" PINK for object names +cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) +cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) + + +"=== OPTIONS ================================================================== + +" disable highlighted CursorLineNr +if exists('g:office_light_CursorLineNr') +if g:office_light_CursorLineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +endif +endif + +" disable LineNr background altogether +if exists('g:office_light_LineNr') +if g:office_light_LineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +endif +endif diff --git a/VimFiles/colors/obsidian.vim b/VimFiles/colors/obsidian.vim new file mode 100755 index 0000000..a9d9dfa --- /dev/null +++ b/VimFiles/colors/obsidian.vim @@ -0,0 +1,23 @@ +set background=dark +hi clear + +if exists("syntax_on") + syntax reset +endif + +let g:colors_name="obsidian" + +hi PreProc ctermfg=5 cterm=bold +hi cDefine ctermfg=5 cterm=bold +hi cDefined ctermfg=4 cterm=bold +" hi Function ctermfg=1 cterm=bold +hi def cCustomFunc gui=bold guifg=#FF00FF ctermfg=4 cterm=bold +hi StorageClass ctermfg=5 cterm=bold +" hi Type ctermfg=7 cterm=bold +" hi Type ctermfg=5 cterm=bold +hi Type ctermfg=5 cterm=bold +hi cIncluded ctermfg=0 cterm=bold +hi Comment ctermfg=1 +hi Constant ctermfg=1 cterm=bold + + diff --git a/VimFiles/doc/lldb.txt b/VimFiles/doc/lldb.txt new file mode 100755 index 0000000..5a369f8 --- /dev/null +++ b/VimFiles/doc/lldb.txt @@ -0,0 +1,173 @@ +*lldb.txt* A plugin that enables debugging from your favourite editor + + _ ____ ____ + _ __(_)___ ___ / / /___/ / /_ + | | / / / __ `__ \______/ / / __ / __ \ + | |/ / / / / / / /_____/ / / /_/ / /_/ / + |___/_/_/ /_/ /_/ /_/_/\__,_/_.___/ + + LLDB Debugger Ingegration For VIM + +============================================================================== + +CONTENTS *lldb-contents* + + 1. Introduction .................... |lldb-intro| + 2. Getting Started ................. |lldb-start| + 3. Commands ........................ |lldb-commands| + 4. Mappings ........................ |lldb-mappings| + 4. License ......................... |lldb-license| + 5. Bugs ............................ |lldb-bugs| + 6. Contributing .................... |lldb-contributing| + + +Maintainer : Tobias Pflug +Original Author: Daniel Malea +License: Same terms as Vim itself (see |license|) + +INTRODUCTION *lldb-intro* + +The plugin provides an interface to the lldb debugger allowing for +convenient debugging sessions inside your favorite editor including +features such as breakpoints, stepping, watchpoints etc. + +The original plugin can be found here: + +http://llvm.org/svn/llvm-project/lldb/trunk/utils/vim-lldb/ + +Credit for pretty much all current functionality goes to the original +authors. Currently only minor modifications have been made to the +original plugin. + + +GETTING STARTED *lldb-start* + +To quickly get started compile (don't forget to compile with debugging +symbols) and start some program. Then open a source file belonging to the +program in vim and execute ':Lattach .' Then select some +line in the source file and execute ':Lbreakpoint' to set a breakpint at +the current line. + +Once the program reaches the specified breakpoint you will be able to +inspect state and step through the proram using the commands described below. + +COMMANDS *lldb-commands* + +The LLDB command interpreter is exposed to Vim's command mode using the +':L' prefix. Tab-completion is available and will cycle through commands. +Some commands have modified behaviour in Vim; for example, :Lbreakpoint +with no arguments will set a breakpoint at the current cursor, rather than +printing the standard help information for the LLDB command 'breakpoint'. + + *lldb-windows* + +In addition to the standard commands available under the LLDB interpreter, +there are also commands to display or hide informational debugger panes. + +Windows can be shown or hidden using the ':Lhide ' or ':Lshow ' +commands. + *lldb-:Lhide* +:Lhide [windowname] Hide informational debugger pane named 'windowname'. + + *lldb-:Lshow* +:Lshow [windowname] Show informational debugger pane named 'windowname'. + +Possible window name arguments to the Lhide and Lshow commands include: + + * backtrace + * breakpoints + * disassembly + * locals + * registers + * threads + *lldb-:Lattach* +:Lattach Attach to a process by name. + + *lldb-:Ldetach* +:Ldetach Detach from the current process. + + *lldb-:Ltarget* +:Ltarget [[create] executable] + Create a target with the specified executable. If + run with a single argument, that argument is assumed + to be a path to the executable to be debugged. + Otherwise, all arguments are passed into LLDB's command + interpreter. + + *lldb-:Lstart* +:Lstart Create a process by executing the current target + and wait for LLDB to attach. + + *lldb-:Lrun* +:Lrun Create a process by executing the current target + without waiting for LLDB to attach. + + *lldb-:Lcontinue* +:Lcontinue Continue execution of the process until the next + breakpoint is hit or the process exits. + + *lldb-:Lthread* +:Lthread Passes through to LLDB. See :Lhelp thread. + + *lldb-:Lstep* +:Lstep Step into the current function call. + + *lldb-:Lstepin* +:Lstepin Step into the current function call. + + *lldb-:Lstepinst* +:Lstepinst Step one instruction. + + *lldb-:Lstepinstover* +:Lstepinstover Step one instruction, but skip over jump or call + instructions. + + *lldb-:Lnext* +:Lnext Step to the next line. + + *lldb-:Lfinish* +:Lfinish Step out of the current function. + + *lldb-:Lbreakpoint* +:Lbreakpoint [args] When arguments are provided, the lldb breakpoint + command is invoked. If no arguments are provided, + a breakpoint at the location under the cursor. + + *lldb-:Lprint* + *lldb-:Lpo* + *lldb-:LpO* +:Lprint Aliases to the lldb print and po commands. Cursor +:Lpo word (cursor WORD for LpO) will be used when +:LpO expression omitted. + +MAPPINGS *lldb-mappings* + +There are no default mappings defined by the plugin. All commands described +above can be mapped by defining a respective variable: + + let g:lldb_map_Lframe = "f" + +This will map the Lframe command to "f". Other commands can be +mapped accordingly using 'lldb_map_' + . + + +LICENSE *lldb-license* + +Same as Vim itself. + +BUGS *lldb-bugs* + +If you run into a bug use the github issue tracker to report it: +http://github.com/gilligan/vim-lldb/issues/ + +CONTRIBUTING *lldb-contributing* + +If you want to help out you are more then welcome to do so. In fact +I am sure there are plenty of people out there that will do a better +job with this plugin than me. My C skills are more than rusty. I mostly +wanted to make this nice plugin more public and host it in a way in which +it is easy to install with your favorite plugin manager. + +Long story short: Bring on your forks and pull requests. + + vim:tw=78:sw=4:ft=help:norl: diff --git a/VimSetup.rc b/VimSetup.rc index ae53725..4115b50 100644 --- a/VimSetup.rc +++ b/VimSetup.rc @@ -1,4 +1,8 @@ +" Loads bundles +execute pathogen#infect() + + " Make vim behave like vim rather than like vi set nocompatible " set backup @@ -8,6 +12,8 @@ " going to use this until it comes back to bite me... " Amazing - it never did. " +" Implication here is that following a tag to another +" file will write the current file if modified set autowrite " @@ -24,13 +30,22 @@ " Ctrl-E to go back to editing " Ctrl-C to commit working copy " Ctrl-S to list repository status +" Ctrl-L to list current directory " Enter when over item in the list, it opens it map :set splitright \| vnew \| r!svn cat #:windo :diffthis1G map :q! map :!svn commit --editor-cmd vim %:p map :new \| r!svn st `svn info --show-item wc-root` \| sort -r1G +map :new \| r!ls -la1G map $bgf +" Get SVN log on current file: +" map :new \| r!svn log #1G +" Also useful might be being able to load particular revisions +" Or get the diff between revisions +" Or show the blame +" map :new \| r!svn blame #1G + " " Defaults for Bash-Support Vim plugin " @@ -80,22 +95,24 @@ map :cp -" Stuff From wiki - -set ts=2 sw=2 et -" set shiftwidth=4 -" set softtabstop=4 +" Indentation and tab settings set expandtab - +set shiftwidth=2 +set softtabstop=2 +set tabstop=2 " Justin informs me that :0 in your cinoptions is how you prevent the extra indentation on switch statements. "cinoptions=[options],:0 "cinoptions+=:0 -set tags=$BASEDIR/.tags +set tags=./tags; map -map +map +map +" map + +" map bwg] set shiftround set autoindent @@ -153,8 +170,12 @@ " * Keystrokes -- Formatting " have Q reformat the current paragraph (or selected text if there is any): -nnoremap Q gqap -vnoremap Q gq +" nnoremap Q gqap +" vnoremap Q gq + +" Reformats the current function +map Q ]}=% + " have the usual indentation keystrokes still work in visual mode: vnoremap > @@ -227,7 +248,52 @@ " command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell() +function! PrintHelp() + " Now we can just write to the buffer, whatever you want. + call append('$', " ") + call append('$', " John's .vimrc Extensions 1.0 ") + call append('$', " " . split(system('vi --version'),'(')[0] ) + call append('$', ' ' . split(system('uname -v'),':')[0]) + call append('$', " ") + call append('$', " Navigation keys: ") + call append('$', " Ctrl-Q to quit all (without saving) ") + call append('$', " space to follow link under cursor ") + call append('$', " tab to go back in cursor history ") + call append('$', " Ctrl-T to navigate back ") + call append('$', " j / k to page up or down ") + call append('$', " [[ / ]] next/prev code block ") + call append('$', " % move to matching pair ") + call append('$', " Ctrl-I/O fwd/back in cursor history ") + call append('$', " ") + call append('$', " Editing keys: ") + call append('$', " Q reformat the current function ") + call append('$', " ") + call append('$', " Compiling integration: ") + call append('$', " Ctrl-M to execute make ") + call append('$', " Ctrl-N/X to jump to next error ") + call append('$', " Ctrl-P/Z to jump to prev error ") + call append('$', " ") + call append('$', " SVN related integration: ") + call append('$', " Ctrl-D to diff working copy ") + call append('$', " Ctrl-E to go back to editing ") + call append('$', " Ctrl-C to commit working copy ") + call append('$', " Ctrl-S to list repository status ") + call append('$', " Ctrl-L to list current directory ") + call append('$', " Enter to open file from status list ") + call append('$', " ") +endfunction + + function! ShowHelp() + new + call PrintHelp() +endfunction + + +:command Help call ShowHelp() + + +function! ShowOnStartHelp() " Only continue if started without opening a file or anything fancy if argc() || line2byte('$') != -1 || v:progname !~? '^[-gmnq]\=vim\=x\=\%[\.exe]$' || &insertmode return @@ -248,30 +314,7 @@ \ noswapfile \ norelativenumber - " Now we can just write to the buffer, whatever you want. - call append('$', " ") - call append('$', " John's .vimrc Extensions 1.0 ") - call append('$', " " . split(system('vi --version'),'(')[0] ) - call append('$', ' ' . split(system('uname -v'),':')[0]) - call append('$', " ") - call append('$', " Navigation keys: ") - call append('$', " space to follow tag/symbol under cursor ") - call append('$', " tab to follow tag/symbol under cursor ") - call append('$', " Ctrl-Q to quit all (without saving) ") - call append('$', " j / k to page up or down ") - call append('$', " ") - call append('$', " Compiling integration: ") - call append('$', " Ctrl-M to execute make ") - call append('$', " Ctrl-N/X to jump to next error ") - call append('$', " Ctrl-P/Z to jump to prev error ") - call append('$', " ") - call append('$', " SVN related integration: ") - call append('$', " Ctrl-D to diff working copy ") - call append('$', " Ctrl-E to go back to editing ") - call append('$', " Ctrl-C to commit working copy ") - call append('$', " Ctrl-S to list repository status ") - call append('$', " Enter to open file from status list ") - call append('$', " ") + call PrintHelp() " No modifications to this buffer setlocal nomodifiable nomodified @@ -280,12 +323,10 @@ nnoremap e :enew nnoremap i :enew startinsert nnoremap o :enew startinsert - endfunction " Run after doing all the startup stuff -autocmd VimEnter * call ShowHelp() - +autocmd VimEnter * call ShowOnStartHelp() diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/VimFiles/colors/colors.vim b/VimFiles/colors/colors.vim new file mode 100755 index 0000000..e9e1cb4 --- /dev/null +++ b/VimFiles/colors/colors.vim @@ -0,0 +1,236 @@ +" office-light, a vim colourscheme by nightsense +" +" generated with a theme template adapted from +" base16-vim (https://github.com/chriskempson/base16-vim) +" by Chris Kempson (http://chriskempson.com) + + +"=== SET COLOUR VARIABLES ===================================================== + +" GUI colours +let s:g0 = 'fffff0' +let s:g1 = 'f0f0e1' +let s:g2 = 'b5b5aa' +let s:g3 = '9e9e95' +let s:g4 = '8a8a81' +let s:g5 = '75756e' +let s:g6 = '3b3b37' +let s:g7 = '2b2b29' +let s:g8 = 'f55050' +let s:g9 = 'e06a26' +let s:gA = 'd4ac35' +let s:gB = '219e21' +let s:gC = '1b9e9e' +let s:gD = '468dd4' +let s:gE = 'a26fbf' +let s:gF = 'd46a84' + +" terminal colours +let s:t0 = '10' +let s:t3 = '08' +let s:t5 = '07' +let s:t7 = '15' +let s:t8 = '01' +let s:tA = '03' +let s:tB = '02' +let s:tC = '06' +let s:tD = '04' +let s:tE = '05' +let s:t1 = '10' +let s:t2 = '11' +let s:t4 = '12' +let s:t6 = '13' +let s:t9 = '09' +let s:tF = '14' + +" neovim colours +if has('nvim') + let g:terminal_color_0 = '#fffff0' + let g:terminal_color_1 = '#f55050' + let g:terminal_color_2 = '#219e21' + let g:terminal_color_3 = '#d4ac35' + let g:terminal_color_4 = '#468dd4' + let g:terminal_color_5 = '#a26fbf' + let g:terminal_color_6 = '#1b9e9e' + let g:terminal_color_7 = '#75756e' + let g:terminal_color_8 = '#9e9e95' + let g:terminal_color_9 = '#e06a26' + let g:terminal_color_10 = '#f0f0e1' + let g:terminal_color_11 = '#b5b5aa' + let g:terminal_color_12 = '#8a8a81' + let g:terminal_color_13 = '#3b3b37' + let g:terminal_color_14 = '#d46a84' + let g:terminal_color_15 = '#2b2b29' +endif + + +"=== OTHER PREPARATION ======================================================== + +" clear old theme +hi clear +syntax reset + +" set new theme +set background=light +augroup NightsenseThemeSet + autocmd! + autocmd CursorMoved * execute 'if !exists("colors_name") | + \ colorscheme office-light | endif' +augroup END +let colors_name = 'office-light' + +" highlighting function +fun! h(x, gf, gb, cf, cb, a, s) + if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif + if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif + if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif + if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif + if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif + if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif +endfun + + +"=== BASIC HIGHLIGHTING ======================================================= + +" cursor + status line + selected tab +cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) + +" line numbers +cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" basic text +cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) +cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) +cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) +cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) +cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) + +" commented-out text +cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) + +" highlighted background +cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) + +" muted text on highlighted background +cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" strongly highlighted background +cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) + +" selected menu item +cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) +cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) + +" solid lines +cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) +cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) +cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) + + +"=== ALERT/SYNTAX HIGHLIGHTING ================================================ + +" RED for warning elements +cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) +cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) +cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) +cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) + +" ORANGE for preliminary elements +cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) +cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) +cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) + +" YELLOW for highlighted elements +cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) + +" GREEN for action elements +cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) +cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) + +" TEAL for object types +cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) +cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) + +" BLUE for constants +cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) + +" PURPLE for special text +cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) +cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) + +" PINK for object names +cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) +cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) + + +"=== OPTIONS ================================================================== + +" disable highlighted CursorLineNr +if exists('g:office_light_CursorLineNr') +if g:office_light_CursorLineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +endif +endif + +" disable LineNr background altogether +if exists('g:office_light_LineNr') +if g:office_light_LineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +endif +endif diff --git a/VimFiles/colors/obsidian.vim b/VimFiles/colors/obsidian.vim new file mode 100755 index 0000000..a9d9dfa --- /dev/null +++ b/VimFiles/colors/obsidian.vim @@ -0,0 +1,23 @@ +set background=dark +hi clear + +if exists("syntax_on") + syntax reset +endif + +let g:colors_name="obsidian" + +hi PreProc ctermfg=5 cterm=bold +hi cDefine ctermfg=5 cterm=bold +hi cDefined ctermfg=4 cterm=bold +" hi Function ctermfg=1 cterm=bold +hi def cCustomFunc gui=bold guifg=#FF00FF ctermfg=4 cterm=bold +hi StorageClass ctermfg=5 cterm=bold +" hi Type ctermfg=7 cterm=bold +" hi Type ctermfg=5 cterm=bold +hi Type ctermfg=5 cterm=bold +hi cIncluded ctermfg=0 cterm=bold +hi Comment ctermfg=1 +hi Constant ctermfg=1 cterm=bold + + diff --git a/VimFiles/doc/lldb.txt b/VimFiles/doc/lldb.txt new file mode 100755 index 0000000..5a369f8 --- /dev/null +++ b/VimFiles/doc/lldb.txt @@ -0,0 +1,173 @@ +*lldb.txt* A plugin that enables debugging from your favourite editor + + _ ____ ____ + _ __(_)___ ___ / / /___/ / /_ + | | / / / __ `__ \______/ / / __ / __ \ + | |/ / / / / / / /_____/ / / /_/ / /_/ / + |___/_/_/ /_/ /_/ /_/_/\__,_/_.___/ + + LLDB Debugger Ingegration For VIM + +============================================================================== + +CONTENTS *lldb-contents* + + 1. Introduction .................... |lldb-intro| + 2. Getting Started ................. |lldb-start| + 3. Commands ........................ |lldb-commands| + 4. Mappings ........................ |lldb-mappings| + 4. License ......................... |lldb-license| + 5. Bugs ............................ |lldb-bugs| + 6. Contributing .................... |lldb-contributing| + + +Maintainer : Tobias Pflug +Original Author: Daniel Malea +License: Same terms as Vim itself (see |license|) + +INTRODUCTION *lldb-intro* + +The plugin provides an interface to the lldb debugger allowing for +convenient debugging sessions inside your favorite editor including +features such as breakpoints, stepping, watchpoints etc. + +The original plugin can be found here: + +http://llvm.org/svn/llvm-project/lldb/trunk/utils/vim-lldb/ + +Credit for pretty much all current functionality goes to the original +authors. Currently only minor modifications have been made to the +original plugin. + + +GETTING STARTED *lldb-start* + +To quickly get started compile (don't forget to compile with debugging +symbols) and start some program. Then open a source file belonging to the +program in vim and execute ':Lattach .' Then select some +line in the source file and execute ':Lbreakpoint' to set a breakpint at +the current line. + +Once the program reaches the specified breakpoint you will be able to +inspect state and step through the proram using the commands described below. + +COMMANDS *lldb-commands* + +The LLDB command interpreter is exposed to Vim's command mode using the +':L' prefix. Tab-completion is available and will cycle through commands. +Some commands have modified behaviour in Vim; for example, :Lbreakpoint +with no arguments will set a breakpoint at the current cursor, rather than +printing the standard help information for the LLDB command 'breakpoint'. + + *lldb-windows* + +In addition to the standard commands available under the LLDB interpreter, +there are also commands to display or hide informational debugger panes. + +Windows can be shown or hidden using the ':Lhide ' or ':Lshow ' +commands. + *lldb-:Lhide* +:Lhide [windowname] Hide informational debugger pane named 'windowname'. + + *lldb-:Lshow* +:Lshow [windowname] Show informational debugger pane named 'windowname'. + +Possible window name arguments to the Lhide and Lshow commands include: + + * backtrace + * breakpoints + * disassembly + * locals + * registers + * threads + *lldb-:Lattach* +:Lattach Attach to a process by name. + + *lldb-:Ldetach* +:Ldetach Detach from the current process. + + *lldb-:Ltarget* +:Ltarget [[create] executable] + Create a target with the specified executable. If + run with a single argument, that argument is assumed + to be a path to the executable to be debugged. + Otherwise, all arguments are passed into LLDB's command + interpreter. + + *lldb-:Lstart* +:Lstart Create a process by executing the current target + and wait for LLDB to attach. + + *lldb-:Lrun* +:Lrun Create a process by executing the current target + without waiting for LLDB to attach. + + *lldb-:Lcontinue* +:Lcontinue Continue execution of the process until the next + breakpoint is hit or the process exits. + + *lldb-:Lthread* +:Lthread Passes through to LLDB. See :Lhelp thread. + + *lldb-:Lstep* +:Lstep Step into the current function call. + + *lldb-:Lstepin* +:Lstepin Step into the current function call. + + *lldb-:Lstepinst* +:Lstepinst Step one instruction. + + *lldb-:Lstepinstover* +:Lstepinstover Step one instruction, but skip over jump or call + instructions. + + *lldb-:Lnext* +:Lnext Step to the next line. + + *lldb-:Lfinish* +:Lfinish Step out of the current function. + + *lldb-:Lbreakpoint* +:Lbreakpoint [args] When arguments are provided, the lldb breakpoint + command is invoked. If no arguments are provided, + a breakpoint at the location under the cursor. + + *lldb-:Lprint* + *lldb-:Lpo* + *lldb-:LpO* +:Lprint Aliases to the lldb print and po commands. Cursor +:Lpo word (cursor WORD for LpO) will be used when +:LpO expression omitted. + +MAPPINGS *lldb-mappings* + +There are no default mappings defined by the plugin. All commands described +above can be mapped by defining a respective variable: + + let g:lldb_map_Lframe = "f" + +This will map the Lframe command to "f". Other commands can be +mapped accordingly using 'lldb_map_' + . + + +LICENSE *lldb-license* + +Same as Vim itself. + +BUGS *lldb-bugs* + +If you run into a bug use the github issue tracker to report it: +http://github.com/gilligan/vim-lldb/issues/ + +CONTRIBUTING *lldb-contributing* + +If you want to help out you are more then welcome to do so. In fact +I am sure there are plenty of people out there that will do a better +job with this plugin than me. My C skills are more than rusty. I mostly +wanted to make this nice plugin more public and host it in a way in which +it is easy to install with your favorite plugin manager. + +Long story short: Bring on your forks and pull requests. + + vim:tw=78:sw=4:ft=help:norl: diff --git a/VimSetup.rc b/VimSetup.rc index ae53725..4115b50 100644 --- a/VimSetup.rc +++ b/VimSetup.rc @@ -1,4 +1,8 @@ +" Loads bundles +execute pathogen#infect() + + " Make vim behave like vim rather than like vi set nocompatible " set backup @@ -8,6 +12,8 @@ " going to use this until it comes back to bite me... " Amazing - it never did. " +" Implication here is that following a tag to another +" file will write the current file if modified set autowrite " @@ -24,13 +30,22 @@ " Ctrl-E to go back to editing " Ctrl-C to commit working copy " Ctrl-S to list repository status +" Ctrl-L to list current directory " Enter when over item in the list, it opens it map :set splitright \| vnew \| r!svn cat #:windo :diffthis1G map :q! map :!svn commit --editor-cmd vim %:p map :new \| r!svn st `svn info --show-item wc-root` \| sort -r1G +map :new \| r!ls -la1G map $bgf +" Get SVN log on current file: +" map :new \| r!svn log #1G +" Also useful might be being able to load particular revisions +" Or get the diff between revisions +" Or show the blame +" map :new \| r!svn blame #1G + " " Defaults for Bash-Support Vim plugin " @@ -80,22 +95,24 @@ map :cp -" Stuff From wiki - -set ts=2 sw=2 et -" set shiftwidth=4 -" set softtabstop=4 +" Indentation and tab settings set expandtab - +set shiftwidth=2 +set softtabstop=2 +set tabstop=2 " Justin informs me that :0 in your cinoptions is how you prevent the extra indentation on switch statements. "cinoptions=[options],:0 "cinoptions+=:0 -set tags=$BASEDIR/.tags +set tags=./tags; map -map +map +map +" map + +" map bwg] set shiftround set autoindent @@ -153,8 +170,12 @@ " * Keystrokes -- Formatting " have Q reformat the current paragraph (or selected text if there is any): -nnoremap Q gqap -vnoremap Q gq +" nnoremap Q gqap +" vnoremap Q gq + +" Reformats the current function +map Q ]}=% + " have the usual indentation keystrokes still work in visual mode: vnoremap > @@ -227,7 +248,52 @@ " command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell() +function! PrintHelp() + " Now we can just write to the buffer, whatever you want. + call append('$', " ") + call append('$', " John's .vimrc Extensions 1.0 ") + call append('$', " " . split(system('vi --version'),'(')[0] ) + call append('$', ' ' . split(system('uname -v'),':')[0]) + call append('$', " ") + call append('$', " Navigation keys: ") + call append('$', " Ctrl-Q to quit all (without saving) ") + call append('$', " space to follow link under cursor ") + call append('$', " tab to go back in cursor history ") + call append('$', " Ctrl-T to navigate back ") + call append('$', " j / k to page up or down ") + call append('$', " [[ / ]] next/prev code block ") + call append('$', " % move to matching pair ") + call append('$', " Ctrl-I/O fwd/back in cursor history ") + call append('$', " ") + call append('$', " Editing keys: ") + call append('$', " Q reformat the current function ") + call append('$', " ") + call append('$', " Compiling integration: ") + call append('$', " Ctrl-M to execute make ") + call append('$', " Ctrl-N/X to jump to next error ") + call append('$', " Ctrl-P/Z to jump to prev error ") + call append('$', " ") + call append('$', " SVN related integration: ") + call append('$', " Ctrl-D to diff working copy ") + call append('$', " Ctrl-E to go back to editing ") + call append('$', " Ctrl-C to commit working copy ") + call append('$', " Ctrl-S to list repository status ") + call append('$', " Ctrl-L to list current directory ") + call append('$', " Enter to open file from status list ") + call append('$', " ") +endfunction + + function! ShowHelp() + new + call PrintHelp() +endfunction + + +:command Help call ShowHelp() + + +function! ShowOnStartHelp() " Only continue if started without opening a file or anything fancy if argc() || line2byte('$') != -1 || v:progname !~? '^[-gmnq]\=vim\=x\=\%[\.exe]$' || &insertmode return @@ -248,30 +314,7 @@ \ noswapfile \ norelativenumber - " Now we can just write to the buffer, whatever you want. - call append('$', " ") - call append('$', " John's .vimrc Extensions 1.0 ") - call append('$', " " . split(system('vi --version'),'(')[0] ) - call append('$', ' ' . split(system('uname -v'),':')[0]) - call append('$', " ") - call append('$', " Navigation keys: ") - call append('$', " space to follow tag/symbol under cursor ") - call append('$', " tab to follow tag/symbol under cursor ") - call append('$', " Ctrl-Q to quit all (without saving) ") - call append('$', " j / k to page up or down ") - call append('$', " ") - call append('$', " Compiling integration: ") - call append('$', " Ctrl-M to execute make ") - call append('$', " Ctrl-N/X to jump to next error ") - call append('$', " Ctrl-P/Z to jump to prev error ") - call append('$', " ") - call append('$', " SVN related integration: ") - call append('$', " Ctrl-D to diff working copy ") - call append('$', " Ctrl-E to go back to editing ") - call append('$', " Ctrl-C to commit working copy ") - call append('$', " Ctrl-S to list repository status ") - call append('$', " Enter to open file from status list ") - call append('$', " ") + call PrintHelp() " No modifications to this buffer setlocal nomodifiable nomodified @@ -280,12 +323,10 @@ nnoremap e :enew nnoremap i :enew startinsert nnoremap o :enew startinsert - endfunction " Run after doing all the startup stuff -autocmd VimEnter * call ShowHelp() - +autocmd VimEnter * call ShowOnStartHelp() diff --git a/colors.vim b/colors.vim deleted file mode 100644 index e9e1cb4..0000000 --- a/colors.vim +++ /dev/null @@ -1,236 +0,0 @@ -" office-light, a vim colourscheme by nightsense -" -" generated with a theme template adapted from -" base16-vim (https://github.com/chriskempson/base16-vim) -" by Chris Kempson (http://chriskempson.com) - - -"=== SET COLOUR VARIABLES ===================================================== - -" GUI colours -let s:g0 = 'fffff0' -let s:g1 = 'f0f0e1' -let s:g2 = 'b5b5aa' -let s:g3 = '9e9e95' -let s:g4 = '8a8a81' -let s:g5 = '75756e' -let s:g6 = '3b3b37' -let s:g7 = '2b2b29' -let s:g8 = 'f55050' -let s:g9 = 'e06a26' -let s:gA = 'd4ac35' -let s:gB = '219e21' -let s:gC = '1b9e9e' -let s:gD = '468dd4' -let s:gE = 'a26fbf' -let s:gF = 'd46a84' - -" terminal colours -let s:t0 = '10' -let s:t3 = '08' -let s:t5 = '07' -let s:t7 = '15' -let s:t8 = '01' -let s:tA = '03' -let s:tB = '02' -let s:tC = '06' -let s:tD = '04' -let s:tE = '05' -let s:t1 = '10' -let s:t2 = '11' -let s:t4 = '12' -let s:t6 = '13' -let s:t9 = '09' -let s:tF = '14' - -" neovim colours -if has('nvim') - let g:terminal_color_0 = '#fffff0' - let g:terminal_color_1 = '#f55050' - let g:terminal_color_2 = '#219e21' - let g:terminal_color_3 = '#d4ac35' - let g:terminal_color_4 = '#468dd4' - let g:terminal_color_5 = '#a26fbf' - let g:terminal_color_6 = '#1b9e9e' - let g:terminal_color_7 = '#75756e' - let g:terminal_color_8 = '#9e9e95' - let g:terminal_color_9 = '#e06a26' - let g:terminal_color_10 = '#f0f0e1' - let g:terminal_color_11 = '#b5b5aa' - let g:terminal_color_12 = '#8a8a81' - let g:terminal_color_13 = '#3b3b37' - let g:terminal_color_14 = '#d46a84' - let g:terminal_color_15 = '#2b2b29' -endif - - -"=== OTHER PREPARATION ======================================================== - -" clear old theme -hi clear -syntax reset - -" set new theme -set background=light -augroup NightsenseThemeSet - autocmd! - autocmd CursorMoved * execute 'if !exists("colors_name") | - \ colorscheme office-light | endif' -augroup END -let colors_name = 'office-light' - -" highlighting function -fun! h(x, gf, gb, cf, cb, a, s) - if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif - if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif - if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif - if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif - if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif - if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif -endfun - - -"=== BASIC HIGHLIGHTING ======================================================= - -" cursor + status line + selected tab -cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) - -" line numbers -cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) -cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) - -" basic text -cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) -cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) -cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) -cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) -cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) - -" commented-out text -cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) - -" highlighted background -cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) -cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) -cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) - -" muted text on highlighted background -cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) - -" strongly highlighted background -cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) -cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) -cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) - -" selected menu item -cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) -cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) - -" solid lines -cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) -cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) -cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) - - -"=== ALERT/SYNTAX HIGHLIGHTING ================================================ - -" RED for warning elements -cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) -cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) -cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) -cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) -cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) -cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) - -" ORANGE for preliminary elements -cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) -cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) -cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) - -" YELLOW for highlighted elements -cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) -cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) -cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) - -" GREEN for action elements -cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) -cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) - -" TEAL for object types -cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) -cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) -cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) -cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) -cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) - -" BLUE for constants -cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) - -" PURPLE for special text -cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) -cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) - -" PINK for object names -cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) -cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) - - -"=== OPTIONS ================================================================== - -" disable highlighted CursorLineNr -if exists('g:office_light_CursorLineNr') -if g:office_light_CursorLineNr == 'off' -cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -endif -endif - -" disable LineNr background altogether -if exists('g:office_light_LineNr') -if g:office_light_LineNr == 'off' -cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) -cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) -endif -endif diff --git a/BashProfile.sh b/BashProfile.sh index 6e4af8b..119cf4b 100644 --- a/BashProfile.sh +++ b/BashProfile.sh @@ -1,4 +1,7 @@ alias vi='vim' alias ls='ls -G' +svndiff () { vimdiff <(svn diff "$@"); } +export EDITOR=vi +export SVN_EDITOR=vi diff --git a/VimFiles/autoload/pathogen.vim b/VimFiles/autoload/pathogen.vim new file mode 100644 index 0000000..3582fbf --- /dev/null +++ b/VimFiles/autoload/pathogen.vim @@ -0,0 +1,264 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.4 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() or an absolute path to invoke pathogen#surround(). +" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all +" subdirectories inside "bundle" inside all directories in the runtime path. +" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}" +" on versions of Vim without native package support. +function! pathogen#infect(...) abort + if a:0 + let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")') + else + let paths = ['bundle/{}', 'pack/{}/start/{}'] + endif + if has('packages') + call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"') + endif + let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$' + for path in filter(copy(paths), 'v:val =~# static') + call pathogen#surround(path) + endfor + for path in filter(copy(paths), 'v:val !~# static') + if path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call pathogen#surround(path) + else + call pathogen#interpose(path) + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/VimFiles/bundle/lldb/.gitignore b/VimFiles/bundle/lldb/.gitignore new file mode 100755 index 0000000..040ea62 --- /dev/null +++ b/VimFiles/bundle/lldb/.gitignore @@ -0,0 +1,2 @@ +doc/tags +*.pyc diff --git a/VimFiles/bundle/lldb/README.md b/VimFiles/bundle/lldb/README.md new file mode 100755 index 0000000..07b8429 --- /dev/null +++ b/VimFiles/bundle/lldb/README.md @@ -0,0 +1,5 @@ + + +:help lldb + + diff --git a/VimFiles/bundle/lldb/plugin/lldb.vim b/VimFiles/bundle/lldb/plugin/lldb.vim new file mode 100755 index 0000000..c21a0da --- /dev/null +++ b/VimFiles/bundle/lldb/plugin/lldb.vim @@ -0,0 +1,149 @@ +" --------------------------------------------------------------------- +" File: lldb.vim +" Description: LLDB Debugger Integration Plugin +" Maintainer: Tobias Pflug +" License: Same License as Vim itself +" -------------------------------------------------------------------- + +if (exists('g:loaded_lldb') && g:loaded_lldb) || v:version < 703 || &cp || !has('python') + finish +endif +let g:loaded_lldb = 1 + +" +" format of the command entries is as follows: +" [ command name , completion function, nargs, python code, keymap] +" +let s:lldb_commands = [ +\ ['Lhide', 's:CompleteWindow', '1', 'ctrl.doHide("")'], +\ ['Lshow', 's:CompleteWindow', '1', 'ctrl.doShow("")'], +\ ['Lstart', '', '*', 'ctrl.doLaunch(True, "")'], +\ ['Lrun', '', '*', 'ctrl.doLaunch(False, "")'], +\ ['Lattach', '', '1', 'ctrl.doAttach("")'], +\ ['Ldetach', '', '0', 'ctrl.doDetach()'], +\ ['Lregexpattach', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-attach", "")'], +\ ['Lregexpbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-break", "")'], +\ ['Lregexpbt', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-bt", "")'], +\ ['Lregexpdown', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-down", "")'], +\ ['Lregexptbreak', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-tbreak", "")'], +\ ['Lregexpdisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-display", "")'], +\ ['Lregexpundisplay', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-undisplay", "")'], +\ ['Lregexpup', 's:CompleteCommand', '*', 'ctrl.doCommand("_regexp-up", "")'], +\ ['Lapropos', 's:CompleteCommand', '*', 'ctrl.doCommand("apropos", "")'], +\ ['Lbacktrace', 's:CompleteCommand', '*', 'ctrl.doCommand("bt", "")'], +\ ['Lbreakpoint', 's:CompleteCommand', '*', 'ctrl.doBreakpoint("")', 'lb'], +\ ["Lcommand", "s:CompleteCommand", "*", 'ctrl.doCommand("command", "")'], +\ ["Ldisassemble", "s:CompleteCommand", "*", 'ctrl.doCommand("disassemble", "")'], +\ ["Lexpression", "s:CompleteCommand", "*", 'ctrl.doCommand("expression", "")'], +\ ["Lhelp", "s:CompleteCommand", "*", 'ctrl.doCommand("help", "")'], +\ ["Llog", "s:CompleteCommand", "*", 'ctrl.doCommand("log", "")'], +\ ["Lplatform", "s:CompleteCommand", "*", 'ctrl.doCommand("platform","")'], +\ ["Lplugin", "s:CompleteCommand", "*", 'ctrl.doCommand("plugin", "")'], +\ ["Lprocess", "s:CompleteCommand", "*", 'ctrl.doProcess("")'], +\ ["Lregister", "s:CompleteCommand", "*", 'ctrl.doCommand("register", "")'], +\ ["Lscript", "s:CompleteCommand", "*", 'ctrl.doCommand("script", "")'], +\ ["Lsettings", "s:CompleteCommand", "*", 'ctrl.doCommand("settings","")'], +\ ["Lsource", "s:CompleteCommand", "*", 'ctrl.doCommand("source", "")'], +\ ["Ltype", "s:CompleteCommand", "*", 'ctrl.doCommand("type", "")'], +\ ["Lversion", "s:CompleteCommand", "*", 'ctrl.doCommand("version", "")'], +\ ["Lwatchpoint", "s:CompleteCommand", "*", 'ctrl.doCommand("watchpoint", "")'], +\ ["Lprint", "s:CompleteCommand", "*", 'ctrl.doCommand("print", vim.eval("s:CursorWord("")"))'], +\ ["Lpo", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWord("")"))'], +\ ["LpO", "s:CompleteCommand", "*", 'ctrl.doCommand("po", vim.eval("s:CursorWORD("")"))'], +\ ["Lbt", "s:CompleteCommand", "*", 'ctrl.doCommand("bt", "")'], +\ ["Lframe", "s:CompleteCommand", "*", 'ctrl.doSelect("frame", "")'], +\ ["Lup", "s:CompleteCommand", "?", 'ctrl.doCommand("up", "", print_on_success=False, goto_file=True)'], +\ ["Ldown", "s:CompleteCommand", "?", 'ctrl.doCommand("down", "", print_on_success=False, goto_file=True)'], +\ ["Lthread", "s:CompleteCommand", "*", 'ctrl.doSelect("thread", "")'], +\ ["Ltarget", "s:CompleteCommand", "*", 'ctrl.doTarget("")'], +\ ['Lcontinue', "s:CompleteCommand", "*", 'ctrl.doContinue()', 'lc'], +\ ['Lstepinst', "", "0", 'ctrl.doStep(StepType.INSTRUCTION)'], +\ ['Lstepinstover', "", "0", 'ctrl.doStep(StepType.INSTRUCTION_OVER)'], +\ ['Lstepin', "", "0", 'ctrl.doStep(StepType.INTO)'], +\ ['Lstep', "", "0", 'ctrl.doStep(StepType.INTO)', 'li'], +\ ['Lnext', "", "0", 'ctrl.doStep(StepType.OVER)', 'ln'], +\ ['Lfinish', "", "0", 'ctrl.doStep(StepType.OUT)'], +\ ['Lrefresh', "", "0", 'ctrl.doRefresh()', 'lr'] +\] + +" Python module init {{{ +function! lldb#pythonInit() + execute 'python import sys' + let python_module_dir = fnameescape(globpath(&runtimepath, 'python-vim-lldb')) + execute 'python sys.path.append("' . python_module_dir . '")' + execute 'pyfile ' . python_module_dir . '/plugin.py' +endfunction +" }}} + + +" Command registration {{{ +function! lldb#createCommands() + for cmd in s:lldb_commands + let complFun = '' + let nargs = '' + if len(cmd[1]) > 0 + let complFun = '-complete=custom,' . cmd[1] + endif + if len(cmd[2]) > 0 + let nargs = '-nargs=' . cmd[2] + endif + execute 'command ' . complFun . ' ' . nargs . ' ' . cmd[0] . ' python ' . cmd[3] + endfor + " hack: service the LLDB event-queue when the cursor moves + autocmd CursorMoved * :Lrefresh + autocmd CursorHold * :Lrefresh + autocmd VimLeavePre * python ctrl.doExit() +endfunction +" + +function lldb#createKeyMaps() + for cmd in s:lldb_commands + " only map what has been configured by the user + if exists('g:lldb_map_' . cmd[0]) + execute 'nnoremap ' . eval('g:lldb_map_' . cmd[0]) . ' :' . cmd[0] . '' + endif + endfor +endfunction + +function! s:InitLldbPlugin() + call lldb#pythonInit() + call lldb#createCommands() + call lldb#createKeyMaps() +endfunction() +" }}} + + +" Command Completion Functions {{{ +function! s:CompleteCommand(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteCommand(a, l, p) +EOF +endfunction() + +function! s:CompleteWindow(A, L, P) + python << EOF +a = vim.eval("a:A") +l = vim.eval("a:L") +p = vim.eval("a:P") +returnCompleteWindow(a, l, p) +EOF +endfunction() + +" Returns cword if search term is empty +function! s:CursorWord(term) + return empty(a:term) ? expand('') : a:term +endfunction() + +" Returns cleaned cWORD if search term is empty +function! s:CursorWORD(term) + " Will strip all non-alphabetic characters from both sides + return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term +endfunction() +" }}} + + +call s:InitLldbPlugin() + diff --git a/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py new file mode 100755 index 0000000..a2145d5 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/import_lldb.py @@ -0,0 +1,61 @@ + +# Locate and load the lldb python module + +import os, sys + +def import_lldb(): + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH + try: + import lldb + return True + except ImportError: + pass + + # Allow overriding default path to lldb executable with the LLDB environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + #lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass + + return False + +if not import_lldb(): + import vim + vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py new file mode 100755 index 0000000..923e771 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/lldb_controller.py @@ -0,0 +1,384 @@ + +# +# This file defines the layer that talks to lldb +# + +import os, re, sys +import lldb +import vim +from vim_ui import UI + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [#"create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def doCommand(self, command, command_args, print_on_success = True, goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent(wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) + + +def returnCompleteCommand(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + +def returnCompleteWindow(a, l, p): + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) + +global ctrl +ctrl = LLDBController() diff --git a/VimFiles/bundle/lldb/python-vim-lldb/plugin.py b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py new file mode 100755 index 0000000..694783a --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/plugin.py @@ -0,0 +1,14 @@ + +# Try to import all dependencies, catch and handle the error gracefully if it fails. + +import import_lldb + +try: + import lldb + import vim +except ImportError: + sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass +else: + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py new file mode 100755 index 0000000..7fae06b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_panes.py @@ -0,0 +1,644 @@ +# +# This file contains implementations of the LLDB display panes in VIM +# +# The most generic way to define a new window is to inherit from VimPane +# and to implement: +# - get_content() - returns a string with the pane contents +# +# Optionally, to highlight text, implement: +# - get_highlights() - returns a map +# +# And call: +# - define_highlight(unique_name, colour) +# at some point in the constructor. +# +# +# If the pane shows some key-value data that is in the context of a +# single frame, inherit from FrameKeyValuePane and implement: +# - get_frame_content(self, SBFrame frame) +# +# +# If the pane presents some information that can be retrieved with +# a simple LLDB command while the subprocess is stopped, inherit +# from StoppedCommandPane and call: +# - self.setCommand(command, command_args) +# at some point in the constructor. +# +# Optionally, you can implement: +# - get_selected_line() +# to highlight a selected line and place the cursor there. +# +# +# FIXME: implement WatchlistPane to displayed watched expressions +# FIXME: define interface for interactive panes, like catching enter +# presses to change selected frame/thread... +# + +import lldb +import vim + +import sys + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== + +# Shamelessly copy/pasted from lldbutil.py in the test suite +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + +def get_selected_thread(target): + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") + +def get_selected_frame(target): + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") + +def _cmd(cmd): + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + +def move_cursor(line, col=0): + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + +def winnr(): + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + +def bufwinnr(name): + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + +def goto_window(nr): + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + +def goto_next_window(): + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + +def goto_previous_window(): + """ go to previously selected window """ + vim.command("execute \"normal \\p\"") + +def have_gui(): + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + +class PaneLayout(object): + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes = []): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName = None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained = True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains(curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes = []): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) + + +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True + + def prepare(self, method = 'new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer == None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("setlocal nonumber") # Don't display line numbers + #vim.command("setlocal nowrap") # Don't wrap text + + # Set indentation-based folding up + # Based on: + # http://vim.wikia.com/wiki/Folding_for_plain_text_files_based_on_indentation + vim.command("setlocal foldmethod=expr") + vim.command("setlocal foldexpr=(getline(v:lnum)=~'^$')?-1:((indent(v:lnum)'.indent(v:lnum+1)):indent(v:lnum))") + vim.command("setlocal foldtext=getline(v:foldstart)") + vim.command("setlocal fillchars=fold:\ ") + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int( vim.eval("winwidth(0)") ) + self.height = int( vim.eval("winheight(0)") ) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None + + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True + + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None + + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass + + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} + + +class FrameKeyValuePane(VimPane): + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed = False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret + +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ + def __init__(self, owner, name = 'locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = False + self.show_in_scope_only = True + + def format_variable(self, var, indent = 0): + """ Returns a list of tuples of strings "(Type) Name", "Value" for SBValue var + and its children + """ + MAX_DEPTH = 6 + + if indent > MAX_DEPTH: + return [] + else: + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace with ... + val = "..." + + children = [] + if var.GetNumChildren() > 0: + for x in var: + children.extend(self.format_variable(x, indent + 1)) + + return [("%s(%s) %s" % (' ' * indent, var.GetTypeName(), var.GetName()), + "%s" % val)] + children + + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + + out = [] + for v in [self.format_variable(x) for x in vals]: + out.extend(v) + + return out + +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ + def __init__(self, owner, name = 'registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) + + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) + + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ + + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) + + for reg in register_sets: + result.append(self.format_register(reg)) + return result + +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required + + def setCommand(self, command, args = ""): + self.command = command + self.args = args + + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput(self.command, self.args) + return output + +class StoppedCommandPane(CommandPane): + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) + """ + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput(self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + +class DisassemblyPane(CommandPane): + """ Pane that displays disassembly around PC """ + def __init__(self, owner, name = 'disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) + +class ThreadPane(StoppedCommandPane): + """ Pane that displays threads list """ + def __init__(self, owner, name = 'threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") + +# FIXME: the function below assumes threads are listed in sequential order, +# which turns out to not be the case. Highlighting of selected thread +# will be disabled until this can be fixed. LLDB prints a '*' anyways +# beside the selected thread, so this is not too big of a problem. +# def get_selected_line(self): +# """ Place the cursor on the line with the selected entity. +# Subclasses should override this to customize selection. +# Formula: selected_line = selected_thread_id + 1 +# """ +# (thread, err) = get_selected_thread(self.target) +# if thread is None: +# return None +# else: +# return thread.GetIndexID() + 1 + +class BacktracePane(StoppedCommandPane): + """ Pane that displays backtrace """ + def __init__(self, owner, name = 'backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") + + + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 + +class BreakpointsPane(CommandPane): + def __init__(self, owner, name = 'breakpoints'): + super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) + self.setCommand("breakpoint", "list") diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py new file mode 100755 index 0000000..926cc29 --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_signs.py @@ -0,0 +1,73 @@ + +# Classes responsible for drawing signs in the Vim user interface. + +import vim + +class VimSign(object): + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map of defined signs + key = (sign_text, highlight_colour) + if not key in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, + highlight_colour, + highlight_colour)) + vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, + sign_text, + self.highlight_name, + self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + +class BreakpointSign(VimSign): + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + +class PCSign(VimSign): + def __init__(self, buffer, line_number, is_selected_thread): + super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py new file mode 100755 index 0000000..4be346b --- /dev/null +++ b/VimFiles/bundle/lldb/python-vim-lldb/vim_ui.py @@ -0,0 +1,235 @@ + +# LLDB UI state in the Vim user interface. + +import os, re, sys +import lldb +import vim +from vim_panes import * +from vim_signs import * + +def is_same_file(a, b): + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + +class UI: + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) + return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) + return None + + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + #FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) + sys.stderr.write(str(e)) + + return ret + + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True + +global ui +ui = UI() diff --git a/VimFiles/bundle/lldb/vim-lldb.png b/VimFiles/bundle/lldb/vim-lldb.png new file mode 100755 index 0000000..61d0cef --- /dev/null +++ b/VimFiles/bundle/lldb/vim-lldb.png Binary files differ diff --git a/VimFiles/colors/chlordane.vim b/VimFiles/colors/chlordane.vim new file mode 100755 index 0000000..30e9a4e --- /dev/null +++ b/VimFiles/colors/chlordane.vim @@ -0,0 +1,78 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" Name: chlordane.vim +" Maintainer: Kojo Sugita +" Last Change: 2008-08-18 +" Revision: 1.1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'chlordane' + +hi Cursor guifg=#3a553a guibg=#77dd88 +hi lCursor guifg=#3a553a guibg=#77dd88 +hi CursorIM guifg=#3a553a guibg=#77dd88 +hi Directory guifg=#77dd88 guibg=#000000 gui=bold +hi DiffAdd guifg=#77dd88 guibg=#3a553a gui=none +hi DiffChange guifg=#77dd88 guibg=#3a553a gui=none +hi DiffDelete guifg=#223322 guibg=#223322 gui=none +hi DiffText guifg=#77dd88 guibg=#448844 gui=bold +hi ErrorMsg guifg=#ee1111 guibg=#000000 +hi VertSplit guifg=#223322 guibg=#223322 +hi Folded guifg=#55af66 guibg=#000000 +hi FoldColumn guifg=#557755 guibg=#102010 +hi IncSearch guifg=#3a553a guibg=#77dd88 gui=none +hi LineNr guifg=#446644 guibg=#000000 gui=none +hi ModeMsg guifg=#55af66 guibg=#000000 +hi MoreMsg guifg=#55af66 guibg=#000000 +hi Normal guifg=#55af66 guibg=#000000 +hi Question guifg=#55af66 guibg=#000000 +hi Search guifg=#223322 guibg=#55af66 gui=none +hi NonText guifg=#606060 gui=none +hi SpecialKey guifg=#707070 +"\n, \0, %d, %s, etc... +hi Special guifg=#55af66 guibg=#223333 gui=bold +" status line +hi StatusLine guifg=#88ee99 guibg=#447f55 gui=bold +hi StatusLineNC term=bold cterm=bold,underline ctermfg=green ctermbg=Black +hi StatusLineNC term=bold gui=bold,underline guifg=#3a553a guibg=Black +hi Title guifg=#77dd88 guibg=#223322 gui=bold +hi Visual guifg=#77dd88 guibg=#448844 gui=none +hi VisualNOS guifg=#55af66 guibg=#000000 +hi WarningMsg guifg=#77dd88 guibg=#000000 +hi WildMenu guifg=#3a553a guibg=#77dd88 +hi Number guifg=#77dd88 guibg=#354535 +hi Char guifg=#77dd88 guibg=#354535 +hi String guifg=#77dd88 guibg=#354535 +hi Boolean guifg=#77dd88 guibg=#354535 +hi Comment guifg=#446644 +hi Constant guifg=#88ee99 gui=none +hi Identifier guifg=#77dd88 +hi Statement guifg=#88ee99 gui=none + +"Procedure name +hi Function guifg=#77dd88 + +"Define, def +hi PreProc guifg=#77dd88 gui=bold +hi Type guifg=#77dd88 gui=bold +hi Underlined guifg=#77dd88 gui=underline +hi Error guifg=#ee1111 guibg=#000000 +hi Todo guifg=#223322 guibg=#55af66 gui=none +hi SignColumn guibg=#000000 + +if version >= 700 + " Pmenu + hi Pmenu guibg=#222222 + hi PmenuSel guibg=#3a553a guifg=#77dd88 + hi PmenuSbar guibg=#222222 + + " Tab + hi TabLine guifg=#3a553a guibg=black gui=bold + hi TabLineFill guifg=black guibg=black gui=bold + hi TabLineSel guifg=#88ee99 guibg=#447f55 gui=bold +endif + + diff --git a/VimFiles/colors/colors.vim b/VimFiles/colors/colors.vim new file mode 100755 index 0000000..e9e1cb4 --- /dev/null +++ b/VimFiles/colors/colors.vim @@ -0,0 +1,236 @@ +" office-light, a vim colourscheme by nightsense +" +" generated with a theme template adapted from +" base16-vim (https://github.com/chriskempson/base16-vim) +" by Chris Kempson (http://chriskempson.com) + + +"=== SET COLOUR VARIABLES ===================================================== + +" GUI colours +let s:g0 = 'fffff0' +let s:g1 = 'f0f0e1' +let s:g2 = 'b5b5aa' +let s:g3 = '9e9e95' +let s:g4 = '8a8a81' +let s:g5 = '75756e' +let s:g6 = '3b3b37' +let s:g7 = '2b2b29' +let s:g8 = 'f55050' +let s:g9 = 'e06a26' +let s:gA = 'd4ac35' +let s:gB = '219e21' +let s:gC = '1b9e9e' +let s:gD = '468dd4' +let s:gE = 'a26fbf' +let s:gF = 'd46a84' + +" terminal colours +let s:t0 = '10' +let s:t3 = '08' +let s:t5 = '07' +let s:t7 = '15' +let s:t8 = '01' +let s:tA = '03' +let s:tB = '02' +let s:tC = '06' +let s:tD = '04' +let s:tE = '05' +let s:t1 = '10' +let s:t2 = '11' +let s:t4 = '12' +let s:t6 = '13' +let s:t9 = '09' +let s:tF = '14' + +" neovim colours +if has('nvim') + let g:terminal_color_0 = '#fffff0' + let g:terminal_color_1 = '#f55050' + let g:terminal_color_2 = '#219e21' + let g:terminal_color_3 = '#d4ac35' + let g:terminal_color_4 = '#468dd4' + let g:terminal_color_5 = '#a26fbf' + let g:terminal_color_6 = '#1b9e9e' + let g:terminal_color_7 = '#75756e' + let g:terminal_color_8 = '#9e9e95' + let g:terminal_color_9 = '#e06a26' + let g:terminal_color_10 = '#f0f0e1' + let g:terminal_color_11 = '#b5b5aa' + let g:terminal_color_12 = '#8a8a81' + let g:terminal_color_13 = '#3b3b37' + let g:terminal_color_14 = '#d46a84' + let g:terminal_color_15 = '#2b2b29' +endif + + +"=== OTHER PREPARATION ======================================================== + +" clear old theme +hi clear +syntax reset + +" set new theme +set background=light +augroup NightsenseThemeSet + autocmd! + autocmd CursorMoved * execute 'if !exists("colors_name") | + \ colorscheme office-light | endif' +augroup END +let colors_name = 'office-light' + +" highlighting function +fun! h(x, gf, gb, cf, cb, a, s) + if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif + if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif + if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif + if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif + if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif + if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif +endfun + + +"=== BASIC HIGHLIGHTING ======================================================= + +" cursor + status line + selected tab +cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) +cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) + +" line numbers +cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" basic text +cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) +cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) +cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) +cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) +cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) + +" commented-out text +cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) +cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) + +" highlighted background +cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) +cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) +cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) + +" muted text on highlighted background +cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) + +" strongly highlighted background +cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) +cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) + +" selected menu item +cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) +cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) + +" solid lines +cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) +cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) +cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) + + +"=== ALERT/SYNTAX HIGHLIGHTING ================================================ + +" RED for warning elements +cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) +cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) +cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) +cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) +cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) + +" ORANGE for preliminary elements +cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) +cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) +cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) +cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) + +" YELLOW for highlighted elements +cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) +cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) + +" GREEN for action elements +cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) +cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) +cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) + +" TEAL for object types +cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) +cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) +cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) + +" BLUE for constants +cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) +cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) + +" PURPLE for special text +cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) +cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) +cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) + +" PINK for object names +cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) +cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) + + +"=== OPTIONS ================================================================== + +" disable highlighted CursorLineNr +if exists('g:office_light_CursorLineNr') +if g:office_light_CursorLineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) +endif +endif + +" disable LineNr background altogether +if exists('g:office_light_LineNr') +if g:office_light_LineNr == 'off' +cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) +endif +endif diff --git a/VimFiles/colors/obsidian.vim b/VimFiles/colors/obsidian.vim new file mode 100755 index 0000000..a9d9dfa --- /dev/null +++ b/VimFiles/colors/obsidian.vim @@ -0,0 +1,23 @@ +set background=dark +hi clear + +if exists("syntax_on") + syntax reset +endif + +let g:colors_name="obsidian" + +hi PreProc ctermfg=5 cterm=bold +hi cDefine ctermfg=5 cterm=bold +hi cDefined ctermfg=4 cterm=bold +" hi Function ctermfg=1 cterm=bold +hi def cCustomFunc gui=bold guifg=#FF00FF ctermfg=4 cterm=bold +hi StorageClass ctermfg=5 cterm=bold +" hi Type ctermfg=7 cterm=bold +" hi Type ctermfg=5 cterm=bold +hi Type ctermfg=5 cterm=bold +hi cIncluded ctermfg=0 cterm=bold +hi Comment ctermfg=1 +hi Constant ctermfg=1 cterm=bold + + diff --git a/VimFiles/doc/lldb.txt b/VimFiles/doc/lldb.txt new file mode 100755 index 0000000..5a369f8 --- /dev/null +++ b/VimFiles/doc/lldb.txt @@ -0,0 +1,173 @@ +*lldb.txt* A plugin that enables debugging from your favourite editor + + _ ____ ____ + _ __(_)___ ___ / / /___/ / /_ + | | / / / __ `__ \______/ / / __ / __ \ + | |/ / / / / / / /_____/ / / /_/ / /_/ / + |___/_/_/ /_/ /_/ /_/_/\__,_/_.___/ + + LLDB Debugger Ingegration For VIM + +============================================================================== + +CONTENTS *lldb-contents* + + 1. Introduction .................... |lldb-intro| + 2. Getting Started ................. |lldb-start| + 3. Commands ........................ |lldb-commands| + 4. Mappings ........................ |lldb-mappings| + 4. License ......................... |lldb-license| + 5. Bugs ............................ |lldb-bugs| + 6. Contributing .................... |lldb-contributing| + + +Maintainer : Tobias Pflug +Original Author: Daniel Malea +License: Same terms as Vim itself (see |license|) + +INTRODUCTION *lldb-intro* + +The plugin provides an interface to the lldb debugger allowing for +convenient debugging sessions inside your favorite editor including +features such as breakpoints, stepping, watchpoints etc. + +The original plugin can be found here: + +http://llvm.org/svn/llvm-project/lldb/trunk/utils/vim-lldb/ + +Credit for pretty much all current functionality goes to the original +authors. Currently only minor modifications have been made to the +original plugin. + + +GETTING STARTED *lldb-start* + +To quickly get started compile (don't forget to compile with debugging +symbols) and start some program. Then open a source file belonging to the +program in vim and execute ':Lattach .' Then select some +line in the source file and execute ':Lbreakpoint' to set a breakpint at +the current line. + +Once the program reaches the specified breakpoint you will be able to +inspect state and step through the proram using the commands described below. + +COMMANDS *lldb-commands* + +The LLDB command interpreter is exposed to Vim's command mode using the +':L' prefix. Tab-completion is available and will cycle through commands. +Some commands have modified behaviour in Vim; for example, :Lbreakpoint +with no arguments will set a breakpoint at the current cursor, rather than +printing the standard help information for the LLDB command 'breakpoint'. + + *lldb-windows* + +In addition to the standard commands available under the LLDB interpreter, +there are also commands to display or hide informational debugger panes. + +Windows can be shown or hidden using the ':Lhide ' or ':Lshow ' +commands. + *lldb-:Lhide* +:Lhide [windowname] Hide informational debugger pane named 'windowname'. + + *lldb-:Lshow* +:Lshow [windowname] Show informational debugger pane named 'windowname'. + +Possible window name arguments to the Lhide and Lshow commands include: + + * backtrace + * breakpoints + * disassembly + * locals + * registers + * threads + *lldb-:Lattach* +:Lattach Attach to a process by name. + + *lldb-:Ldetach* +:Ldetach Detach from the current process. + + *lldb-:Ltarget* +:Ltarget [[create] executable] + Create a target with the specified executable. If + run with a single argument, that argument is assumed + to be a path to the executable to be debugged. + Otherwise, all arguments are passed into LLDB's command + interpreter. + + *lldb-:Lstart* +:Lstart Create a process by executing the current target + and wait for LLDB to attach. + + *lldb-:Lrun* +:Lrun Create a process by executing the current target + without waiting for LLDB to attach. + + *lldb-:Lcontinue* +:Lcontinue Continue execution of the process until the next + breakpoint is hit or the process exits. + + *lldb-:Lthread* +:Lthread Passes through to LLDB. See :Lhelp thread. + + *lldb-:Lstep* +:Lstep Step into the current function call. + + *lldb-:Lstepin* +:Lstepin Step into the current function call. + + *lldb-:Lstepinst* +:Lstepinst Step one instruction. + + *lldb-:Lstepinstover* +:Lstepinstover Step one instruction, but skip over jump or call + instructions. + + *lldb-:Lnext* +:Lnext Step to the next line. + + *lldb-:Lfinish* +:Lfinish Step out of the current function. + + *lldb-:Lbreakpoint* +:Lbreakpoint [args] When arguments are provided, the lldb breakpoint + command is invoked. If no arguments are provided, + a breakpoint at the location under the cursor. + + *lldb-:Lprint* + *lldb-:Lpo* + *lldb-:LpO* +:Lprint Aliases to the lldb print and po commands. Cursor +:Lpo word (cursor WORD for LpO) will be used when +:LpO expression omitted. + +MAPPINGS *lldb-mappings* + +There are no default mappings defined by the plugin. All commands described +above can be mapped by defining a respective variable: + + let g:lldb_map_Lframe = "f" + +This will map the Lframe command to "f". Other commands can be +mapped accordingly using 'lldb_map_' + . + + +LICENSE *lldb-license* + +Same as Vim itself. + +BUGS *lldb-bugs* + +If you run into a bug use the github issue tracker to report it: +http://github.com/gilligan/vim-lldb/issues/ + +CONTRIBUTING *lldb-contributing* + +If you want to help out you are more then welcome to do so. In fact +I am sure there are plenty of people out there that will do a better +job with this plugin than me. My C skills are more than rusty. I mostly +wanted to make this nice plugin more public and host it in a way in which +it is easy to install with your favorite plugin manager. + +Long story short: Bring on your forks and pull requests. + + vim:tw=78:sw=4:ft=help:norl: diff --git a/VimSetup.rc b/VimSetup.rc index ae53725..4115b50 100644 --- a/VimSetup.rc +++ b/VimSetup.rc @@ -1,4 +1,8 @@ +" Loads bundles +execute pathogen#infect() + + " Make vim behave like vim rather than like vi set nocompatible " set backup @@ -8,6 +12,8 @@ " going to use this until it comes back to bite me... " Amazing - it never did. " +" Implication here is that following a tag to another +" file will write the current file if modified set autowrite " @@ -24,13 +30,22 @@ " Ctrl-E to go back to editing " Ctrl-C to commit working copy " Ctrl-S to list repository status +" Ctrl-L to list current directory " Enter when over item in the list, it opens it map :set splitright \| vnew \| r!svn cat #:windo :diffthis1G map :q! map :!svn commit --editor-cmd vim %:p map :new \| r!svn st `svn info --show-item wc-root` \| sort -r1G +map :new \| r!ls -la1G map $bgf +" Get SVN log on current file: +" map :new \| r!svn log #1G +" Also useful might be being able to load particular revisions +" Or get the diff between revisions +" Or show the blame +" map :new \| r!svn blame #1G + " " Defaults for Bash-Support Vim plugin " @@ -80,22 +95,24 @@ map :cp -" Stuff From wiki - -set ts=2 sw=2 et -" set shiftwidth=4 -" set softtabstop=4 +" Indentation and tab settings set expandtab - +set shiftwidth=2 +set softtabstop=2 +set tabstop=2 " Justin informs me that :0 in your cinoptions is how you prevent the extra indentation on switch statements. "cinoptions=[options],:0 "cinoptions+=:0 -set tags=$BASEDIR/.tags +set tags=./tags; map -map +map +map +" map + +" map bwg] set shiftround set autoindent @@ -153,8 +170,12 @@ " * Keystrokes -- Formatting " have Q reformat the current paragraph (or selected text if there is any): -nnoremap Q gqap -vnoremap Q gq +" nnoremap Q gqap +" vnoremap Q gq + +" Reformats the current function +map Q ]}=% + " have the usual indentation keystrokes still work in visual mode: vnoremap > @@ -227,7 +248,52 @@ " command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell() +function! PrintHelp() + " Now we can just write to the buffer, whatever you want. + call append('$', " ") + call append('$', " John's .vimrc Extensions 1.0 ") + call append('$', " " . split(system('vi --version'),'(')[0] ) + call append('$', ' ' . split(system('uname -v'),':')[0]) + call append('$', " ") + call append('$', " Navigation keys: ") + call append('$', " Ctrl-Q to quit all (without saving) ") + call append('$', " space to follow link under cursor ") + call append('$', " tab to go back in cursor history ") + call append('$', " Ctrl-T to navigate back ") + call append('$', " j / k to page up or down ") + call append('$', " [[ / ]] next/prev code block ") + call append('$', " % move to matching pair ") + call append('$', " Ctrl-I/O fwd/back in cursor history ") + call append('$', " ") + call append('$', " Editing keys: ") + call append('$', " Q reformat the current function ") + call append('$', " ") + call append('$', " Compiling integration: ") + call append('$', " Ctrl-M to execute make ") + call append('$', " Ctrl-N/X to jump to next error ") + call append('$', " Ctrl-P/Z to jump to prev error ") + call append('$', " ") + call append('$', " SVN related integration: ") + call append('$', " Ctrl-D to diff working copy ") + call append('$', " Ctrl-E to go back to editing ") + call append('$', " Ctrl-C to commit working copy ") + call append('$', " Ctrl-S to list repository status ") + call append('$', " Ctrl-L to list current directory ") + call append('$', " Enter to open file from status list ") + call append('$', " ") +endfunction + + function! ShowHelp() + new + call PrintHelp() +endfunction + + +:command Help call ShowHelp() + + +function! ShowOnStartHelp() " Only continue if started without opening a file or anything fancy if argc() || line2byte('$') != -1 || v:progname !~? '^[-gmnq]\=vim\=x\=\%[\.exe]$' || &insertmode return @@ -248,30 +314,7 @@ \ noswapfile \ norelativenumber - " Now we can just write to the buffer, whatever you want. - call append('$', " ") - call append('$', " John's .vimrc Extensions 1.0 ") - call append('$', " " . split(system('vi --version'),'(')[0] ) - call append('$', ' ' . split(system('uname -v'),':')[0]) - call append('$', " ") - call append('$', " Navigation keys: ") - call append('$', " space to follow tag/symbol under cursor ") - call append('$', " tab to follow tag/symbol under cursor ") - call append('$', " Ctrl-Q to quit all (without saving) ") - call append('$', " j / k to page up or down ") - call append('$', " ") - call append('$', " Compiling integration: ") - call append('$', " Ctrl-M to execute make ") - call append('$', " Ctrl-N/X to jump to next error ") - call append('$', " Ctrl-P/Z to jump to prev error ") - call append('$', " ") - call append('$', " SVN related integration: ") - call append('$', " Ctrl-D to diff working copy ") - call append('$', " Ctrl-E to go back to editing ") - call append('$', " Ctrl-C to commit working copy ") - call append('$', " Ctrl-S to list repository status ") - call append('$', " Enter to open file from status list ") - call append('$', " ") + call PrintHelp() " No modifications to this buffer setlocal nomodifiable nomodified @@ -280,12 +323,10 @@ nnoremap e :enew nnoremap i :enew startinsert nnoremap o :enew startinsert - endfunction " Run after doing all the startup stuff -autocmd VimEnter * call ShowHelp() - +autocmd VimEnter * call ShowOnStartHelp() diff --git a/colors.vim b/colors.vim deleted file mode 100644 index e9e1cb4..0000000 --- a/colors.vim +++ /dev/null @@ -1,236 +0,0 @@ -" office-light, a vim colourscheme by nightsense -" -" generated with a theme template adapted from -" base16-vim (https://github.com/chriskempson/base16-vim) -" by Chris Kempson (http://chriskempson.com) - - -"=== SET COLOUR VARIABLES ===================================================== - -" GUI colours -let s:g0 = 'fffff0' -let s:g1 = 'f0f0e1' -let s:g2 = 'b5b5aa' -let s:g3 = '9e9e95' -let s:g4 = '8a8a81' -let s:g5 = '75756e' -let s:g6 = '3b3b37' -let s:g7 = '2b2b29' -let s:g8 = 'f55050' -let s:g9 = 'e06a26' -let s:gA = 'd4ac35' -let s:gB = '219e21' -let s:gC = '1b9e9e' -let s:gD = '468dd4' -let s:gE = 'a26fbf' -let s:gF = 'd46a84' - -" terminal colours -let s:t0 = '10' -let s:t3 = '08' -let s:t5 = '07' -let s:t7 = '15' -let s:t8 = '01' -let s:tA = '03' -let s:tB = '02' -let s:tC = '06' -let s:tD = '04' -let s:tE = '05' -let s:t1 = '10' -let s:t2 = '11' -let s:t4 = '12' -let s:t6 = '13' -let s:t9 = '09' -let s:tF = '14' - -" neovim colours -if has('nvim') - let g:terminal_color_0 = '#fffff0' - let g:terminal_color_1 = '#f55050' - let g:terminal_color_2 = '#219e21' - let g:terminal_color_3 = '#d4ac35' - let g:terminal_color_4 = '#468dd4' - let g:terminal_color_5 = '#a26fbf' - let g:terminal_color_6 = '#1b9e9e' - let g:terminal_color_7 = '#75756e' - let g:terminal_color_8 = '#9e9e95' - let g:terminal_color_9 = '#e06a26' - let g:terminal_color_10 = '#f0f0e1' - let g:terminal_color_11 = '#b5b5aa' - let g:terminal_color_12 = '#8a8a81' - let g:terminal_color_13 = '#3b3b37' - let g:terminal_color_14 = '#d46a84' - let g:terminal_color_15 = '#2b2b29' -endif - - -"=== OTHER PREPARATION ======================================================== - -" clear old theme -hi clear -syntax reset - -" set new theme -set background=light -augroup NightsenseThemeSet - autocmd! - autocmd CursorMoved * execute 'if !exists("colors_name") | - \ colorscheme office-light | endif' -augroup END -let colors_name = 'office-light' - -" highlighting function -fun! h(x, gf, gb, cf, cb, a, s) - if a:gf != '' | exe 'hi ' . a:x . ' guifg=#' . a:gf | endif - if a:gb != '' | exe 'hi ' . a:x . ' guibg=#' . a:gb | endif - if a:cf != '' | exe 'hi ' . a:x . ' ctermfg=' . a:cf | endif - if a:cb != '' | exe 'hi ' . a:x . ' ctermbg=' . a:cb | endif - if a:a != '' | exe 'hi ' . a:x . ' gui=' . a:a . ' cterm=' . a:a | endif - if a:s != '' | exe 'hi ' . a:x . ' guisp=#' . a:s | endif -endfun - - -"=== BASIC HIGHLIGHTING ======================================================= - -" cursor + status line + selected tab -cal h('Cursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('StatusLine' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('StatusLineTerm' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('TabLineSel' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) -cal h('TermCursor' , s:g0 , s:g4 , s:t0 , s:t4 , 'none' , '' ) - -" line numbers -cal h('CursorLineNr' , s:g0 , s:g3 , s:t0 , s:t3 , 'none' , '' ) -cal h('LineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) - -" basic text -cal h('Bold' , '' , '' , '' , '' , 'bold' , '' ) -cal h('Directory' , s:g5 , '' , s:t5 , '' , 'bold' , '' ) -cal h('Italic' , '' , '' , '' , '' , 'italic' , '' ) -cal h('Normal' , s:g5 , s:g0 , s:t5 , s:t0 , 'none' , '' ) -cal h('Underlined' , s:g5 , '' , s:t5 , '' , 'underline' , '' ) - -" commented-out text -cal h('Comment' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('Conceal' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('EndOfBuffer' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('Ignore' , s:g3 , '' , s:t3 , '' , 'none' , '' ) -cal h('NonText' , s:g3 , '' , s:t3 , '' , 'none' , '' ) - -" highlighted background -cal h('ColorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('CursorColumn' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('CursorLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('QuickFixLine' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('StatusLineNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) -cal h('StatusLineTermNC' , s:g5 , s:g1 , s:t5 , s:t1 , 'none' , '' ) -cal h('TabLineFill' , '' , s:g1 , '' , s:t1 , 'none' , '' ) -cal h('TermCursorNC' , '' , s:g1 , '' , s:t1 , 'none' , '' ) - -" muted text on highlighted background -cal h('DiffChange' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('FoldColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('Folded' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('SignColumn' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('TabLine' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -cal h('VisualNOS' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) - -" strongly highlighted background -cal h('MatchParen' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) -cal h('Pmenu' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) -cal h('Visual' , s:g6 , s:g2 , s:t6 , s:t2 , 'none' , '' ) - -" selected menu item -cal h('PmenuSel' , s:g0 , s:g5 , s:t0 , s:t5 , 'none' , '' ) -cal h('WildMenu' , s:g0 , s:g6 , s:t0 , s:t6 , 'none' , '' ) - -" solid lines -cal h('PmenuSbar' , s:g1 , s:g1 , s:t1 , s:t1 , 'none' , '' ) -cal h('PmenuThumb' , s:g4 , s:g4 , s:t4 , s:t4 , 'none' , '' ) -cal h('VertSplit' , s:g2 , s:g2 , s:t2 , s:t2 , 'none' , '' ) - - -"=== ALERT/SYNTAX HIGHLIGHTING ================================================ - -" RED for warning elements -cal h('DiffDelete' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) -cal h('Error' , s:g8 , s:g0 , s:t8 , s:t0 , 'reverse' , '' ) -cal h('ErrorMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) -cal h('SpellBad' , '' , '' , s:t0 , s:t8 , 'undercurl' , s:g8) -cal h('TooLong' , s:g8 , '' , s:t8 , '' , 'none' , '' ) -cal h('WarningMsg' , s:g8 , s:g0 , s:t8 , s:t0 , 'none' , '' ) - -" ORANGE for preliminary elements -cal h('Define' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('IncSearch' , s:g9 , s:g0 , s:t9 , s:t0 , 'reverse' , '' ) -cal h('Include' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('Macro' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('PreCondit' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('PreProc' , s:g9 , '' , s:t9 , '' , 'none' , '' ) -cal h('SpellCap' , '' , '' , s:t0 , s:t9 , 'undercurl' , s:g9) -cal h('Title' , s:g9 , '' , s:t9 , '' , 'none' , '' ) - -" YELLOW for highlighted elements -cal h('DiffText' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) -cal h('Search' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) -cal h('Todo' , s:gA , s:g6 , s:tA , s:t6 , 'reverse' , '' ) - -" GREEN for action elements -cal h('Conditional' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('DiffAdd' , s:gB , s:g0 , s:tB , s:t0 , 'reverse' , '' ) -cal h('Exception' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Keyword' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Label' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('ModeMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('MoreMsg' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Operator' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Question' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Repeat' , s:gB , '' , s:tB , '' , 'none' , '' ) -cal h('Statement' , s:gB , '' , s:tB , '' , 'none' , '' ) - -" TEAL for object types -cal h('SpellLocal' , '' , '' , s:t0 , s:tC , 'undercurl' , s:gC) -cal h('StorageClass' , s:gC , '' , s:tC , '' , 'none' , '' ) -cal h('Structure' , s:gC , '' , s:tC , '' , 'none' , '' ) -cal h('Type' , s:gC , '' , s:tC , '' , 'none' , '' ) -cal h('Typedef' , s:gC , '' , s:tC , '' , 'none' , '' ) - -" BLUE for constants -cal h('Boolean' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Character' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Constant' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Float' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('Number' , s:gD , '' , s:tD , '' , 'none' , '' ) -cal h('String' , s:gD , '' , s:tD , '' , 'none' , '' ) - -" PURPLE for special text -cal h('Debug' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('Delimiter' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('Special' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpecialChar' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpecialComment' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpecialKey' , s:gE , '' , s:tE , '' , 'none' , '' ) -cal h('SpellRare' , '' , '' , s:t0 , s:tE , 'undercurl' , s:gE) -cal h('Tag' , s:gE , '' , s:tE , '' , 'none' , '' ) - -" PINK for object names -cal h('Function' , s:gF , '' , s:tF , '' , 'none' , '' ) -cal h('Identifier' , s:gF , '' , s:tF , '' , 'none' , '' ) - - -"=== OPTIONS ================================================================== - -" disable highlighted CursorLineNr -if exists('g:office_light_CursorLineNr') -if g:office_light_CursorLineNr == 'off' -cal h('CursorLineNr' , s:g4 , s:g1 , s:t4 , s:t1 , 'none' , '' ) -endif -endif - -" disable LineNr background altogether -if exists('g:office_light_LineNr') -if g:office_light_LineNr == 'off' -cal h('CursorLineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) -cal h('LineNr' , s:g4 , s:g0 , s:t4 , s:t0 , 'none' , '' ) -endif -endif diff --git a/vim-setup.sh b/vim-setup.sh index 910dee4..cef0774 100644 --- a/vim-setup.sh +++ b/vim-setup.sh @@ -3,7 +3,8 @@ echo "Assumes you don't have a .vimrc or .bash_profile file already" echo ln -s $PWD/BashProfile.sh ~/.bash_profile echo ln -s $PWD/VimSetup.rc ~/.vimrc -echo mkdir -p ~/.vim/colors -echo ln -s $PWD/colors.vim ~/.vim/colors +echo ln -s $PWD/VimFiles ~/.vim +# echo mkdir -p ~/.vim/colors +# echo ln -s $PWD/colors.vim ~/.vim/colors