# HG changeset patch # User Steve Losh # Date 1297974183 18000 # Node ID 4bd40ce732d70062f57fd5857556b5c182594fe2 # Parent 9bd6d1ef0a9f085cd1b3e95c576577b765f8a4bb vim: lots diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/.vimrc --- a/vim/.vimrc Thu Feb 10 17:11:26 2011 -0500 +++ b/vim/.vimrc Thu Feb 17 15:23:03 2011 -0500 @@ -86,7 +86,7 @@ " }}} " Useful Abbreviations -------------------------------------------------------- {{{ -iabbrev lkdis ಠ_ಠ +iabbrev ldis ಠ_ಠ " }}} " Searching and Movement ------------------------------------------------------ {{{ @@ -113,13 +113,15 @@ nnoremap n nzz nnoremap N Nzz -vnoremap < >gv - nnoremap L $ vnoremap L $ onoremap L $ +nnoremap Ëš :lnext +nnoremap ¬ :lprevious +inoremap Ëš :lnext +inoremap ¬ :lprevious + " Directional Keys {{{ " Why stretch? @@ -164,7 +166,7 @@ let line = substitute(line, '\t', onetab, 'g') let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount)) - let fillcharcount = windowwidth - len(line) - len(foldedlinecount) - 4 + let fillcharcount = windowwidth - len(line) - len(foldedlinecount) return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' ' endfunction " }}} set foldtext=MyFoldText() @@ -209,11 +211,17 @@ au BufNewFile,BufRead *.html imap . au BufNewFile,BufRead *.html nnoremap vitavitoi " }}} +" CSS {{{ +au BufNewFile,BufRead *.css setlocal foldmethod=marker +au BufNewFile,BufRead *.css setlocal foldmarker={,} +au BufNewFile,BufRead *.css nnoremap cc ddko +au BufNewFile,BufRead *.css nnoremap S ?{jV/^\s*\}?$k:sort:noh +au BufNewFile,BufRead *.css inoremap { {}.kA +" }}} " LessCSS {{{ au BufNewFile,BufRead *.less setlocal filetype=less au BufNewFile,BufRead *.less setlocal foldmethod=marker au BufNewFile,BufRead *.less setlocal foldmarker={,} -au BufNewFile,BufRead *.less setlocal nocursorline au BufNewFile,BufRead *.less nnoremap cc ddko au BufNewFile,BufRead *.less nnoremap S ?{jV/^\s*\}?$k:sort:noh au BufNewFile,BufRead *.less inoremap { {}.kA @@ -238,6 +246,11 @@ " Vim {{{ au FileType vim setlocal foldmethod=marker " }}} +" Python {{{ +au Filetype python noremap rr :RopeRename +au Filetype python vnoremap rm :RopeExtractMethod +au Filetype python noremap ri :RopeOrganizeImports +" }}} " Django {{{ au BufNewFile,BufRead urls.py setlocal nowrap au BufNewFile,BufRead urls.py normal! zR @@ -328,15 +341,12 @@ let g:microdata_attributes_complete = 0 let g:atia_attributes_complete = 0 " }}} -" Rope and Bike {{{ -let g:bike_exceptions=1 -source $HOME/.vim/sadness/sadness.vim - +" Rope {{{ let ropevim_enable_shortcuts = 0 let ropevim_guess_project = 1 -noremap rr :RopeRename -vnoremap rm :RopeExtractMethod -noremap roi :RopeOrganizeImports +let ropevim_global_prefix = 'p' + +source $HOME/.vim/sadness/sadness.vim " }}} " Gundo {{{ nnoremap :GundoToggle @@ -449,56 +459,25 @@ endfunction " }}} " }}} -" Diff ------------------------------------------------------------------------ {{{ - -let g:HgDiffing = 0 +" Open quoted ----------------------------------------------------------------- {{{ +nnoremap :OpenQuoted +command! OpenQuoted call OpenQuoted() +function! OpenQuoted() " {{{ + let @r = '' -function! s:HgDiffCurrentFile() " {{{ - if g:HgDiffing == 1 - if bufwinnr(bufnr('__HGDIFF__')) != -1 - exe bufwinnr(bufnr('__HGDIFF__')) . "wincmd w" - bdelete - endif + exe 'normal! vi' . "'" . '"ry' - diffoff! - - let g:HgDiffing = 0 - - return + if len(@r) == 0 + exe 'normal! i' . '"' . '"ry' endif - let fname = bufname('%') - let ftype = &ft - diffthis - - vnew __HGDIFF__ - - setlocal buftype=nofile - setlocal bufhidden=hide - setlocal noswapfile - setlocal nobuflisted - exec 'setlocal filetype='.ftype - - setlocal modifiable + if len(@r) == 0 + exe 'normal! "ry' + let @r = '' + endif - silent normal! ggdG - silent exec ':r!hg cat ' . fname - silent normal! ggdd - - setlocal nomodifiable - - diffthis - - wincmd l - - let g:HgDiffing = 1 - - return + exe "silent !open ." . @r endfunction " }}} - -command! HgDiffCurrent call s:HgDiffCurrentFile() -nmap d :HgDiffCurrent - " }}} " MacVim ---------------------------------------------------------------------- {{{ diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/colors/molokai.vim --- a/vim/colors/molokai.vim Thu Feb 10 17:11:26 2011 -0500 +++ b/vim/colors/molokai.vim Thu Feb 17 15:23:03 2011 -0500 @@ -68,8 +68,9 @@ hi Question guifg=#66D9EF hi Repeat guifg=#F92672 gui=bold hi Search guifg=#FFFFFF guibg=#455354 + " marks column -hi SignColumn guifg=#A6E22E guibg=#1B1D1E +hi SignColumn guifg=#A6E22E guibg=#151617 hi SpecialChar guifg=#F92672 gui=bold hi SpecialComment guifg=#465457 gui=bold hi Special guifg=#66D9EF guibg=bg gui=italic @@ -93,7 +94,7 @@ hi Type guifg=#66D9EF gui=none hi Underlined guifg=#808080 gui=underline -hi VertSplit guifg=#808080 guibg=#080808 gui=bold +hi VertSplit guifg=#AAAAAA guibg=#151617 gui=none hi VisualNOS guibg=#403D3D hi Visual guibg=#403D3D hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/ftplugin/python/folding.vim --- a/vim/ftplugin/python/folding.vim Thu Feb 10 17:11:26 2011 -0500 +++ b/vim/ftplugin/python/folding.vim Thu Feb 17 15:23:03 2011 -0500 @@ -64,7 +64,7 @@ let line = substitute(line, '\t', onetab, 'g') let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount)) - let fillcharcount = windowwidth - len(line) - len(foldedlinecount) - 4 + let fillcharcount = windowwidth - len(line) - len(foldedlinecount) return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' ' endfunction diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/AUTHORS --- a/vim/sadness/bike/AUTHORS Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -Authors -------- - -Phil Dawes - Current Maintainer - and Main Author -Shae Erisson - Original Maintainer - - -The following people have contributed code, bugfixes and patches: - -Jürgen Hermann -Canis Lupus -Syver Enstad Windows emacs patches -Mathew Yeates VIM support and bug fixes -Marius Gedminas More VIM support -François Pinard Pymacs + help with - emacs integration -Ender -Jonathan -Steve -Peter Astrand - -See ChangeLog for more details. - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/COPYING --- a/vim/sadness/bike/COPYING Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -COPYRIGHT AND PERMISSION NOTICE - -Copyright (c) 2000 by Shae Erisson -Copyright (c) 2001 by Phil Dawes - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, and/or sell copies of the Software, and to permit persons -to whom the Software is furnished to do so, provided that the above -copyright notice(s) and this permission notice appear in all copies of -the Software and that both the above copyright notice(s) and this -permission notice appear in supporting documentation. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL -INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING -FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, use -or other dealings in this Software without prior written authorization -of the copyright holder. - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ChangeLog --- a/vim/sadness/bike/ChangeLog Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2034 +0,0 @@ -2004-02-18 Phil Dawes - - * bike/query/getTypeOf.py: Added feature to - resolveImportedModuleOrPackage that searches the package hierarchy - of the scope even if it isn't in the pythonpath. - -2004-02-11 Phil Dawes - - * bike/query/getTypeOf.py: rewrote resolveImportedModuleOrPackage - to use purely getModuleOrPackageUsingFQN searches. (doesnt use - getTypeOf Root searching any more) - - * bike/query/common.py: rewrote getLogicalLine to handle - multilines that parse seperately. (But was submitted by Peter - Astrand) - -2004-02-10 Phil Dawes - - * bike/query/getTypeOf.py: Added functionality to search from the - current directory if looking for an import and scope is a module - -2004-02-10 Phil Dawes - - * bike/refactor/moveToModule.py: Added handling of individual - 'from a.foo import theFunction'. - - * bike/parsing/fastparserast.py: Added Peter Astrand's patch to - fix following bug: - 'Find-References (and probably others) fails if there is more - whitespace than a single space between the "class"/"def" keyword - and the class/def name.' - - * bike/query/common.py: fixed bug in just-written-code where no - dest in Printnl causes npe. - - * bike/query/common.py: Fixed a bug in MatchFinder. Printnl ast - nodes (print >>foo, bah) look at there children the opposito way - to the way the text comes. (i.e. they do visit(bah), visit(foo) in - the example above). Wrote code to get round this. - -2004-02-09 Phil Dawes - - * bike/refactor/moveToModule.py: added more functionality to - moveFunction - - * bike/bikefacade.py: added expanduser to normalizeFilename so - that ~/src/foo gets turned into a proper full path. - - * bike/bikefacade.py: exposed moveClassToNewModule. - - * bike/refactor/moveClass.py: started move-class-to-new-module - refactoring. - -2004-02-05 Phil Dawes - - * bike/parsing/pathutils.py: new module containing all the - functions that search all the files in the pythonpath. - - * bike/parsing/extended_ast.py: Removed this module. SourceFile is - now in load.py, the rest is in fastparserast.py - - * ide-integration/BicycleRepairMan_Idle.py : Added patch from - Steve to allow easier saving of files - before refactoring in IDLE - -2004-02-04 Phil Dawes - - * bike/parsing/extended_ast.py: lots of cleanup. Renamed Source - class to SourceFile. Slimmed down Package and Root. Am planning on - removing this module completely, and moving the classes into other - modules. - - - * bike/refactor/extractVariable.py: refactored and removed - extractLocalVariable_old - - * bike/refactor/extractMethod.py: refactored and removed - extractMethod_old - - * bike/refactor/test_rename*.py: Removed the 'rename twice' - tests. They are no longer applicable (since BRM saves to disk - after each refactoring) - - * bike/transformer/: Moved save.py and undo.py into the - transformer package - - * bike/parsing/newstuff.py: moved generatePackageDependencies into - the parsing package, because it needs to be used by other modules - in the parsing package. - -2004-02-03 Phil Dawes - - * bike/query/relationships.py: Added generatePackageDependencies - which given a file in a package hierarchy, yields a list of - external packages and modules used by the package. - - * bike/parsing/newstuff.py: Rewrote - generateModuleFilenamesInPythonPath wrt new ref search scheme. - Scheme: If the module you are searching from is in a package - hierarchy, scan every module in the hierarchy, and the files in - the directory above it (since they can reach the package without - including it in PYTHONPATH). - If the module is in a non-package directory, search in all files - in the directory, and in any packages below that directory. - N.B. this is in addition to directories in the PYTHONPATH. - -2004-02-02 Phil Dawes - - * bike/parsing/newstuff.py: Removed getRegexMatchesInPythonPath - - * bike/parsing/newstuff.py: Modified getSourceNodesContainingRegex - to search the pythonpath + the set of python files in the - directory above the root package of the current file. This should - remove the requirement to add the root directory to the python - path, and thus prevent BRM from finding references in other - package structures. - - * bike/query/common.py: Removed scanASTSourceNodesForMatches and walkSourceNodes - - * bike/globals.py: Added True/False declaration for python 2.2 - back-compatibility. - -2004-01-26 Phil Dawes - - * bike/query/common.py: Added code to check for \ in a previous - line when locating logical lines - -2004-01-25 Phil Dawes - - * bike/query/common.py: Added a test and fixed a bug that meant - find-definitions from multiline statements wouldn't work if the - braces were equalised on the following line. - (thanks again to Detlev for reporting this bug) - -2004-01-14 Phil Dawes - - * bike/query/common.py: Added a test and fixed a bug that meant - find-definitions from multiline statements wouldn't work. - (thanks to Detlev for reporting this bug) - -2004-01-12 Phil Dawes - - * bike/parsing/load.py: Added Detlevs patch to not recurse into - subversion directories. - -2004-01-11 Phil Dawes - - * bike/parsing/newstuff.py: Added code in - generateModuleFilenamesInPythonPath to ensure each filename is - generated once. (and added test to check for it) - (Thanks to Detlev & Syver for this bug report) - - * bike/query/common.py (globalScanForMatches): Removed old - ast-based code from globalScanForMatches - -2004-01-08 Phil Dawes - - * bike/query/getTypeOf.py: Fixed bug where 'from foo import aou' - would cause an assert to fail if foo didn't exist. (Thanks Syver) - -2004-01-06 Phil Dawes - - * bike/bikefacade.py: Added code to normalize paths coming into - BRM. (hopefully fixes Syver's problems on windows - Thanks Syver) - - -2003-09-04 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Fixed bug in - Bicyclerepair_idle. - ------------------------ 0.9 BETA4 ------------------------------- - -2003-09-02 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Fixed bug where brmctx - was being tested for a __nonzero__ operator due to new wrapper - stuff. - Also made the matches window a singleton - - * bike/query/findReferences.py: Rewrote attribute reference - finding algorithm to locate a possible match, and then check if - the match class shares a common ancestor with the target. (rather - than finding all classes in the target hierarchy and then testing - each match class against the hierarchy). - This results in a 10000% - -2003-09-02 Phil Dawes - - * bike/query/relationships.py: Added buildClassHierarchy - functionality to guess a class hierarchy, but found that it's - still much too slow to handle the wxpython class hierarchy of 1900 - odd classes under 1 root! - - -2003-09-01 Phil Dawes - - * bike/parsing/fastparserast.py: Added maskedsrc to the cache - - * bike/query/getTypeOf.py: Added caching of type lookups - - * bike/bikefacade.py: Added a generic wrapper which purges the - caches before and after each brm ctx call - -2003-08-31 Phil Dawes - - * bike/parsing/newstuff.py: Added simple caching mechanism for - sourceNodes - -2003-08-30 Phil Dawes - - * bike/parsing/extended_ast.py: Removed some crufty methods and - base classes for managing the ast tree hierarchy - - * bike/bikefacade.py: Removed a couple of ast related methods - - * bike/query/findReferences.py: Modified the findRefs - functionality to exclude matches where the confidence is high that - it's *not* the right type. - - * bike/parsing/load.py: removed the load function (and made - necessary refactorings to remove it) - -2003-08-25 Phil Dawes - - * bike/bikefacade.py: Added setWarningLogger - -2003-08-25 Phil Dawes - - * bike/parsing/extended_ast.py: Fixed bug where "../.." was being - added to sys.path. This was because extended_ast.py was adding - importing setpath.py. - -2003-08-25 Phil Dawes - - * bike/bikefacade.py: Added warning code to print message if - sys.path is changed by setpath.py - - * ide-integration/test/README: Added ide tests for inline and - extract variable - - * bike/bikefacade.py: Removed the load() function, and fixed - inline and extract local variable - ------------------------ 0.9 BETA3 ------------------------------- - -2003-08-22 Phil Dawes - - * bike/bikefacade.py: Fixed removeLibdirsFromPath to work with - windows python lib directories - ------------------------ 0.9 BETA2 ------------------------------- - -2003-08-21 Phil Dawes - - * bike/*: Made it backward compatible with python 2.2 - - * ide-integration/bike.vim: Adapted vim plugin to work with new - api. - ------------------------ 0.9 BETA1 ------------------------------- - -2003-08-20 Phil Dawes - - * bike/test_*: Misc fixes for windows paths - - * ide-integration/BicycleRepairMan_Idle.py: Cleaned up error - handling for undo stack - - * bike/query/*: Misc fixes for tests - - * bike/refactor/extractMethod.py: Updated to work with new - non-tree system - -2003-08-19 Phil Dawes - - * bike/testutils.py: Converted createSourceNodeAt to create a - directory structure rather than an ast. (and broke a load of tests) - -2003-08-18 Phil Dawes - - * bike/testutils.py: added test setup fixture to change directory - before executing tests - -2003-08-17 Phil Dawes - - * bike/query/getTypeOf.py: Fixed bug which was stopping sub - packages from being found properly - - * bike/query/relationships.py: Fixed getAllClassesInHierarchy and - getAllDerivedClasses to work without AST. Uses a smart algorithm - which scans the text of files with regexes for baseclassnames and - import aliases to narrow down the likely candidates. - - -2003-08-12 Phil Dawes - - * README.idle: Updated docs for python2.3/idlefork - -2003-08-11 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Added code to just use - 1 window for matches, and to reopen it if needed after it is closed - -2003-08-04 Phil Dawes - - * bike/parsing/load.py: Fixed bug which cause BRM to descend into - non-package directorys - - * bike/parsing/extended_ast.py: Added a couple of new functions to - handle pythonpaths for queries and refactorings - -2003-08-01 Phil Dawes - - * bike/query/common.py: modified globalScanForMatches to scan - files in addition to walking the ast. - - * bike/query/findReferences.py: Added code to work with new - stateless design. - -2003-07-31 Phil Dawes - - * bike/query/findDefinition.py: Removed module locating code from - findDefinition, and made it use resolveImportedModuleOrPackage - instead. - - * bike/query/getTypeOf.py: Modified resolveImportedModuleOrPackage - to use the newstuff function getModuleOrPackageUsingFQN if it cant - locate the module in the AST tree. - - * bike/parsing/newstuff.py: modified getModuleUsingFQN - to handle packages. renamed to getModuleOrPackageUsingFQN - -2003-07-25 Phil Dawes - - * bike/query/findDefinition.py: Made necessary modifications - enable finding of function definitions without importing code - (uses the python path to determine where to look). Doesnt work for - methods yet. - -2003-07-10 Phil Dawes - - * bike/refactor/inlineVariable.py: Applied Jonathan's patch which - fixes bug when multiple instances of a variable are on one line. - -2003-06-12 Phil Dawes - - * bike/query/findReferences.py: changed findReferences interface - to take a filename instead of a srcnode - - * bike/query/findReferences.py: Fixed bug where error wasnt being - reported properly - -2003-06-11 Phil Dawes - - * bike/query/findReferences.py: renamed findReferences to - findReferences_old, and created a new findReferences which takes a - filename instead of the srcnode - - * bike/bikefacade.py: Removed getFullyQualifiedNameOfScope - it's - not used anywhere, and relies on the fqn stuff working. - - * all tests: attempted to remove all usage of fqn from - tests. Instead, replaced with name and filename tests. This is - because fqn is one of the major things binding the scopes - together. - - * bike/bikefacade.py: removed getTypeOfExpression. It's not used - anywhere. Will reinstate when it is required again. - - * bike/query/getTypeOf.py: Fixed bug where a recursive function - could cause BRM to stack overflow - -2003-06-10 Phil Dawes - - * bike/query/getTypeOf.py: Added resolveImportedModuleOrPackage fn - to try and split the number of calls to getTypeOf() - - * bike/query/getTypeOf.py: Fixed bug where a[0].theMethod() would - cause brm to barf. - - * bike/parsing/fastparserast.py: Beefed up the __str__ members for - fastparser nodes - -2003-06-06 Phil Dawes - - * bike/parsing/output.py: Removed output.py. (functionality now in - save.py) - -2003-06-05 Phil Dawes - - * bike/refactor/extractMethod.py: removed the ismodified stuff, in - an attempt to make the xast hierarchy a read-only resource. - Added a hook in save.py to update the xast whenever somebody - queues an update to be saved. - - * bike/parsing/save.py: Added new save module which maintains its - own queue of src to be written back to disk. Replaces output.py - -2003-05-30 Phil Dawes - - * bike/parsing/undo.py (UndoStack.undo): refactored to use dictionary - - * bike/query/findDefinition.py: Refactored main function to have a - 'stateless' interface (i.e. no need to pass a context). - findAllPossibleDefinitionsByCoords(filepath,lineno,col) - -2003-05-29 Phil Dawes - - * bike/parsing/extended_ast.py (getRoot): Made the Root object a - singleton. Use the getRoot() method to get it. This is an - intermediate step in making the parser stateless. (idea is to make - it pretend to be stateless by being a singleton, then once the - interfaces have changed, transition the parser code to actually - make it stateless) - -2003-04-02 Phil Dawes - - * ide-integration/bikeemacs.py: Added exception catching and error - reporting to bike-emacs integration - -2003-03-31 Phil Dawes - - * Applied Jonathan's patches - - InlineVariable handles multiline statements - - Fix to bike vim integration - -2003-03-31 Marius Gedminas - - * ide-integration/bike.vim: Removed unnecessary argument - to BikeRename(). - - * bike/query/common.py: Fixed handling of lambdas in MatchFinder. - -2003-03-17 Phil Dawes - - * bike/refactor/extractVariable.py: Made a start on the - extract-local-variable refactoring - -2003-03-13 Phil Dawes - - * bike/refactor/inlineVariable.py: Made a start on the - inline-local-variable refactoring - ------------------------ 0.8 BETA2 ------------------------------- - -2003-03-11 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Fixed bug where - paths with spaces meant that you couldn't select a reference when - doing a findReferences. (Thanks to Andy Bulka for the report) - - * bike/query/getTypeOf.py: Added infinite recursion protection to - getTypeOf - - * bike/query/relationships.py: Added some performance improving - code when searching for a classhierarchy. Rather than doing a - getTypeOf() on every base class, it finds the strings likely to be - base classes (i.e. the name of the base class, and any 'import - name as foo' lines) to narrow the search. - -2003-03-10 Phil Dawes - - * bike/refactor/extractMethod.py: Fixed bug in extract method, - where blank lines were messing up the indentation in the resultant - block - - ------------------------ 0.8 BETA1 ------------------------------- - -2003-03-10 Phil Dawes - - * ide-integration/bikeemacs.py: Fixed bug in brm with emacs on - windows, where the mark can be active and nil at the same time. - - * bike/bikefacade.py (BRMContext_impl.load): Fixed bug which - affected windows users. Path needs to be saved after it's been - normalized. - -2003-03-06 Phil Dawes - - * bike/query/findDefinition.py: fixed bug in attribute finding - code - was only searching the first function - - * bike/query/getTypeOf.py: Fixed bug where x = x.bah() would cause - recursion error. (just catches the stack overflow) - -2003-03-05 Phil Dawes - - * bike/*: implemented automatic importing of changed files. This - means that ide integration stuff no longer has to import code into - brm whenever it is saved. - -2003-02-25 Phil Dawes - - * ide-integration/bike.vim: Consolidated RenameMethod, - RenameFunction and RenameClass into 1 menu option. This is because - brm now supports renaming of variables and attributes and I didn't - want to add another 2 menu items. - - -2003-02-24 Phil Dawes - - * ide-integration/bikeemacs.py: Fixed rename 'prompt' - bug. Consolidated all the rename stuff into 1 menu option. - -2003-02-19 Phil Dawes - - * bike/query/*: removed getReferencesToClass/Function/Method and - replaced with findReferences - -2003-02-13 Phil Dawes - - * bike/query/findReferences.py: Added findReferencesIncludingDefn - and made 'vanilla' findReferences not return the definition. This - paves the way for a unified rename that can be used to rename - anything. - -2003-02-11 Phil Dawes - - * bike/query/findDefinition.py: Fixed bug reported by Marius - if - class is declared in __init__.py, it blows up. - - * bike/query/findReferences.py: Fixed bugs in - 'getDefinitionAndScope' logic, so can handle nested classes etc.. - -2003-02-10 Phil Dawes - - * bike/query/getReferencesToClass.py: Replaced module logic - with call to findReferences() - - * tests: modified or removed tests that tested for the erroneous - 'import a.b.bah.TheClass'. (A class or function can't be imported - - only a module) - -2003-01-24 Marius Gedminas - - * ide-integration/bike.vim: Show the line itself after finding - references/definition. - -2003-01-23 Marius Gedminas - - * bike/query/common.py: Fixed a trivial NameError in - MatchFinder.visitGlobal(). - -2003-01-23 Phil Dawes - - * bike/query/getTypeOf.py: Refactored and cleaned up the code in - this module. - -2003-01-22 Marius Gedminas - - * bike/query/common.py: Fixed another ValueError, this time on - "from foo import bar" lines. - -2003-01-20 Marius Gedminas - - * bike/query/common.py, bike/query/findDefinition.py, - bike/query/findReferences.py: Fixed ValueError: list.index(x): x not - in list" error caused by several visitFunction methods visiting - their child nodes (argument names and default values) out-of-order. - -2003-01-16 Marius Gedminas - - * bike/refactor/extractMethod.py: Now puts spaces after commas in - generated code. - -2003-01-15 Marius Gedminas - - * ide-integration/bike.vim: Better load failure diagnostics. - -2003-01-14 Marius Gedminas - - * bike/bikefacade.py, bike/parsing/fastparserast.py, - ide-integration/BicycleRepairMan_Idle.py: CRLF -> LF translation - -2003-01-13 Marius Gedminas - - * bike/bikefacade.py: Added a function to check whether a given file - was ever imported. - - * bike/test_bikefacade.py: Unit test for the above. - - * ide-integration/bike.vim: Added code to watch for modified files - and reimport them into if they had been imported previously. - -2003-01-13 Phil Dawes - - * bike/query/getReferencesToModule.py: Added Ender's - getReferencesToModule module (and test module) - -2003-01-10 Phil Dawes - - * bike/query/findDefinition.py: Added some find class attribute - definition functionality - -2003-01-09 Phil Dawes - - * bike/query/findDefinition.py: fixed bug where 'import' - statements in fn scopes weren't being searched - - * ide-integration/bike.vim: Modified Marius' bike.vim vi - integration to support new rename and findReferences calls. - -2003-01-06 Phil Dawes - - * ide-integration/bikeemacs.py: Added fix to redisplay frame in - emacs, and to test for mark correctly in emacs. - -2003-01-05 Phil Dawes - - * AUTHORS: Added Mathew and Marius - -2003-01-03 Phil Dawes - - * README.emacs: Added simple instructions for installing pymacs. - - * ide-integration/Pymacs-0.20: I'm going to ship pymacs-0.20 with - bicyclerepairman. I've modified it a little to make installation - easier. - - * ide-integration/bikeemacs.py: Moved bikeemacs back to its - original place. - - -2003-01-02 Phil Dawes - - * bike/parsing/extended_ast.py: Cleaned this up a bit - - * bike/parsing/fastparser.py: Fixed bug reported by Mathew Yeates - where more than one space between 'class' and the name foxed the - parser. - -2002-12-22 Phil Dawes - - * bike/query/findReferences.py: Started work on unified - findReferences code. (uses findDefinition to compare matches) - - * ide-integration/emacs/bikeemacs.py: Rewrote emacs integration - using the excellent pymacs package - -2002-12-09 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Fixed findDefinition - cosmetic bug - - * ide-integration/bike.el, bikeemacs: Added Syver Enstad's patch - for allowing filenames with spaces - -2002-12-06 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Completed support for - findDefinition - - * ide-integration/bike.el: added code to handle the fact that if - you select a region, the point is one greater than the end of the - region and so misses it. - -2002-12-03 Phil Dawes - - * bike/query/findDefinition.py: Added code to scan for other - method matches after locating the 100% one - -2002-12-02 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Added basic - finddefinition support to idle - - * ide-integration/bikeemacs.py: Added finddefinition support to xemacs - - * bike/bikefacade.py: Exposed findDefinition through bikefacade - - * bike/query/findDefinition.py: Added new query interface for - finding the definition of a reference, given its line/col position - in a module. Just supports function, method, and class references - for now. - ----------------------- 0.7 --------------------------------------- - -2002-11-27 Phil Dawes - - * ide-integration/bike.el: Fixed bug where saving buffers caused - the new emacs protocol to get in a tangle. My solution was to add - a disableMessages capability - ----------------------- 0.7RC3 ------------------------------------ - -2002-11-22 Phil Dawes - - * ide-integration/bikeemacs.py: Added acknowledgement protocol, to - get round synchronisation problems in windows emacs - -2002-11-20 Phil Dawes - - * bike/parsing: decommissioned addtypeinfo, typeinfo, tokenutils, - tokenhandler, matchTokensToAST, doublelinkedlist, testdata - - * bike/query/getReferencesToClass.py: Fixed bug where - 'from foo import *' would cause an exception if searching for a - class called 'foo' - - * bike/*/test_*.py: Removed dependency on brmtransformer. - -2002-11-15 Phil Dawes - - * bike/refactor/extractMethod.py: Rewrote extract method module to - use all the new cool stuff (and operate or strings). Doesnt use - linked lists, iterators, tokens, brmtransformer or any of that - shite any more. - -2002-11-11 Phil Dawes - - * bike/query/getTypeOf.py: Fixed bug where classscope was being - searched if the name wasnt found in methodscope. This is incorrect - because class scope isn't visible except through 'self' or a fully - qualified classname. - -2002-11-10 Phil Dawes - - * bike/query/common.py: Re-wrote MatchFinder to scan along the - source code text when visiting ast nodes. This removes the need to - match tokens in order to find the source code location of an ast - node. - ----------------------- 0.7RC1 ------------------------------------ - - -2002-11-01 Phil Dawes - - * bike/query/relationships.py: Added performance enhancement to - getAllDerivedClasses. Now does string search on file before ast - searching the classes. - -2002-10-30 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Finished - findReferencesByCoordinates support in idle. - -2002-10-29 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Added trace - console. Started integration of findReferencesByCoordinates into - idle. - - * ide-integration/bike-emacs.py: Added xemacs support for - getFullyQualifiedNameOfScope, getTypeOfExpression and - findReferencesByCoordinates - - -2002-10-28 Phil Dawes - - * bike/bikefacade.py: Added getFullyQualifiedNameOfScope, - getTypeOfExpression and findReferencesByCoordinates - -2002-10-08 Phil Dawes - - * bike/bikefacade.py: changed promptForRename callback signature - to be linenumbers and columnnumbers - - * bike/refactor/renameMethod.py: Added prompt - functionality. - -2002-10-02 Phil Dawes - - * bike/query/getTypeOf.py: Added functionality to handle scanning - for types of references (needed by getReferencesToMethod) - - * bike/query/getReferencesToMethod.py: Implemented to use - common.py stuff - -2002-09-30 Phil Dawes - - * bike/query/common.py: Split out common query code into common.py - -2002-09-27 Phil Dawes - - * bike/refactor/renameFunction.py: Now uses the getReferences stuff - -2002-09-26 Phil Dawes - - * bike/transformer/WordRewriter.py: Split this class out of the - renameClass module. - - * bike/transformer: Added new transformer package to contain code - which rewrites the internal representation of the sourcecode - - * bike/bikefacade.py: Implemented locateNode to use the new - fastparserast stuff. - - * bike/parsing/extended_ast.py: Added code to set fqn (fully - qualified name) attributes on the fastparser ast - -2002-09-25 Phil Dawes - - * bike/refactor/renameClass.py: Finished modification to use - getReferencesToClass. - -2002-09-06 Phil Dawes - - * bike/query/getTypeOf.py: Refactored getType() functionality out - of ast classes and into a query module. - - * bike/parsing/fastparser.py: Added parsing of import and from - lines to fastparser, and optimised a little. - -2002-09-04 Phil Dawes - - * bike/refactor/renameClass.py: Started modification to use - getReferencesToClass. - -2002-08-30 Phil Dawes - - * bike/query/getReferencesToClass.py: New module which returns a - sequence of references to a class - - * bike/parsing/fastparser.py: Wrote new parser which builds a tree - of functions and classes, very quickly. - -2002-08-14 Phil Dawes - - * bike/parsing/tokenutils.py: Fixed bug where attempting to - tokenize small strings would result in attributeerror - -2002-08-05 Phil Dawes - - * bike/logging.py: Logging module. Eventually will be replaced by - import logging, but for now is a copy of the code by Vinay Sajip - (to save people from having to download the module) - - * bike/parsing/brmtransformer.py: Added simple fix - tuple being - concatinated to list was causing problems - - ----------------------- 0.6.7 ------------------------------------ - -2002-07-31 Phil Dawes - - - * ide-integration/BicycleRepairMan_Idle.py: Added Canis fix for - the bug which stopped brm from displaying the menu when starting - idle via right-click file. - - * bike/bikefacade.py: Added Canis windows compatability fix for - dealing with .pyw files - - -2002-07-25 Phil Dawes - - * bike/refactor/extractMethod.py: Fixed bug where extracting an - expression from a line just below a block opener (e.g. if foo:) - would cause a parse error. - -2002-07-21 Phil Dawes - - * README.idle: Doc about problems on windows - ----------------------- 0.6.6 ------------------------------------ - -2002-07-19 Phil Dawes - - * bike/parsing/doublelinkedlist.py: Optimised to use a list rather - than a class instance for each link element. - -2002-07-17 Phil Dawes - - * bike/parsing/typeinfo.py: Fixed bug - package wasn't checking - parent packages (and Root) for types. This meant that modules - imported from higher up the tree weren't being found. - - * bike/parsing/extended_ast.py: Renamed 'Top' to 'Root' - ----------------------- 0.6.5 ------------------------------------ - -2002-07-15 Phil Dawes - - * ide-integration/bike.el: Minor bug fix - -2002-07-12 Phil Dawes - - * ide-integration/bikeemacs.py: Added code so that it waits for - buffer to be reloaded in emacs before sending the request to - update the next one. - - * ide-integration/bike.el: Added bug fix - if prompt for rename - was on file not loaded, emacs would send a message back to brm - when it ran find-file, which buggered up the 'rename-this-method?' - interaction. - -2002-07-11 Phil Dawes - - * ide-integration/bike.el: Added support for GNU emacs - - * README.emacs: renamed from README.xemacs - - * - -2002-07-09 Phil Dawes - - * bike/bikefacade.py: Added code to handle more windows filename - brokenness - -2002-07-05 Phil Dawes - - * bike/refactor/renameMethod.py: Added same optimisation to - renameMethod. - - * bike/refactor/renameClass.py: Added optimisation: source string - is scanned for classname before visiting ast. (with the lazy ast - creation this means that files aren't parsed unless they contain - the keyword (or are linked to the source via function call). - - * bike/parsing/extended_ast.py: Refactored .source member into - .getSource() method and implemented so that tokens are - synchronised with source if they're modified. - -2002-07-03 Phil Dawes - - * bike/parsing/extended_ast.py: Added lazy parsing of ast when - source.getModule() is called. - - * bike/parsing/typeinfo.py: Added PackageTypeInfo which deduces - child types by interrogating the package rather than relying on - children to register themselves in the typeinfo. This was required - to facilitate lazy parsing of ast. (since parse would have had to - be done to add module node to package). A lookup of a module now - causes getModule() to be called on the sourcefile, thus triggering - parse of source into ast. - ----------------------- 0.6.4 ------------------------------------ - -2002-06-27 Phil Dawes - - * bike/parsing/tokenutils.py: Added bug fix for superflous - brackets. Basically, if brackets are unecessary (e.g. '(a).foo()') - then they aren't in the parse tree but are in the token - stream. This buggers up the token matching. - This fix just ignores unmatching ')'s. It was the simplist thing - that could possibly work, but may cause problems later - needs - lots of testing. - ----------------------- 0.6.3 ------------------------------------ - -2002-06-26 Phil Dawes - - * bike/parsing/tokenhandler.py: Fixed bug where getattr renamed - all occurences of the methodattr in the rest of the tokens - -2002-06-21 Phil Dawes - - * bike/refactor/extractMethod.py: Fixed bug where commend before - the extracted block would make brm think it should be extracting - an expression rather than a block. - - * bike/parsing/addtypeinfo.py: Fixed the same bug in _getImportedType - - * bike/refactor/renameClass.py: Fixed bug where the module search - routine in the 'From foo import *' code was using the parent scope - as the search position. This doesnt work if 'from' is nested in a - class since parent scope is a module, not a package. Added method - _getParentPackage() to handle this correctly. - -2002-06-13 Phil Dawes - - * bike/refactor/extractMethod.py: Fixed the 'loop' bug. extract - method will now recognise variables assigned to by the extracted - function and used in a loop by the calling function. - -2002-06-12 Phil Dawes - - * bike/refactor/extractMethod.py: Lots of refactoring prior to - fixing a bug. - -2002-06-10 Phil Dawes - - * bike/parsing/doublelinkedlist.py: Rewrote 'insert' so that it - doesnt move the iterator. Renamed old method to - insertAndPositionIteratorOnNewElement. - -2002-06-07 Phil Dawes - - * bike/refactor/extractMethod.py: Fixed the parse error when - extracting code from an if...else... block. The problem was that - the code below the extraction contained the 'else', but not the - 'if'. This is hacked around by inserting an 'if 1: - pass'. This seems to work, but I welcome a better way of handling - this. - - * bike/parsing/output.py: Added code to ensure that indent never - dips below 0. This fixes a bug in parsing during method extracts - out of nested blocks. - - * bike/refactor/extractMethod.py: Fixed the 'don't know what type - this isAssAttr(Name('item'), 'decl', 'OP_ASSIGN')' bug - ----------------------- 0.6 -------------------------------------- - -2002-05-28 Phil Dawes - - * ide-integration/test/*: Added manual test script for testing ide - integration before a release - - * ide-integration/BicycleRepairMan_Idle.py: Now imports code into - brm when loaded, or saved for the first time. - - * ide-integration/bike.el: Now imports all loaded python files - into brm. Also checks to see if file was just updated to avoid - superflous reloads. - -2002-05-27 Phil Dawes - - * ide-integration/bike.el: Added menu for brm - - * bike/parsing/undo.py: Added an internal undo buffer size - - * ide-integration/BicycleRepairMan_Idle.py: Added generic - exception reporting to idle - - * ide-integration/bikeemacs.py: Added generic exception - reporting. All exceptions are handled and reported back to the - user. - -2002-05-24 Phil Dawes - - * ide-integration/BicycleRepairMan_Idle.py: Exposed undo to idle - - * ide-integration/bikeemacs.py: Exposed undo to emacs - - * bike/bikefacade.py: Exposed undo functionality to facade - - * bike/parsing/undo.py: Added undo functionality - -2002-05-15 Phil Dawes - - * bike/refactor/test_extractMethod.py: Fixed bug in expression - extracting code (which caused a parse exception with correct code) - - * bike/bikefacade.py: Added public interface - ----------------------- 0.5 -------------------------------------- - - * ide-integration: Created new directory for integration modules - -2002-05-14 Phil Dawes - - * bike/ui/BicycleRepairMan_Idle.py: Exposed extract function to idle - - * bike/ui/bikeemacs.py: Exposed extract function to emacs - - * bike/refactor/extractMethod.py: Added support for extracting - expressions into methods (e.g. a = 1+2 -> a = self.oneplustwo()) - Added support for extracting functions. - -2002-05-13 Phil Dawes - - * bike/refactor/extractMethod.py: Extract Method pretty much - finished. Now on with the testing... - -2002-05-03 Phil Dawes - - * bike/ui/BicycleRepairMan_Idle.py: Added extract method support - for idle - -2002-05-02 Phil Dawes - - * bike/ui/bike.el: implemented extract-method for emacs - - * bike/bikefacade.py: Exposed extract-method to the outside world - - -2002-05-01 Phil Dawes - - * bike/refactor/extractMethod.py: Implemented simple extract - method - -2002-04-28 Phil Dawes - - * bike/parsing/matchTokensToAST.py: The 'new' addtokens. Instead - of each AST node getting its own slice of tokens, there is only - one token list and each node has 2 linked list iterators pointing - to the start and end of its tokens in within it. - Thus the process of calculating the position of these iterators is - now called 'token matching' rather than 'adding tokens to ast'. - - Having only 1 token stream vastly simplifies things. There are no - consistency problems when renaming or moving tokens, and no need - to 'divide' the comments amongst the AST nodes. - This enables one matching algorithm to be able to cater for all - ast nodes without specialized logic. - - * bike/parsing/vector.py, bike/parsing/doublelinkedlist.py: - containers which support the same bi-directional iterator - interface. Used in refactoring the parsing module to use a linked - list of tokens - -2002-04-12 Phil Dawes - - * bike/bikefacade.py: Removed use of tokens - ----------------------- 0.4.3 ------------------------------------ - -2002-04-11 Phil Dawes - - * bike/ui/BicycleRepairMan_Idle.py: fixed import problem in - windows - - * bike/parsing/load.py: Added code so that if you select a - directory it will load all the modules and packages in it even if - it isnt a package (i.e. doesnt have a __init__.py), but would - recurse into non-package sub directories. - - * bike/ui/*: This is no longer a package, since the only 2 files - are installed elsewhere. - - * setup.py: Made BicycleRepairMan_Idle.py a root level - module. This means it can be used with idle by just adding - [BicycleRepairMan_Idle] to your .idle file. - - -2002-04-06 Phil Dawes - - * bike/parsing/addtokens.py: Addtokens class now takes tokens in - constructor. The addTokens function is renamed to - addTokensToASTFromSrc. This will pave the way for Source nodes to - hold tokens rather than the source as a string - - * bike/parsing/tokenhandler.py: Fixed bug which caused name ast - node to not be tokenized - - * bike/parsing/load.py: Added check for __init__.py before - recursing into sub directories. This means that non-package sub - directories will not be recursed into. (i.e. the user must load - those seperately) - - -2002-03-29 Phil Dawes - - * NEWS: consolidated all README-version files into one NEWS file - - * README*: updated documentation - - * bike/ui/BicycleRepairMan_Idle.py: Fixed another windows filename - isnt normalized bug - - * bike/ui/bike.el: Added same functionality as for idle - - * bike/ui/BicycleRepairMan_Idle.py: Added load on save - functionality - means each saved python file gets automatically - imported into bicyclerepairman. - -2002-03-27 Phil Dawes - - * bike/parsing/load.py: Added functionality to deduce the package - of the loaded module/package by inspecting parent directories for - __init__.py modules. This allows adding of new modules to an - existing AST. - -2002-03-24 Phil Dawes - - * README.idle: Added Evelyn's ammendment to doc - ----------------------- 0.4.2 ------------------------------------ - -2002-03-23 Phil Dawes - - * setup.py: Removed Icons stuff from setup - - * bike/ui/BicycleRepairMan_Idle.py: Fixed some bugs with idle - integration in windows: - - Ask if should rename dialogs dont take focus (which - makes selection disappear in windows) - - Filename normalizing means that filenames get compared correctly. - -2002-03-21 Phil Dawes - - * bike/testutils.py: Changed the test package structure generation - code to add __init__.py modules to the packages. This will be used - to work with the new loader code (when I write it). - -2002-03-20 Phil Dawes - - * bike/ui/BicycleRepairMan_Idle.py: Fixed bug which was stopping - changed files from being reloaded on windows - ----------------------- 0.4.1 ------------------------------------ - -2002-03-19 Phil Dawes - - * bike/ui/BicycleRepairMan_Idle.py: Fixed bug where rename method - prompts weren't visible to the user. - - * bike/parsing/addtypeinfo.py: Fixed a bug which meant that - sourcenode wasnt getting added to default arguments, which caused - brm to crash when attempting to tokenize these. - - ----------------------- 0.4 -------------------------------------- - -2002-03-18 Phil Dawes - - * setup.py: Removed bikegui and pyxmi from the setup - program. These are now deprecated. - - * bike/ui/BicycleRepairMan_Idle.py: Added the idle support module - to cvs. - - * bike/parsing/tokenhandler.py: Simplified SimpleTokenHandler - - * bike/parsing/extended_ast.py: Removed ExtendedNode base class - - it isnt needed (thanks Evelyn) - - * bike/parsing/tokenutils.py: fixed bug in - _getOffsetOfTokensCorrespondingToParseTree which was including the - NL token in the offset it returned. - - * bike/bikefacade.py: Changed signature of rename method - callback. It now sends filename and coords as args rather than - exposing the ast nodes to the client. - -2002-03-07 Phil Dawes - - * bike/__init__.py: Moved bikefacade.py (from the ui package) into - the bike package. This is now referenced from __init__.py so a - client can do: - import bike; ctx = bike.load("mypath"); ctx.renameMethod() - - - * bike/parsing/typeinfo.py: ModuleTypeinfo.getTypeOf() - functionality now uses the imported module *name* to check other - modules, rather than a reference to the module itself. This is to - allow module reloading. - - * bike/parsing/extended_ast.py: Added 'addtypeinfo' call to Source - node. This is now done when the sourcenode is added to the parent - node rather than being run once over the whole tree. This - facilitates adding additional trees to the ast without having to - run the whole addtypeinfo step again. - - * bike/parsing/addtypeinfo.py: Removed the subclasses stuff from - the classtypeinfo functionality. Doing this at initial-parse time - is too brittle, since a reload of a child source node could remove - (or add) a subclass from a base class. - Instead, subclasses are calculated at refactoring time. - - - -2002-03-07 Phil Dawes - - * bike/parsing/addtypeinfo.py: Removed addfqn, - addparentscopeToNode and addSourcenode to nodes functionality from - the SourceModule, and integrated them with the first 'addtypeinfo' - pass. This almost halves the initial parsing time. - - -2002-03-04 Phil Dawes - - * bike/refactor/renameMethod.py: Changed renameMethod signature to - take a method fqn rather than class and method parameters. This - allows the tests to take advantage of the same signature for - renameMethod,renameFunction and renameClass. - - * bike/ui/bikeemacs.py: refactored to use the new bikefacade module - - * bike/ui/bikefacade.py: New module which provides easy interface - into brm, for integrating into IDEs. - - * bike/parsing/test_addtypeinfo.py: Added recursion handling for - things like a=a() (just catches the runtime error) - -2002-02-28 Phil Dawes - - * bike/parsing/addtypeinfo.py: found a problem with lambdas - they - take the reference from the outer scope. If the reference is a - loop variable (e.g. for i in blah) then it is reassigned which - knackers the closure. - Solution - lambda i=i: doSomethingWith(i) - - * bike/ui/bikegui.py: removed reliance on tokens - - * bike/parsing/tokenhandler.py: added getStartCoords() and - getEndCoords() functions. - - -2002-02-27 Phil Dawes - - * */setpath.py: code which insures pythonpath includes path - to the bike module (used for running test scripts). This is - imported by most modules. - - * bike/parsing/extended_ast.py: moved addParentScopeToNodes() - functionality from addtypeinfo into Source class. - - * bike/parsing/addtypeinfo.py: For deduced types (e.g. types got - from function calls), the closure of the type deducing function is - put in the typeinfo rather than the type itself. The closure is - then run at lookup. - This facilitates lazy loading, and means source modules can be - reloaded without invalidating the typeinfo objects. - -2002-02-18 Phil Dawes - - * bike/ui/bikeemacs.py: Added reload source functionality - - * bike/ui/bike.el: Added support for renameMethod - prompts user - for types that brm can't deduce - -2002-02-06 Phil Dawes - - * bike/ui/bikeemacs.py: New support for emacs - - * bike/parsing/addtypeinfo.py: Fixed bug which was causing - inheritance specs not to be renamed - - * bike/parsing/output.py: Added some code to preserve level of - indent in multiline (comma ended) statements (e.g. function - arguments, class inheritence args etc...). This really needs - reworking into a general solution, but works 70% of the time for - now. - -2002-01-31 Phil Dawes - - * bike/parsing/output.py: Added comment indenting code which - should preserve the indent level of comments - -2002-01-28 Phil Dawes - - * bike/refactor/renameClass.py: Added functionality to rename the - function and class ref in 'import a.b.theFunction and from a - import theClass' type statements - - * bike/parsing/renameFunction.py: new refactoring - - * bike/parsing/tokenhandler.py: Added code to update the typeinfo - objects of the parent scope and the Top node. This enables renames - to be carried out more than once on the same ast - - * bike/parsing/addtypeinfo.py: Removed node.typeinfo.fqn. refactor - code should now use node.fqn - -2002-01-25 Phil Dawes - - * bike/parsing/tokenhandler.py: Added token functionality to - Name. Removed the getPreceedingTokens() stuff - the getTokens() - now returns all tokens including preceeding comments, tokens - etc... getNodeTokens() returns just the tokens associated with the - node. This is consistent across all the tokenhandler base classes. - - * bike/parsing/tokenutils.py: Fixed bug in _appendTokens where - the src 'raise foo' would result in 'raise' being picked up when - searching for 'foo' because both tokens are of the same type (name). - -2002-01-24 Phil Dawes - - * bike/parsing/addtokens.py: Added code to class tokenizer to - delegate tokens to the baseclass spec (i.e. bah in - 'class foo(bah):'). - - * bike/parsing/tokenhandler.py: Class handler stuff to output - tokens (see above). This means that renameClass now renames class - refs in baseclass specs. - -2002-01-23 Phil Dawes - - * bike/refactor/renameMethod.py: Fixed a bug which stopped classes - that inherited from classes not in the ast from having method - declarations renamed. - -2002-01-22 Phil Dawes - - * bike/parsing/output.py: Added support for handling line breaks. - i.e. if foo and \ - bah: - - * bike/refactor/renameClass.py: Started new refactoring - - renameClass - - * bike/parsing/addtypeinfo.py: removed 'typing indirect recursive - functions causes stack overflow' bug - - * bike/refactor/renameMethod.py: Refactored the code so that the - renameMethodReferences is done once, with a list of all the - classes (in the hierarchy) to match. - - -2002-01-21 Phil Dawes - - * bike/refactor/renameMethod.py: Now renames methods on all - related classes (base classes and sub classes). - - * doc/*: added some html documentation - -2002-01-19 Phil Dawes - - * bike/refactor/renameMethod.py: Did some major refactoring and - removed all the code which is functionally duplicated in the - addtypeinfo module. - - * bike/parsing/addtypeinfo.py: Spruced up the type inference - stuff. - ModuleTypeInfo now handles from foo import * by storing a list of - other modules to search. - -2002-01-17 Phil Dawes - - * bike/parsing/output.py: Save now returns a list of the files modified - -2002-01-16 Phil Dawes - - * bike/parsing/extended_ast.py: Added lazy tokenization. Source - node now parses the source (rather than being handed the ast). - -2002-01-15 Phil Dawes - - * bike/parsing/output.py: Added lazy saving. Files are only saved - if source modified. - - * bike/testutils.py: Added new utility to find an ast node in a - tree based on attributes of the node. - e.g. getMatchingASTNode(ast,"Function",name="foo") - -2002-01-14 Phil Dawes - - * bike/refactor/renameMethod.py: Added functionality to look for - method and ref renames in sub classes - -2002-01-11 Phil Dawes - - * bike/parsing/addtypeinfo.py: Added support for imports, import - from and import as statements - -2002-01-09 Phil Dawes - - * bike/parsing/tokenutils.py: Fixed bug where method call was - split over 2 lines. The problem is that the tokenlist contains the - NL, but the parsetree doesnt, so the matching wasnt working. See - addtokens test_doesntBarfWhenMethodCallSplitOverTwoLines for details. - - * bike/parsing/brmtransformer.py: Added 2 classes which override - Print and Println, and return the child nodes in the desired order - (they are the wrong way round as they come out of - ast.py). The print_stmt method returns these. - - * bike/parsing/output.py: Added code to handle spacing with commas - and stream operators - -2002-01-08 Phil Dawes - - * bike/refactor/test_renameMethod.py: Refactored tests so that - BikeGUI can use them (through template method). Tests are now - split into RenameMethodTests, - RenameMethodReferenceTests_ImportsClass and - RenameMethodReferenceTests_doesntImportClass. This is because - bikegui - -2002-01-07 Phil Dawes - - * bike/ui/bikegui.py: Added dialog to ask user if want to rename - method reference (for cases where the type engine can't deduce the - type of the instance) - -2002-01-04 Phil Dawes - - * bike/ui/bikegui.py: Added a simple gui for renameMethod - -2002-01-03 Phil Dawes - - * bike/parsing/load.py: Added functionality to strip of preceeding - directories from package structures. (so if you load - '/usr/local/python2.2/compiler', the root package is 'compiler') - - * bike/parsing/load.py: Added load_readonly(), which doesn't do the - addtokens step. - Also added code to enable load() to be called more than once, to - add new files and packages to the tree. - Moved ui messages into constants module - -2002-01-02 Phil Dawes - - * bike/parsing/brmtransformer.py: removed addTokens() step from - parse(), so that it must be called seperately. This is because it - isn't complete, and imposes quite a performance penalty. (and it's - not needed by pyxmi). Updated all the tests to reflect this. - -2002-01-01 Phil Dawes - - * bike/parsing/addtypeinfo.py : Added getSubClasses() - functionality to class typeinfo. - -2001-12-30 Phil Dawes - * bike/*: Fixed path bugs for windows platform. All tests run on - win32 python now. - -2001-12-29 Phil Dawes - - * bike/parsing/addtypeinfo.py: Added 'self' type to function - typeinfo. This means renameMethod can handle self.theMethod() - automatically. - -2001-12-28 Phil Dawes - - * pyxmi: Wrote little tool to create xmi representation of python - code. Suitable for loading into argouml. - - * bike/ui/bikecli.py: Added progress meter support. (also in - addtokens.py, renameMethod.py, load.py and output.py - -2001-12-26 Phil Dawes - - * bike/refactor/renameMethod.py: Fixed bug where function call - returning instance resulted in crash. 'e.g. e().f()' - -2001-12-24 Phil Dawes - - * bike/parsing/addtokens.py: Reworked addtokens scheme to 'get all - tokens for node, and then pass them to children to take their - nodes'. This makes for a much easier time processing tokens. - -2001-12-16 Phil Dawes - - * bike/parsing/tokenhandler.py: Changed Getattr rename - functionality to work when attribute token isn't second token of - node tokenlist - - * bike/refactor/test_renameMethod.py: refactored renameMethod - tests into generic abstract base class. These are now used by the - ui package (rather than vice versa) - - * bike/ui/bikecli.py: Added code to tell you how many changes have - been made, and advice on what might be wrong if this number is 0. - -2001-12-15 Phil Dawes - - * bike/parsing/tokenhandler.py: Added getNodeTokens() - implementation to miss out any preceeding cruft not picked up by - addtoken functionality on previous nodes. - -2001-12-14 Phil Dawes - - * bike/refactor/renameMethod.py: Changed renameMethodDefinition to - work with nested methods (utilising the new typeinfo.fqn stuff). - Removed findclass and findmethod. - -2001-12-12 Phil Dawes - - * bike/ui/bikecli.py: Modified prompt message a bit. Added actual - standard io stuff so that it works with a user input as well as - through the test harness. - - * bike/refactor/renameMethod.py: Modified RenameMethodReferences - to create a stack of scopes. The code uses the typeinfo from each - scope to determine the type of references, and if it can't find - the type there, it checks its own references deduced from the - classname passed in. I.e. it assumes that the classname is a - class, even if it can't find the definition, and renames instances - derived from it. - - Also ammended the 'prompt user callback' code to only ask the user - if the type engine doesnt know the type of the instance - expression. (before now it was prompting if the type was not the - same as the input classname) - -2001-12-11 Phil Dawes - - * bike/ui/bikecli.py: Added code to handle prompting the user for - whether the method reference should be renamed. - - * bike/refactor/renameMethod.py: Added code to prompt user when - type of object instance isn't known - -2001-12-08 Phil Dawes - - * bike/refactor.py: now takes advantage of typeinfo stuff to - deduce types of references - -2001-12-03 Phil Dawes - - * bike/parsing/addtypeinfo.py: New classes to deduce the types of - references. Adds a typeinfo attribute to each scope ast node, - which maps reference names to their types (currently as strings). - -2001-11-26 Phil Dawes - - * bike/refactor/renameMethod.py: Added stack to maintain - references to object instances while visiting package structure - -2001-11-25 Phil Dawes - - * bike/refactor/renameMethod.py: Added support for 'from foo - import *' - - * bike/ui/test_bikecli.py: Refactored tests so that all the single - file tests are exercised in a package hierarchy context. - -2001-11-24 Phil Dawes - - * bike/refactor/renameMethod.py: Added support to rename methods - based on imported classes - -2001-11-23 Phil Dawes - - * bike/refactor/renameMethod.py: Refactored code (took out - RenameMethod class, since wasnt using instance state). Added - support for compound references (a.b.c.foo) - -2001-11-21 Phil Dawes - - * bike/parsing/load_application.py: removed. (see load.py instead) - - * bike/refactor/renameMethod.py: Added support for fully qualified - classnames in _findClass. e.g. a.b.bah.foo. This means that the ui - now supports renaming package nested methods (but not their - references). - -2001-11-20 Phil Dawes - - * bike/parsing: Added fixes to parser module to reflect changes in - python 2.2 compiler module - -2001-11-16 Phil Dawes - - * bike/parsing/output.py: new function 'save' saves an entire ast - tree - - * bike/refactor/renameMethod.py: Adapted to take an ast rather - than source file - -2001-11-14 Phil Dawes - - * bike/parsing/load.py: Replacement for load_application.py using - Juergen's pythius loader code. load() hierarchically loads a bunch - of packages and modules into a big AST. - - * bike/parsing/extended_ast.py: Fleshed out Package and Top nodes - to support hierarchical module ast - - -2001-11-08 Phil Dawes - - * bike/parsing/load_application.py: Fixed import visitor code to - handle comma seperated imports. (i.e. import foo,bar). Added code - to recognise imports via a from clause (i.e. from foo import bar) - - Removed Imports.py. Integrated code into load_application - - -2001-11-06 Phil Dawes - - * bike/parsing/load_application.py: Added load_application and - Imports modules back into build. Started writing tests for them. - - -2001-11-05 Phil Dawes - - * bike/parsing/brmtransformer.py : Rewrote this to override the - methods which create nodes at the root of the parse. This means - that a few methods adding parser nodelists to ast nodes should - cater for practically all the AST nodes. - - * bike/parsing/tokenhandler.py (GetattrTokenHander.renameAttr): - added renameAttr method which renames the attribute in the object - state, and in the corresponding tokens. This is a very brittle - implementation, but will be fixed as new functionality is - added. (it's the simplist thing right now) - - * bike/parsing/addtokens.py (AddTokens.visitGetattr): added - token support for getattr - - * bike/parsing/tokenutils.py: Added getTokensPreceedingNodes, - which takes a parsetree of nodes and returns all the tokens before - the node represented by the parsetree. This is important because - until there is an token-handling implementation of all the ast - nodes, some tokens will be missed. By eating the tokens in between - the implemented ast nodes, this ensures all the tokens will be - outputted at the end. - - -2001-10-30 Phil Dawes - - Created new CVS module, which makes use of distutils much more - uniform. - - * setup.py: Created distutils setup stript: - -2001-10-25 Phil Dawes - - * parsing/output.py: Code to handle spacing in inline comments - - * refactor/renameMethod.py: Started code to handle references when - object is created in same scope - - -2001-10-24 Phil Dawes - - * parsing/output.py: spaces in conditionals (a == b etc..) - - * parsing/tokenutils.py: Refactored code in TokenList to handle - rearranging indent/dedent tokens so that whole-line comments are - indented with the things they comment. The transformations are now - done after the initial scan (slower, but easier to follow) - - -2001-10-23 Phil Dawes - - * parsing/output.py: ensured a.b not seperated by spaces. - - -2001-10-22 Phil Dawes - - * parsing/output.py: Code to seperate a=b with spaces (a = b) - - * ui/test_cli.py: Merged cli tests with renameMethod tests to - ensure all tests work through the cli - -2001-10-19 Phil Dawes - - * */testall.py: unified testing scripts so that all tests can be - run from one place - -2001-10-15 Phil Dawes - - * ui/cli.py: Added simple command line interface. - -2001-10-14 Phil Dawes - - * parsing/output.py: Finished simple ast->string functionality - -2001-10-13 Phil Dawes - - * testall.py: added master test script - - * parsing/tokenhandler.py (FunctionTokenHandler.rename): added - rename a function and keep tokens in sync functionality - - -2001-10-12 Phil Dawes - - * parsing/output.py: started tokens -> string functionality - -2001-10-07 Phil Dawes - * refactor/renameMethod.py: very basic findClass, findMethod - functionality. Needs refactoring into analysis package, and - merging with existing code - -2001-10-05 Phil Dawes - - * refactor/simplediff.py: wrote a simple diff utility to support - writing top down tests. (i.e. do a renameMethod, then assert that - the diff is correct) - - -2001-10-04 Phil Dawes - - * refactor/renameMethod.py: Got fedup with trying to secondguess - what the parser module should do. Decided to do some top-down - proper XP style development. Started with implementing the - renameMethod story. - -2001-10-01 Phil Dawes - - * parsing/test_addtokens.py: refactored tests so that they use - brmtransformer to get a node, rather than mocking it. - -2001-09-29 Phil Dawes - - * parsing/brmtransformer.py: Added nodelist to pass_stmt - -2001-09-28 Phil Dawes - - * parsing/addtokens.py (AddTokens.visitModule): finished method - - * parsing/tokenutils.py - (TokenConverter.getTokensUptoLastNewlineBeforeCode): method added - -2001-09-27 Phil Dawes - - * parsing/addtokens.py: started visitmodule() impl - - * parsing/extended_ast.py: Added tokens support to Module - -2001-09-26 Phil Dawes - - * parsing/test_addtokens.py Refactored tests. Made up better names. - -2001-09-25 Phil Dawes - - Laptop broke. Continuing with an older version of the code (hence - the gap in changelog) - - * parsing/tokenutils.py (TokenConverter.getTokensToColon): Added - function which just gobbles tokens to the next colon. Refactored - getTokensStartBlock() to use this instead of walking the nodelist, - since I think all - - * parsing/addtokens.py (AddTokens.visitFunction): Now that - function and class no longer need to pass in partial nodelists, - the code is common. Refactored common code into - visitCompoundNode(). - - (hence the gap in the changelog) - - * parsing/tokenhandler.py: removed the preceeding tokens code - - you ain't gonna need it! - - * parsing/test_addtokens.py: changed visitclass tests to use - mockobjects - -2001-09-10 Phil Dawes - - * parsing/tokenhandler.py: - - * parsing/*: Integrated code with bike parsing package - - Split tokenhandler base classes into seperate module - Merged brmast stuff into extended_ast package - - -2001-09-08 Phil Dawes - - * test_tokenutils.py: Added more unit tests - -2001-09-06 Phil Dawes - - * test_tokenutils.py: Added more unit tests - - -2001-09-04 Phil Dawes - - * test_addtokens.py: Added some mock objects and tests - -2001-08-31 Phil Dawes - - * test_tokenutils.py: beefed up the unit tests a bit - -2001-08-29 Phil Dawes - - * brmtransformer.py: This module now just contains code to add the - nodelist member to each ast node as the compiler generates - it. This is so the code in addtokens has access to the original - python parser nodes to generate tokens from. - - * addtokens.py: Moved the code to add the tokens to the ast nodes - to this module. It now relies on there being a 'nodelist' member - on each ast object, containing the original python parser - nodelist. - - * brmast.py: Added hack to retrofit TokenHandler base class to - existing compiler.ast classes. This means that we no longer have - to include compiler classes with the distribution. - Not sure if this is completely legal - doesn't work with jython. - - Removed stock Python compiler classes from src tree. - - -2001-08-27 Phil Dawes - Set about reimplementing the token stuff - will now add tokens to - ast objects *after* the nodes have been processed by the compiler - module. - -2001-08-22 Phil Dawes - - * tokenutils.py: Added support for tokenising strings as well as - files. - - * test_tokenutils.py: removed testdata directory, and moved all - the testdata into this module, now that the tokenutils stuff can - take strings as well as files - - * brmtransformer.py: Renamed TransformerWithTokens to Transformer, - now that it's in a seperate module. - - * brmast.py: Refactored the added token code out of ast module - into this one. Created a seperate mixin called TokenHandler rather - than sticking this code in the Node base class. Each class now - re-inherits this baseclass. - Unfortunately this means that I had to modify the transformer.py - file to import brmast rather than ast. Need to think of a better - way of doing this. - -2001-08-21 Phil Dawes - - * brmtransformer.py: Created new brmtransformer module and - refactored token code from transformer.Transformer into seperate - class TransformerWithTokens. Refactored common code from - funcdef() and classdef() into do_compound_stmt() - - * transformer.py: Now that all new code is factored out, reverted - to original transformer module from Python-2.1/Tools/compiler. - - * tokenutils.py: Added code to alter DEDENT token line numbers - when they are rearranged - -2001-08-19 Phil Dawes - - * tokenutils.py: Added code to do token reordering to ensure that - comments immediately before a block of code are placed after the - previous block DEDENT token. - -2001-08-15 Phil Dawes - - * transformer.py: tidied up code, and released prototype - -2001-08-14 Phil Dawes - - * ast.py: Refactored management of tokens into base Node - class. Removed code from Class, and moved node->token conversion - to transformer.py - - * transformer.py: See above - -2001-08-13 Phil Dawes - - * ast.py: Added support for tokens in 'Class' nodes. 'Class' uses - nodes passed to convert to tokens using TokenConverter. - - -2001-08-10 Phil Dawes - - * tokenutils.py: Started TokenConverter class to convert python - parser nodes to tokens. - - * test_tokenutils.py: unit tests for above - ------------------- One year later... ------------------------- - - -2000-10-21 19:02 gwilder - - * context.py, refactor/.cvsignore, refactor/NewClass.py, - refactor/Refactor.py, refactor/__init__.py: - - first refactoring: NewClass - -2000-10-21 18:56 gwilder - - * kickstand/: test_HasFromStar.py, test_IsClass.py, - test_IsGlobal.py, test_all.py, test_context.py, - test_load_application.py, testdata/HasFromStar_tf1.py, - testdata/HasFromStar_tf2.py, testdata/IsGlobal_tf1.py, - testdata/load_application_tf1.expected, - testdata/load_application_tf1.py, - testdata/rf_addclass_tf1.expected, testdata/rf_addclass_tf1.py: - - more tests - -2000-10-21 18:55 gwilder - - * analysis/: HasFromStar.py, IsClass.py, IsGlobal.py, - Superclasses.py, TODO: - - more analysis functions - -2000-10-21 18:38 gwilder - - * parsing/: .cvsignore, Imports.py, README, TODO, __init__.py, - extended_ast.py, load_application.py: - - parse and load a whole app. - -2000-10-13 19:32 gwilder - - * INSTALL, analysis/.cvsignore, analysis/IsClass.py, - analysis/IsGlobal.py, analysis/README, analysis/TODO, - analysis/__init__.py, assembly/genpy.py, kickstand/test_IsClass.py, - kickstand/test_IsGlobal.py, kickstand/test_all.py, - kickstand/testdata/.cvsignore, kickstand/testdata/IsClass_tf1.py, - kickstand/testdata/IsGlobal_tf1.py: - - new analysis functions; install instructions; testsuite additions. - -2000-09-28 00:59 eris - - * .cvsignore, CHANGES, README, assembly/.cvsignore, - disassembly/.cvsignore, kickstand/.cvsignore, - kickstand/test_common.py, kickstand/treefailtest.py, - kickstand/treematchtest.py, kickstand/unequalvars.py, - sprocket/.cvsignore, sprocket/common.py, sprocket/common.txt: - - - added .cvsignore files in each dir got the unit test for - sprocket/common.py working, added files for that test. - -2000-09-06 01:21 jhermann - - * CHANGES, INSTALL, README, TODO: - - Added administrative files - -2000-09-05 22:13 jhermann - - * assembly/__init__.py, disassembly/__init__.py, - kickstand/__init__.py, sprocket/__init__.py: - - Made the inits non-empty - -2000-09-05 22:11 jhermann - - * __init__.py: - - Minor correction - -2000-09-01 18:33 jhermann - - * kickstand/__init__.py, kickstand/test_fsm.py, - kickstand/test_regast.py, sprocket/__init__.py, sprocket/common.py, - sprocket/fsm.py, sprocket/regast.py: - - Initial source checkin (2000-09-01) - -2000-09-01 18:26 jhermann - - * .cvsignore, __init__.py, assembly/__init__.py, assembly/genpy.py, - disassembly/__init__.py, disassembly/ast.py, disassembly/consts.py, - disassembly/transformer.py: - - Initial source checkin (2000-09-01) - -2000-09-01 18:22 jhermann - - * README: - - Additions by shae - -2000-08-19 01:35 eris - - * README: - - - new dir structure by snibril aka Jürgen Herrman first stab at a - tree matcher in common.py - -2000-08-01 01:44 jhermann - - * README: - - Added a readme dummy diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/INSTALL --- a/vim/sadness/bike/INSTALL Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -Bicycle Repair Man - a Python Refactoring Browser -================================================= - -$Id: INSTALL,v 1.4 2002/03/29 13:10:49 pdawes Exp $ - ------------------------------------------------------------------------------ - -Bicycle Repair Man requires Python 2.2 and above. - -Run -% python setup.py install - - -Then look for at the relevant README file to integrate Bicycle Repair -Man with your IDE. - ------------------------------------------------------------------------------ diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/NEWS --- a/vim/sadness/bike/NEWS Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -Main highlights of each new version. See ChangeLog for a more detailed -description of changes. - -Version 0.9 ------------ - -This version removes the requirement to load files into -bicyclerepairman before refactoring. Instead, it searches the -PYTHONPATH (and the path in which the file being queried is in). This -allows 'findDefinition' queries to be made on references -(e.g. classes, methods) where the definition is in the python library. - - -Version 0.8 ------------ - -This release improves on the internal type-deduction engine to handle -variables and attributes. To reflect this, 'rename' now works on -variables and attributes, in addition to methods, functions and -classes. This release also adds vim support (thanks to Marius Gedminas -and Matt Yeates for this) - -Version 0.7 ------------ - -This release includes a totally re-written type querying engine, which -is much faster and paves the way for new refactorings. It also adds -the 'FindReferences' and 'FindDefinition' query to emacs and idle. - - -Version 0.6 ------------ - -This release adds undo functionality to the mix, and beefs up the idle -and emacs integration so that code is automatically imported into brm -when you load a file into a buffer. - - -Version 0.5 ------------ - -This release adds the ExtractMethod refactoring - - -Version 0.4 ------------ - -This release adds support for IDLE (see README.idle), and fixes a few -bugs. The CLI and GUI interfaces are now deprecated and have been -removed from this release. - - - -Version 0.3 ------------ - -This release adds the RenameClass and RenameFunction refactorings. -It also contains the initial xemacs integration functionality (see -README.xemacs). - - - -Version 0.2 ------------ - -This release adds a simple GUI for renaming methods - run bikegui.py -after installation. - -There's also some upgrades to pyxmi. It should now be able to generate -xmi to model all generalizations (including cross-package ones). -N.B. pyxmi.py is now called py2xmi.py. See changelog for reasons! - - - -Version 0.1 ------------ - -This is the first release of Bicycle Repair Man. It requires python -version 2.2 and above. - -This version supports a partial implementation of the RenameMethod -refactoring through a command line interface. - -It automatically renames the method and references to the method that -it can deduce. It asks you about method references it can't deduce the -instance type of. - -This software should be considered alpha, and may damage your source -files - backup your sources before use! - -See INSTALL for installation and usage instructions. - - -N.B. This package also contains pyxmi - a little python -> xmi tool I -cobbled together out of the bicycle repair man parsing package. It -generates an xmi file out of a source-file or package-structure, -suitable for loading into the argouml tool. See -http://argouml.tigris.org. diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/PKG-INFO --- a/vim/sadness/bike/PKG-INFO Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -Metadata-Version: 1.0 -Name: bicyclerepair -Version: 0.9 -Summary: Bicycle Repair Man, the Python refactoring tool -Home-page: http://bicyclerepair.sourceforge.net -Author: Phil Dawes -Author-email: pdawes@users.sourceforge.net -License: UNKNOWN -Description: UNKNOWN -Platform: UNKNOWN diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/README --- a/vim/sadness/bike/README Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -Bicycle Repair Man - a Python Refactoring Browser -================================================= - -Copyright (c) 2000 by Shae Erisson -Copyright (c) 2001-3 by Phil Dawes - -All rights reserved, see COPYING for details. - -$Id: README,v 1.7 2003/08/24 19:48:43 pdawes Exp $ - ------------------------------------------------------------------------------ - -Bicycle Repair Man is the Python Refactoring Browser, helping -Pythonistas everywhere glide over the gory details of refactoring their -code. Watch him extract jumbled code into well ordered classes. Gasp, as -he renames all occurrences of a method. Thank You, Bicycle Repair Man! - -execute ./testall.py to run all the tests - -see INSTALL for installation instructions (uses distutils). - -see README.idle, README.emacs etc.. for instructions on how to -integrate bicyclerepairman into supported IDEs. - ------------------------------------------------------------------------------ - - -What's Python? - -Python is a programming language. To find out more -about it, go to the Python Homepage at http://www.python.org/ - - -What's a Refactoring Browser? - -A Refactoring Browser is an editor that automates Refactorings. The -first Refactoring Browser was written by Dr. Don Roberts and Dr. John -Brant at the University of Illinois in Urbana-Champagne. Dr. Don -Roberts wrote his Ph.D. thesis on the design and implementation of the -Refactoring Browser. For more detail, read the aforementioned thesis -at http://st-www.cs.uiuc.edu/~droberts/thesis.pdf - - -What's a Refactoring? - -A Refactoring is a behaviour preserving change to source code. Some -Refactorings are RenameVariable, RenameClass, RenameMethod, -PullUpMethod, and PushDownVariable. Lots of people say it's very easy -to just type a different name in where your class, method, or variable -is defined. That's not always a refactoring though. The Refactoring -Browser is smart enough to rename every reference to your class, -method or variable. If you've ever renamed a variable and broken -classes in widely scattered parts of your system, you might be happier -using a Refactoring Browser. A Refactoring Browser operates on any of -method, function, class, or variable. It can add, delete, rename, move -up down or sideways, inline and abstract. There are some operations -that are specific to one of the three types, such as abstracting a -variable into accessors, or turing several lines of code into a -separate method. - -For more information on Refactoring, check out the websites of Martin -Fowler at http://www.martinfowler.com/ and his Refactoring Site at -http://www.refactoring.com/ . - - -Why Bicycle Repair Man? - -The Bicycle Repair Man was a superhero in a Monty Python skit, his -special power was repairing bicycles. - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/README.emacs --- a/vim/sadness/bike/README.emacs Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -Instructions for running Bicycle Repair Man through emacs/xemacs ----------------------------------------------------------------- - -N.B. You need xemacs / emacs 21 or above. - -The emacs integration utilises the excellent 'Pymacs' package, written -by François Pinard, which integrates python with emacs. A copy of this -software is included with this package. - - -There are 3 steps to installing bicyclerepairman for emacs: - -1) Install the base bicyclerepairman package - -2) Install the Pymacs package (if you haven't already got it) - -3) Modify your .emacs to active the bicyclerepairman functionality - -See the sections below for instructions on doing each of these. - -WINDOWS USERS: -You need to have both the python executable and the scripts directory -(e.g. c:\Python22/Scripts) in your path for Bicyclerepairman to work. - -There are a couple of niggles with brm/emacs on -windows. See the comments at the end of this file. - - - - - - - -1) Installation of Base Bicyclerepairman: ------------------------------------------ - -- install bicyclerepair man as per INSTALL - - -2) Installation of Pymacs: --------------------------- - -(You can skip this if you already have pymacs installed. - -- Go to the ide-integration/Pymacs-0.20 directory -- Run - python setup.py install -- Run - python setup-emacs.py -l - OR - python setup-emacs.py -E xemacs -l - Depending on your version of emacs. - -- Add the following into your .emacs or .xemacs/init.el: - -;; pymacs -(autoload 'pymacs-load "pymacs" nil t) -(autoload 'pymacs-eval "pymacs" nil t) -(autoload 'pymacs-apply "pymacs") -(autoload 'pymacs-call "pymacs") - -- Check that it has installed correctly: - (Taken from the pymacs README) - - - To check that `pymacs.el' is properly installed, start Emacs and give - it the command `M-x load-library RET pymacs': you should not receive - any error. - - To check that `pymacs.py' is properly installed, start - an interactive Python session (e.g. from a command shell) and type - `from Pymacs import lisp': you should not receive any error. - - To check that `pymacs-services' is properly installed, type - `pymacs-services' in a shell; you should then get a line ending - with "(pymacs-version VERSION)". Press ctrl-c to exit. - - -If you have any problems, consult the README file included with the -pymacs distribution. N.B. I renamed the setup script to setup-emacs.py -to make it more intuitive and easier for windows users. I've also -added a pymacs-services.bat file to allow it to run on windows. - - -3) Activating the Bike/Emacs integration ----------------------------------------- - -Add the following to your .emacs or .xemacs/init.el, after the pymacs -stuff: - -(pymacs-load "bikeemacs" "brm-") -(brm-init) - - -You need to be using python-mode for the bicyclerepairman menu to -appear. If you haven't already, enable this with: - -(autoload 'python-mode "python-mode" "Python editing mode." t) -(setq auto-mode-alist - (cons '("\\.py$" . python-mode) auto-mode-alist)) - - - -Usage: ------- - -Load a python file into emacs. A BicycleRepairMan menu should appear. - - -Windows GNU-Emacs users ------------------------ - -The load dialog in windows GNU-Emacs doesn't seem to allow selection -of directories. If this is the case for you, use 'M-x brm-load' to -import a package hierarchy. diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/README.idle --- a/vim/sadness/bike/README.idle Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -BicycleRepairMan_Idle.py is the name of the idle integration module. - - -Installation on Python 2.3 or idlefork --------------------------------------- -1) Install Bicycle Repair Man (see INSTALL) - -2) Add the following to your ~/.idlerc/config-extensions.cfg: -(NOTE - I had to put this in my -/idlelib/config-extensions.def for it to work correctly) - -[BicycleRepairMan_Idle] -enable=1 -trace=0 -[BicycleRepairMan_Idle_cfgBindings] -brm-find-references= -brm-find-definition= -brm-rename= -brm-extract-method= -brm-undo= - -Python sourcefile editor windows will now have a 'BicycleRepairMan' -menu. - - - -Installation on python 2.2 version of idle ------------------------------------------- - -1) Install Bicycle Repair Man (see INSTALL) - -2) Add the following line to your /config.txt or -~/.idle: - -[BicycleRepairMan_Idle] - - -Python sourcefile editor windows will now have a 'BicycleRepairMan' -menu. - - - -Caveats -------- - -Sometimes dialogs get lost behind windows. If things seem to have -paused in a rename-method, try looking for a dialog. diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/README.vim --- a/vim/sadness/bike/README.vim Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -Instructions for installing bike.vim are in the file itself. -See ide-integration/bike.vim \ No newline at end of file diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/__init__.py --- a/vim/sadness/bike/bike/__init__.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -# The root bicyclerepairman package -# do: -# --------------------- -# import bike -# ctx = bike.load() -# --------------------- -# to instantiate a bicyclerepairman context object - - -from bikefacade import init, NotAPythonModuleOrPackageException, CouldntLocateASTNodeFromCoordinatesException, UndoStackEmptyException diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/bikefacade.py --- a/vim/sadness/bike/bike/bikefacade.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -import os -import sys -import compiler -from parser import ParserError -from bike.parsing.pathutils import getRootDirectory -from bike.refactor import extractMethod -from bike.refactor.rename import rename -from bike.refactor.extractMethod import coords -from bike.transformer.save import save as saveUpdates -from bike.parsing.utils import fqn_rcar, fqn_rcdr -from bike.parsing import visitor -from bike.transformer.undo import getUndoStack, UndoStackEmptyException -from bike.parsing.fastparserast import getRoot, Class, Function -from bike.query.common import getScopeForLine -from bike.query.getTypeOf import getTypeOfExpr, UnfoundType -from bike.query.findReferences import findReferences -from bike.query.findDefinition import findAllPossibleDefinitionsByCoords -from bike.refactor import inlineVariable, extractVariable, moveToModule -from bike.parsing.load import Cache -from bike import log - -def init(): - #context = BRMContext_impl() - context = BRMContext_wrapper() - return context - -# the context object public interface -class BRMContext(object): - - - def save(self): - """ save the changed files out to disk """ - - def setRenameMethodPromptCallback(self, callback): - """ - sets a callback to ask the user about method refs which brm - can't deduce the type of. The callback must be callable, and - take the following parameters: - - filename - - linenumber - - begin column - - end column - (begin and end columns enclose the problematic method call) - """ - - def renameByCoordinates(self, filename_path, line, col, newname): - """ an ide friendly method which renames a class/fn/method - pointed to by the coords and filename""" - - def extract(self, filename_path, - begin_line, begin_col, - end_line, end_col, - name): - """ extracts the region into the named method/function based - on context""" - - def inlineLocalVariable(self,filename_path, line, col): - """ Inlines the variable pointed to by - line:col. (N.B. line:col can also point to a reference to the - variable as well as the definition) """ - - - def extractLocalVariable(self,filename_path, begin_line, begin_col, - end_line, end_col, variablename): - """ Extracts the region into a variable """ - - def setProgressLogger(self,logger): - """ Sets the progress logger to an object with a write method - """ - - def setWarningLogger(self,logger): - """ Sets the warning logger to an object with a write method - """ - - def undo(self): - """ undoes the last refactoring. WARNING: this is dangerous if - the user has modified files since the last refactoring. - Raises UndoStackEmptyException""" - - def findReferencesByCoordinates(self, filename_path, line, column): - """ given the coords of a function, class, method or variable - returns a generator which finds references to it. - """ - - def findDefinitionByCoordinates(self,filename_path,line,col): - """ given the coordates to a reference, tries to find the - definition of that reference """ - - def moveClassToNewModule(self,filename_path, line, - newfilename): - """ moves the class pointed to by (filename_path, line) - to a new module """ - - -class NotAPythonModuleOrPackageException: pass -class CouldntLocateASTNodeFromCoordinatesException: pass - - -# Wrapper to ensure that caches are purged on each request -class BRMContext_wrapper: - def __init__(self): - self.brmctx = BRMContext_impl() - - def __getattr__(self,name): - return BRMContext_callWrapper(self.brmctx,name) - - -class BRMContext_callWrapper: - def __init__(self,brmctx,methodname): - self.name = methodname - self.brmctx = brmctx - - def __call__(self,*args): - Cache.instance.reset() - try: - return getattr(self.brmctx,self.name)(*args) - finally: - Cache.instance.reset() - - -class BRMContext_impl(BRMContext): - - def __init__(self): - self.ast = getRoot() - - # Used because some refactorings delegate back to the user. - # this flag ensures that code isnt imported during those times - self.readyToLoadNewCode = 1 - self.paths = [] - getUndoStack(1) # force new undo stack - if not getRoot().unittestmode: - log.warning = sys.stderr - self.promptUserClientCallback = None - - def _getAST(self): - return self.ast - - # returns a list of saved filenames - def save(self): - savedfiles = saveUpdates() - return savedfiles - - def setRenameMethodPromptCallback(self, callback): - self.promptUserClientCallback = callback - - - def normalizeFilename(self,filename): - filename = os.path.expanduser(filename) - filename = os.path.normpath(os.path.abspath(filename)) - return filename - - def extractMethod(self, filename_path, - begin_line, begin_column, - end_line, end_column, - methodname): - self.extract(filename_path, begin_line, begin_column, - end_line, end_column,methodname) - - def extractFunction(self, filename_path, - begin_line, begin_column, - end_line, end_column, - methodname): - self.extract(filename_path, begin_line, begin_column, - end_line, end_column,methodname) - - # does it based on context - def extract(self, filename_path, - begin_line, begin_col, - end_line, end_col, - name): - filename_path = self.normalizeFilename(filename_path) - extractMethod.extractMethod(filename_path, - coords(begin_line, begin_col), - coords(end_line, end_col), name) - - def inlineLocalVariable(self,filename_path, line, col): - filename_path = self.normalizeFilename(filename_path) - inlineVariable.inlineLocalVariable(filename_path,line,col) - - def extractLocalVariable(self,filename_path, begin_line, begin_col, - end_line, end_col, variablename): - filename_path = self.normalizeFilename(filename_path) - extractVariable.extractLocalVariable(filename_path, - coords(begin_line, begin_col), - coords(end_line, end_col), - variablename) - - def moveClassToNewModule(self,filename_path, line, - newfilename): - filename_path = self.normalizeFilename(filename_path) - newfilename = self.normalizeFilename(newfilename) - moveToModule.moveClassToNewModule(filename_path, line, - newfilename) - - def undo(self): - getUndoStack().undo() - - def _promptUser(self, filename, lineno, colbegin, colend): - return self.promptUserClientCallback(filename, lineno, colbegin, colend) - - - # must be an object with a write method - def setProgressLogger(self,logger): - log.progress = logger - - # must be an object with a write method - def setWarningLogger(self,logger): - log.warning = logger - - - # filename_path must be absolute - def renameByCoordinates(self, filename_path, line, col, newname): - filename_path = self.normalizeFilename(filename_path) - Cache.instance.reset() - try: - self._setNonLibPythonPath(filename_path) - rename(filename_path,line,col,newname, - self.promptUserClientCallback) - finally: - Cache.instance.reset() - - def _reverseCoordsIfWrongWayRound(self, colbegin, colend): - if(colbegin > colend): - colbegin,colend = colend,colbegin - return colbegin,colend - - - def findDefinitionByCoordinates(self,filename_path,line,col): - filename_path = self.normalizeFilename(filename_path) - self._setCompletePythonPath(filename_path) - return findAllPossibleDefinitionsByCoords(filename_path,line,col) - - - # filename_path must be absolute - def findReferencesByCoordinates(self, filename_path, line, column): - filename_path = self.normalizeFilename(filename_path) - self._setNonLibPythonPath(filename_path) - return findReferences(filename_path,line,column) - - def refreshASTFromFileSystem(self): - for path in self.paths: - self.ast = loadast(path, self.ast) - - def _setCompletePythonPath(self,filename): - pythonpath = [] + sys.path # make a copy - self.ast.pythonpath = pythonpath - - def _setNonLibPythonPath(self,filename): - if getRoot().unittestmode: - return - pythonpath = self._removeLibdirsFromPath(sys.path) - pythonpath = [os.path.abspath(p) for p in pythonpath] - self.ast.pythonpath = pythonpath - - def _getCurrentSearchPath(self): - return self.ast.pythonpath - - def _removeLibdirsFromPath(self, pythonpath): - libdir = os.path.join(sys.prefix,"lib").lower() - pythonpath = [p for p in pythonpath - if not p.lower().startswith(libdir)] - return pythonpath - - -def _deducePackageOfFile(filename): - package = "" - dot = "" - dir = os.path.dirname(filename) - while dir != ""and \ - os.path.exists(os.path.join(dir, "__init__.py")): - dir, dirname = os.path.split(dir) - package = dirname+dot+package - dot = "." - return package diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/globals.py --- a/vim/sadness/bike/bike/globals.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -try: - True = 1 - False = 0 -except: - pass - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/log.py --- a/vim/sadness/bike/bike/log.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -import sys -class SilentLogger: - def write(*args): - pass - -progress = SilentLogger() -warning = SilentLogger() -#warning = sys.stderr diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/logging.py --- a/vim/sadness/bike/bike/logging.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1995 +0,0 @@ -#! /usr/bin/env python -# -# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose and without fee is hereby granted, -# provided that the above copyright notice appear in all copies and that -# both that copyright notice and this permission notice appear in -# supporting documentation, and that the name of Vinay Sajip -# not be used in advertising or publicity pertaining to distribution -# of the software without specific, written prior permission. -# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# -# For the change history, see README.txt in the distribution. -# -# This file is part of the Python logging distribution. See -# http://www.red-dove.com/python_logging.html -# - -""" -Logging module for Python. Based on PEP 282 and comments thereto in -comp.lang.python, and influenced by Apache's log4j system. - -Should work under Python versions >= 1.5.2, except that source line -information is not available unless 'inspect' is. - -Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved. - -To use, simply 'import logging' and log away! -""" - -import sys, os, types, time, string, socket, cPickle, cStringIO - -from SocketServer import ThreadingTCPServer, StreamRequestHandler - - -try: - import thread -except ImportError: - thread = None -try: - import inspect -except ImportError: - inspect = None - -__author__ = "Vinay Sajip " -__status__ = "alpha" -__version__ = "0.4.5" -__date__ = "4 June 2002" - -#--------------------------------------------------------------------------- -# Miscellaneous module data -#--------------------------------------------------------------------------- - -# -#_srcfile is used when walking the stack to check when we've got the first -# caller stack frame. -#If run as a script, __file__ is not bound. -# -if __name__ == "__main__": - _srcfile = None -else: - if string.lower(__file__[-4:]) in ['.pyc', '.pyo']: - _srcfile = __file__[:-4] + '.py' - else: - _srcfile = __file__ - _srcfile = os.path.normcase(_srcfile) - -# -#_startTime is used as the base when calculating the relative time of events -# -_startTime = time.time() - -# -# Some constants... -# - -DEFAULT_TCP_LOGGING_PORT = 9020 -DEFAULT_UDP_LOGGING_PORT = 9021 -DEFAULT_HTTP_LOGGING_PORT = 9022 -DEFAULT_SOAP_LOGGING_PORT = 9023 -DEFAULT_LOGGING_CONFIG_PORT = 9030 -SYSLOG_UDP_PORT = 514 - -#--------------------------------------------------------------------------- -# Level related stuff -#--------------------------------------------------------------------------- -# -# Default levels and level names, these can be replaced with any positive set -# of values having corresponding names. There is a pseudo-level, ALL, which -# is only really there as a lower limit for user-defined levels. Handlers and -# loggers are initialized with ALL so that they will log all messages, even -# at user-defined levels. -# -CRITICAL = 50 -FATAL = CRITICAL -ERROR = 40 -WARN = 30 -INFO = 20 -DEBUG = 10 -ALL = 0 - -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARN : 'WARN', - INFO : 'INFO', - DEBUG : 'DEBUG', - ALL : 'ALL', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARN, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'ALL' : ALL, -} - -def getLevelName(lvl): - """ - Return the textual representation of logging level 'lvl'. If the level is - one of the predefined levels (CRITICAL, ERROR, WARN, INFO, DEBUG) then you - get the corresponding string. If you have associated levels with names - using addLevelName then the name you have associated with 'lvl' is - returned. Otherwise, the string "Level %s" % lvl is returned. - """ - return _levelNames.get(lvl, ("Level %s" % lvl)) - -def addLevelName(lvl, levelName): - """ - Associate 'levelName' with 'lvl'. This is used when converting levels - to text during message formatting. - """ - _acquireLock() - try: #unlikely to cause an exception, but you never know... - _levelNames[lvl] = levelName - _levelNames[levelName] = lvl - finally: - _releaseLock() - -#--------------------------------------------------------------------------- -# Thread-related stuff -#--------------------------------------------------------------------------- - -# -#_lock is used to serialize access to shared data structures in this module. -#This needs to be an RLock because fileConfig() creates Handlers and so -#might arbitrary user threads. Since Handler.__init__() updates the shared -#dictionary _handlers, it needs to acquire the lock. But if configuring, -#the lock would already have been acquired - so we need an RLock. -#The same argument applies to Loggers and Manager.loggerDict. -# -_lock = None - -def _acquireLock(): - """ - Acquire the module-level lock for serializing access to shared data. - This should be released with _releaseLock(). - """ - global _lock - if (not _lock) and thread: - import threading #this had better work - _lock = threading.RLock() - if _lock: - _lock.acquire() - -def _releaseLock(): - """ - Release the module-level lock acquired by calling _acquireLock(). - """ - if _lock: - _lock.release() - -#--------------------------------------------------------------------------- -# The logging record -#--------------------------------------------------------------------------- - -class LogRecord: - """ - LogRecord instances are created every time something is logged. They - contain all the information pertinent to the event being logged. The - main information passed in is in msg and args, which are combined - using msg % args to create the message field of the record. The record - also includes information such as when the record was created, the - source line where the logging call was made, and any exception - information to be logged. - """ - def __init__(self, name, lvl, pathname, lineno, msg, args, exc_info): - """ - Initialize a logging record with interesting information. - """ - ct = time.time() - self.name = name - self.msg = msg - self.args = args - self.levelname = getLevelName(lvl) - self.levelno = lvl - self.pathname = pathname - try: - self.filename = os.path.basename(pathname) - self.module = os.path.splitext(self.filename)[0] - except: - self.filename = pathname - self.module = "Unknown module" - self.exc_info = exc_info - self.lineno = lineno - self.created = ct - self.msecs = (ct - long(ct)) * 1000 - self.relativeCreated = (self.created - _startTime) * 1000 - if thread: - self.thread = thread.get_ident() - else: - self.thread = None - - def __str__(self): - return ''%(self.name, self.levelno, - self.pathname, self.lineno, self.msg) - - def getMessage(self): - """ - Return the message for this LogRecord, merging any user-supplied - arguments with the message. - """ - msg = str(self.msg) - if self.args: - msg = msg % self.args - return msg - -#--------------------------------------------------------------------------- -# Formatter classes and functions -#--------------------------------------------------------------------------- - -class Formatter: - """ - Formatters need to know how a LogRecord is constructed. They are - responsible for converting a LogRecord to (usually) a string which can - be interpreted by either a human or an external system. The base Formatter - allows a formatting string to be specified. If none is supplied, the - default value of "%s(message)\\n" is used. - - The Formatter can be initialized with a format string which makes use of - knowledge of the LogRecord attributes - e.g. the default value mentioned - above makes use of the fact that the user's message and arguments are pre- - formatted into a LogRecord's message attribute. Currently, the useful - attributes in a LogRecord are described by: - - %(name)s Name of the logger (logging channel) - %(levelno)s Numeric logging level for the message (DEBUG, INFO, - WARN, ERROR, CRITICAL) - %(levelname)s Text logging level for the message ("DEBUG", "INFO", - "WARN", "ERROR", "CRITICAL") - %(pathname)s Full pathname of the source file where the logging - call was issued (if available) - %(filename)s Filename portion of pathname - %(module)s Module (name portion of filename) - %(lineno)d Source line number where the logging call was issued - (if available) - %(created)f Time when the LogRecord was created (time.time() - return value) - %(asctime)s Textual time when the LogRecord was created - %(msecs)d Millisecond portion of the creation time - %(relativeCreated)d Time in milliseconds when the LogRecord was created, - relative to the time the logging module was loaded - (typically at application startup time) - %(thread)d Thread ID (if available) - %(message)s The result of msg % args, computed just as the - record is emitted - """ - def __init__(self, fmt=None, datefmt=None): - """ - Initialize the formatter either with the specified format string, or a - default as described above. Allow for specialized date formatting with - the optional datefmt argument (if omitted, you get the ISO8601 format). - """ - if fmt: - self._fmt = fmt - else: - self._fmt = "%(message)s" - self.datefmt = datefmt - - def formatTime(self, record, datefmt=None): - """ - This method should be called from format() by a formatter which - wants to make use of a formatted time. This method can be overridden - in formatters to provide for any specific requirement, but the - basic behaviour is as follows: if datefmt (a string) is specified, - it is used with time.strftime() to format the creation time of the - record. Otherwise, the ISO8601 format is used. The resulting - string is returned. - """ - ct = record.created - if datefmt: - s = time.strftime(datefmt, time.localtime(ct)) - else: - t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ct)) - s = "%s,%03d" % (t, record.msecs) - return s - - def formatException(self, ei): - """ - Format the specified exception information as a string. This - default implementation just uses traceback.print_exception() - """ - import traceback - sio = cStringIO.StringIO() - traceback.print_exception(ei[0], ei[1], ei[2], None, sio) - s = sio.getvalue() - sio.close() - if s[-1] == "\n": - s = s[:-1] - return s - - def format(self, record): - """ - The record's attribute dictionary is used as the operand to a - string formatting operation which yields the returned string. - Before formatting the dictionary, a couple of preparatory steps - are carried out. The message attribute of the record is computed - using msg % args. If the formatting string contains "%(asctime)", - formatTime() is called to format the event time. If there is - exception information, it is formatted using formatException() - and appended to the message. - """ - record.message = record.getMessage() - if string.find(self._fmt,"%(asctime)") >= 0: - record.asctime = self.formatTime(record, self.datefmt) - s = self._fmt % record.__dict__ - if record.exc_info: - if s[-1] != "\n": - s = s + "\n" - s = s + self.formatException(record.exc_info) - return s - -# -# The default formatter to use when no other is specified -# -_defaultFormatter = Formatter() - -class BufferingFormatter: - """ - A formatter suitable for formatting a number of records. - """ - def __init__(self, linefmt=None): - """ - Optionally specify a formatter which will be used to format each - individual record. - """ - if linefmt: - self.linefmt = linefmt - else: - self.linefmt = _defaultFormatter - - def formatHeader(self, records): - """ - Return the header string for the specified records. - """ - return "" - - def formatFooter(self, records): - """ - Return the footer string for the specified records. - """ - return "" - - def format(self, records): - """ - Format the specified records and return the result as a string. - """ - rv = "" - if len(records) > 0: - rv = rv + self.formatHeader(records) - for record in records: - rv = rv + self.linefmt.format(record) - rv = rv + self.formatFooter(records) - return rv - -#--------------------------------------------------------------------------- -# Filter classes and functions -#--------------------------------------------------------------------------- - -class Filter: - """ - The base filter class. Loggers and Handlers can optionally use Filter - instances to filter records as desired. The base filter class only allows - events which are below a certain point in the logger hierarchy. For - example, a filter initialized with "A.B" will allow events logged by - loggers "A.B", "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" - etc. If initialized with the empty string, all events are passed. - """ - def __init__(self, name=''): - """ - Initialize with the name of the logger which, together with its - children, will have its events allowed through the filter. If no - name is specified, allow every event. - """ - self.name = name - self.nlen = len(name) - - def filter(self, record): - """ - Is the specified record to be logged? Returns 0 for no, nonzero for - yes. If deemed appropriate, the record may be modified in-place. - """ - if self.nlen == 0: - return 1 - elif self.name == record.name: - return 1 - elif string.find(record.name, self.name, 0, self.nlen) != 0: - return 0 - return (record.name[self.nlen] == ".") - -class Filterer: - """ - A base class for loggers and handlers which allows them to share - common code. - """ - def __init__(self): - """ - Initialize the list of filters to be an empty list. - """ - self.filters = [] - - def addFilter(self, filter): - """ - Add the specified filter to this handler. - """ - if not (filter in self.filters): - self.filters.append(filter) - - def removeFilter(self, filter): - """ - Remove the specified filter from this handler. - """ - if filter in self.filters: - self.filters.remove(filter) - - def filter(self, record): - """ - Determine if a record is loggable by consulting all the filters. The - default is to allow the record to be logged; any filter can veto this - and the record is then dropped. Returns a boolean value. - """ - rv = 1 - for f in self.filters: - if not f.filter(record): - rv = 0 - break - return rv - -#--------------------------------------------------------------------------- -# Handler classes and functions -#--------------------------------------------------------------------------- - -_handlers = {} #repository of handlers (for flushing when shutdown called) - -class Handler(Filterer): - """ - The base handler class. Acts as a placeholder which defines the Handler - interface. Handlers can optionally use Formatter instances to format - records as desired. By default, no formatter is specified; in this case, - the 'raw' message as determined by record.message is logged. - """ - def __init__(self, level=ALL): - """ - Initializes the instance - basically setting the formatter to None - and the filter list to empty. - """ - Filterer.__init__(self) - self.level = level - self.formatter = None - #get the module data lock, as we're updating a shared structure. - _acquireLock() - try: #unlikely to raise an exception, but you never know... - _handlers[self] = 1 - finally: - _releaseLock() - self.createLock() - - def createLock(self): - """ - Acquire a thread lock for serializing access to the underlying I/O. - """ - if thread: - self.lock = thread.allocate_lock() - else: - self.lock = None - - def acquire(self): - """ - Acquire the I/O thread lock. - """ - if self.lock: - self.lock.acquire() - - def release(self): - """ - Release the I/O thread lock. - """ - if self.lock: - self.lock.release() - - def setLevel(self, lvl): - """ - Set the logging level of this handler. - """ - self.level = lvl - - def format(self, record): - """ - Do formatting for a record - if a formatter is set, use it. - Otherwise, use the default formatter for the module. - """ - if self.formatter: - fmt = self.formatter - else: - fmt = _defaultFormatter - return fmt.format(record) - - def emit(self, record): - """ - Do whatever it takes to actually log the specified logging record. - This version is intended to be implemented by subclasses and so - raises a NotImplementedError. - """ - raise NotImplementedError, 'emit must be implemented '\ - 'by Handler subclasses' - - def handle(self, record): - """ - Conditionally emit the specified logging record, depending on - filters which may have been added to the handler. Wrap the actual - emission of the record with acquisition/release of the I/O thread - lock. - """ - if self.filter(record): - self.acquire() - try: - self.emit(record) - finally: - self.release() - - def setFormatter(self, fmt): - """ - Set the formatter for this handler. - """ - self.formatter = fmt - - def flush(self): - """ - Ensure all logging output has been flushed. This version does - nothing and is intended to be implemented by subclasses. - """ - pass - - def close(self): - """ - Tidy up any resources used by the handler. This version does - nothing and is intended to be implemented by subclasses. - """ - pass - - def handleError(self): - """ - This method should be called from handlers when an exception is - encountered during an emit() call. By default it does nothing, - which means that exceptions get silently ignored. This is what is - mostly wanted for a logging system - most users will not care - about errors in the logging system, they are more interested in - application errors. You could, however, replace this with a custom - handler if you wish. - """ - #import traceback - #ei = sys.exc_info() - #traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) - #del ei - pass - -class StreamHandler(Handler): - """ - A handler class which writes logging records, appropriately formatted, - to a stream. Note that this class does not close the stream, as - sys.stdout or sys.stderr may be used. - """ - def __init__(self, strm=None): - """ - If strm is not specified, sys.stderr is used. - """ - Handler.__init__(self) - if not strm: - strm = sys.stderr - self.stream = strm - self.formatter = None - - def flush(self): - """ - Flushes the stream. - """ - self.stream.flush() - - def emit(self, record): - """ - If a formatter is specified, it is used to format the record. - The record is then written to the stream with a trailing newline - [N.B. this may be removed depending on feedback]. If exception - information is present, it is formatted using - traceback.print_exception and appended to the stream. - """ - try: - msg = self.format(record) - self.stream.write("%s\n" % msg) - self.flush() - except: - self.handleError() - -class FileHandler(StreamHandler): - """ - A handler class which writes formatted logging records to disk files. - """ - def __init__(self, filename, mode="a+"): - """ - Open the specified file and use it as the stream for logging. - By default, the file grows indefinitely. You can call setRollover() - to allow the file to rollover at a predetermined size. - """ - StreamHandler.__init__(self, open(filename, mode)) - self.maxBytes = 0 - self.backupCount = 0 - self.baseFilename = filename - #self.backupIndex = 0 - self.mode = mode - - def setRollover(self, maxBytes, backupCount): - """ - Set the rollover parameters so that rollover occurs whenever the - current log file is nearly maxBytes in length. If backupCount - is >= 1, the system will successively create new files with the - same pathname as the base file, but with extensions ".1", ".2" - etc. appended to it. For example, with a backupCount of 5 and a - base file name of "app.log", you would get "app.log", "app.log.1", - "app.log.2", ... through to "app.log.5". When the last file reaches - its size limit, the logging reverts to "app.log" which is truncated - to zero length. If maxBytes is zero, rollover never occurs. - """ - self.maxBytes = maxBytes - self.backupCount = backupCount - if maxBytes > 0: - self.mode = "a+" - - def doRollover(self): - """ - Do a rollover, as described in setRollover(). - """ -# Old algorithm -# if self.backupIndex >= self.backupCount: -# self.backupIndex = 0 -# fn = self.baseFilename -# else: -# self.backupIndex = self.backupIndex + 1 -# fn = "%s.%d" % (self.baseFilename, self.backupIndex) -# self.stream.close() -# self.stream = open(fn, "w+") - self.stream.close() - if self.backupCount > 0: - for i in range(self.backupCount - 1, 0, -1): - sfn = "%s.%d" % (self.baseFilename, i) - dfn = "%s.%d" % (self.baseFilename, i + 1) - if os.path.exists(sfn): - #print "%s -> %s" % (sfn, dfn) - if os.path.exists(dfn): - os.remove(dfn) - os.rename(sfn, dfn) - dfn = self.baseFilename + ".1" - if os.path.exists(dfn): - os.remove(dfn) - os.rename(self.baseFilename, dfn) - self.stream = open(self.baseFilename, "w+") - - def emit(self, record): - """ - Output the record to the file, catering for rollover as described - in setRollover(). - """ - if self.maxBytes > 0: # are we rolling over? - msg = "%s\n" % self.format(record) - if self.stream.tell() + len(msg) >= self.maxBytes: - self.doRollover() - StreamHandler.emit(self, record) - - def close(self): - """ - Closes the stream. - """ - self.stream.close() - -class SocketHandler(Handler): - """ - A handler class which writes logging records, in pickle format, to - a streaming socket. The socket is kept open across logging calls. - If the peer resets it, an attempt is made to reconnect on the next call. - Note that the very simple wire protocol used means that packet sizes - are expected to be encodable within 16 bits (i.e. < 32767 bytes). - """ - - def __init__(self, host, port): - """ - Initializes the handler with a specific host address and port. - """ - Handler.__init__(self) - self.host = host - self.port = port - self.sock = None - self.closeOnError = 1 - - def makeSocket(self): - """ - A factory method which allows subclasses to define the precise - type of socket they want. - """ - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((self.host, self.port)) - return s - - def send(self, s): - """ - Send a pickled string to the socket. This function allows for - partial sends which can happen when the network is busy. - """ - sentsofar = 0 - left = len(s) - while left > 0: - sent = self.sock.send(s[sentsofar:]) - sentsofar = sentsofar + sent - left = left - sent - - def makePickle(self, record): - """ - Pickles the record in binary format with a length prefix, and - returns it ready for transmission across the socket. - """ - s = cPickle.dumps(record.__dict__, 1) - n = len(s) - slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF) - return slen + s - - def handleError(self): - """ - An error has occurred during logging. Most likely cause - - connection lost. Close the socket so that we can retry on the - next event. - """ - if self.closeOnError and self.sock: - self.sock.close() - self.sock = None #try to reconnect next time - - def emit(self, record): - """ - Pickles the record and writes it to the socket in binary format. - If there is an error with the socket, silently drop the packet. - If there was a problem with the socket, re-establishes the - socket. - """ - try: - s = self.makePickle(record) - if not self.sock: - self.sock = self.makeSocket() - self.send(s) - except: - self.handleError() - - def close(self): - """ - Closes the socket. - """ - if self.sock: - self.sock.close() - self.sock = None - -class DatagramHandler(SocketHandler): - """ - A handler class which writes logging records, in pickle format, to - a datagram socket. Note that the very simple wire protocol used means - that packet sizes are expected to be encodable within 16 bits - (i.e. < 32767 bytes). - - """ - def __init__(self, host, port): - """ - Initializes the handler with a specific host address and port. - """ - SocketHandler.__init__(self, host, port) - self.closeOnError = 0 - - def makeSocket(self): - """ - The factory method of SocketHandler is here overridden to create - a UDP socket (SOCK_DGRAM). - """ - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - return s - - def send(self, s): - """ - Send a pickled string to a socket. This function allows for - partial sends which can happen when the network is busy. - """ - sentsofar = 0 - left = len(s) - addr = (self.host, self.port) - while left > 0: - sent = self.sock.sendto(s[sentsofar:], addr) - sentsofar = sentsofar + sent - left = left - sent - -class SysLogHandler(Handler): - """ - A handler class which sends formatted logging records to a syslog - server. Based on Sam Rushing's syslog module: - http://www.nightmare.com/squirl/python-ext/misc/syslog.py - Contributed by Nicolas Untz (after which minor refactoring changes - have been made). - """ - - # from : - # ====================================================================== - # priorities/facilities are encoded into a single 32-bit quantity, where - # the bottom 3 bits are the priority (0-7) and the top 28 bits are the - # facility (0-big number). Both the priorities and the facilities map - # roughly one-to-one to strings in the syslogd(8) source code. This - # mapping is included in this file. - # - # priorities (these are ordered) - - LOG_EMERG = 0 # system is unusable - LOG_ALERT = 1 # action must be taken immediately - LOG_CRIT = 2 # critical conditions - LOG_ERR = 3 # error conditions - LOG_WARNING = 4 # warning conditions - LOG_NOTICE = 5 # normal but significant condition - LOG_INFO = 6 # informational - LOG_DEBUG = 7 # debug-level messages - - # facility codes - LOG_KERN = 0 # kernel messages - LOG_USER = 1 # random user-level messages - LOG_MAIL = 2 # mail system - LOG_DAEMON = 3 # system daemons - LOG_AUTH = 4 # security/authorization messages - LOG_SYSLOG = 5 # messages generated internally by syslogd - LOG_LPR = 6 # line printer subsystem - LOG_NEWS = 7 # network news subsystem - LOG_UUCP = 8 # UUCP subsystem - LOG_CRON = 9 # clock daemon - LOG_AUTHPRIV = 10 # security/authorization messages (private) - - # other codes through 15 reserved for system use - LOG_LOCAL0 = 16 # reserved for local use - LOG_LOCAL1 = 17 # reserved for local use - LOG_LOCAL2 = 18 # reserved for local use - LOG_LOCAL3 = 19 # reserved for local use - LOG_LOCAL4 = 20 # reserved for local use - LOG_LOCAL5 = 21 # reserved for local use - LOG_LOCAL6 = 22 # reserved for local use - LOG_LOCAL7 = 23 # reserved for local use - - priority_names = { - "alert": LOG_ALERT, - "crit": LOG_CRIT, - "critical": LOG_CRIT, - "debug": LOG_DEBUG, - "emerg": LOG_EMERG, - "err": LOG_ERR, - "error": LOG_ERR, # DEPRECATED - "info": LOG_INFO, - "notice": LOG_NOTICE, - "panic": LOG_EMERG, # DEPRECATED - "warn": LOG_WARNING, # DEPRECATED - "warning": LOG_WARNING, - } - - facility_names = { - "auth": LOG_AUTH, - "authpriv": LOG_AUTHPRIV, - "cron": LOG_CRON, - "daemon": LOG_DAEMON, - "kern": LOG_KERN, - "lpr": LOG_LPR, - "mail": LOG_MAIL, - "news": LOG_NEWS, - "security": LOG_AUTH, # DEPRECATED - "syslog": LOG_SYSLOG, - "user": LOG_USER, - "uucp": LOG_UUCP, - "local0": LOG_LOCAL0, - "local1": LOG_LOCAL1, - "local2": LOG_LOCAL2, - "local3": LOG_LOCAL3, - "local4": LOG_LOCAL4, - "local5": LOG_LOCAL5, - "local6": LOG_LOCAL6, - "local7": LOG_LOCAL7, - } - - def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER): - """ - If address is specified as a string, UNIX socket is used. - If facility is not specified, LOG_USER is used. - """ - Handler.__init__(self) - - self.address = address - self.facility = facility - if type(address) == types.StringType: - self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.socket.connect(address) - self.unixsocket = 1 - else: - self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.unixsocket = 0 - - self.formatter = None - - # curious: when talking to the unix-domain '/dev/log' socket, a - # zero-terminator seems to be required. this string is placed - # into a class variable so that it can be overridden if - # necessary. - log_format_string = '<%d>%s\000' - - def encodePriority (self, facility, priority): - """ - Encode the facility and priority. You can pass in strings or - integers - if strings are passed, the facility_names and - priority_names mapping dictionaries are used to convert them to - integers. - """ - if type(facility) == types.StringType: - facility = self.facility_names[facility] - if type(priority) == types.StringType: - priority = self.priority_names[priority] - return (facility << 3) | priority - - def close (self): - """ - Closes the socket. - """ - if self.unixsocket: - self.socket.close() - - def emit(self, record): - """ - The record is formatted, and then sent to the syslog server. If - exception information is present, it is NOT sent to the server. - """ - msg = self.format(record) - """ - We need to convert record level to lowercase, maybe this will - change in the future. - """ - msg = self.log_format_string % ( - self.encodePriority(self.facility, - string.lower(record.levelname)), - msg) - try: - if self.unixsocket: - self.socket.send(msg) - else: - self.socket.sendto(msg, self.address) - except: - self.handleError() - -class SMTPHandler(Handler): - """ - A handler class which sends an SMTP email for each logging event. - """ - def __init__(self, mailhost, fromaddr, toaddrs, subject): - """ - Initialize the instance with the from and to addresses and subject - line of the email. To specify a non-standard SMTP port, use the - (host, port) tuple format for the mailhost argument. - """ - Handler.__init__(self) - if type(mailhost) == types.TupleType: - host, port = mailhost - self.mailhost = host - self.mailport = port - else: - self.mailhost = mailhost - self.mailport = None - self.fromaddr = fromaddr - self.toaddrs = toaddrs - self.subject = subject - - def getSubject(self, record): - """ - If you want to specify a subject line which is record-dependent, - override this method. - """ - return self.subject - - def emit(self, record): - """ - Format the record and send it to the specified addressees. - """ - try: - import smtplib - port = self.mailport - if not port: - port = smtplib.SMTP_PORT - smtp = smtplib.SMTP(self.mailhost, port) - msg = self.format(record) - msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s" % ( - self.fromaddr, - string.join(self.toaddrs, ","), - self.getSubject(record), msg - ) - smtp.sendmail(self.fromaddr, self.toaddrs, msg) - smtp.quit() - except: - self.handleError() - -class BufferingHandler(Handler): - """ - A handler class which buffers logging records in memory. Whenever each - record is added to the buffer, a check is made to see if the buffer should - be flushed. If it should, then flush() is expected to do the needful. - """ - def __init__(self, capacity): - """ - Initialize the handler with the buffer size. - """ - Handler.__init__(self) - self.capacity = capacity - self.buffer = [] - - def shouldFlush(self, record): - """ - Returns true if the buffer is up to capacity. This method can be - overridden to implement custom flushing strategies. - """ - return (len(self.buffer) >= self.capacity) - - def emit(self, record): - """ - Append the record. If shouldFlush() tells us to, call flush() to process - the buffer. - """ - self.buffer.append(record) - if self.shouldFlush(record): - self.flush() - - def flush(self): - """ - Override to implement custom flushing behaviour. This version just zaps - the buffer to empty. - """ - self.buffer = [] - -class MemoryHandler(BufferingHandler): - """ - A handler class which buffers logging records in memory, periodically - flushing them to a target handler. Flushing occurs whenever the buffer - is full, or when an event of a certain severity or greater is seen. - """ - def __init__(self, capacity, flushLevel=ERROR, target=None): - """ - Initialize the handler with the buffer size, the level at which - flushing should occur and an optional target. Note that without a - target being set either here or via setTarget(), a MemoryHandler - is no use to anyone! - """ - BufferingHandler.__init__(self, capacity) - self.flushLevel = flushLevel - self.target = target - - def shouldFlush(self, record): - """ - Check for buffer full or a record at the flushLevel or higher. - """ - return (len(self.buffer) >= self.capacity) or \ - (record.levelno >= self.flushLevel) - - def setTarget(self, target): - """ - Set the target handler for this handler. - """ - self.target = target - - def flush(self): - """ - For a MemoryHandler, flushing means just sending the buffered - records to the target, if there is one. Override if you want - different behaviour. - """ - if self.target: - for record in self.buffer: - self.target.handle(record) - self.buffer = [] - - def close(self): - """ - Flush, set the target to None and lose the buffer. - """ - self.flush() - self.target = None - self.buffer = [] - -class NTEventLogHandler(Handler): - """ - A handler class which sends events to the NT Event Log. Adds a - registry entry for the specified application name. If no dllname is - provided, win32service.pyd (which contains some basic message - placeholders) is used. Note that use of these placeholders will make - your event logs big, as the entire message source is held in the log. - If you want slimmer logs, you have to pass in the name of your own DLL - which contains the message definitions you want to use in the event log. - """ - def __init__(self, appname, dllname=None, logtype="Application"): - Handler.__init__(self) - try: - import win32evtlogutil, win32evtlog - self.appname = appname - self._welu = win32evtlogutil - if not dllname: - dllname = os.path.split(self._welu.__file__) - dllname = os.path.split(dllname[0]) - dllname = os.path.join(dllname[0], r'win32service.pyd') - self.dllname = dllname - self.logtype = logtype - self._welu.AddSourceToRegistry(appname, dllname, logtype) - self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE - self.typemap = { - DEBUG : win32evtlog.EVENTLOG_INFORMATION_TYPE, - INFO : win32evtlog.EVENTLOG_INFORMATION_TYPE, - WARN : win32evtlog.EVENTLOG_WARNING_TYPE, - ERROR : win32evtlog.EVENTLOG_ERROR_TYPE, - CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE, - } - except ImportError: - print "The Python Win32 extensions for NT (service, event "\ - "logging) appear not to be available." - self._welu = None - - def getMessageID(self, record): - """ - Return the message ID for the event record. If you are using your - own messages, you could do this by having the msg passed to the - logger being an ID rather than a formatting string. Then, in here, - you could use a dictionary lookup to get the message ID. This - version returns 1, which is the base message ID in win32service.pyd. - """ - return 1 - - def getEventCategory(self, record): - """ - Return the event category for the record. Override this if you - want to specify your own categories. This version returns 0. - """ - return 0 - - def getEventType(self, record): - """ - Return the event type for the record. Override this if you want - to specify your own types. This version does a mapping using the - handler's typemap attribute, which is set up in __init__() to a - dictionary which contains mappings for DEBUG, INFO, WARN, ERROR - and CRITICAL. If you are using your own levels you will either need - to override this method or place a suitable dictionary in the - handler's typemap attribute. - """ - return self.typemap.get(record.levelno, self.deftype) - - def emit(self, record): - """ - Determine the message ID, event category and event type. Then - log the message in the NT event log. - """ - if self._welu: - try: - id = self.getMessageID(record) - cat = self.getEventCategory(record) - type = self.getEventType(record) - msg = self.format(record) - self._welu.ReportEvent(self.appname, id, cat, type, [msg]) - except: - self.handleError() - - def close(self): - """ - You can remove the application name from the registry as a - source of event log entries. However, if you do this, you will - not be able to see the events as you intended in the Event Log - Viewer - it needs to be able to access the registry to get the - DLL name. - """ - #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype) - pass - -class HTTPHandler(Handler): - """ - A class which sends records to a Web server, using either GET or - POST semantics. - """ - def __init__(self, host, url, method="GET"): - """ - Initialize the instance with the host, the request URL, and the method - ("GET" or "POST") - """ - Handler.__init__(self) - method = string.upper(method) - if method not in ["GET", "POST"]: - raise ValueError, "method must be GET or POST" - self.host = host - self.url = url - self.method = method - - def emit(self, record): - """ - Send the record to the Web server as an URL-encoded dictionary - """ - try: - import httplib, urllib - h = httplib.HTTP(self.host) - url = self.url - data = urllib.urlencode(record.__dict__) - if self.method == "GET": - if (string.find(url, '?') >= 0): - sep = '&' - else: - sep = '?' - url = url + "%c%s" % (sep, data) - h.putrequest(self.method, url) - if self.method == "POST": - h.putheader("Content-length", str(len(data))) - h.endheaders() - if self.method == "POST": - h.send(data) - h.getreply() #can't do anything with the result - except: - self.handleError() - -#--------------------------------------------------------------------------- -# Manager classes and functions -#--------------------------------------------------------------------------- - -class PlaceHolder: - """ - PlaceHolder instances are used in the Manager logger hierarchy to take - the place of nodes for which no loggers have been defined [FIXME add - example]. - """ - def __init__(self, alogger): - """ - Initialize with the specified logger being a child of this placeholder. - """ - self.loggers = [alogger] - - def append(self, alogger): - """ - Add the specified logger as a child of this placeholder. - """ - if alogger not in self.loggers: - self.loggers.append(alogger) - -# -# Determine which class to use when instantiating loggers. -# -_loggerClass = None - -def setLoggerClass(klass): - """ - Set the class to be used when instantiating a logger. The class should - define __init__() such that only a name argument is required, and the - __init__() should call Logger.__init__() - """ - if klass != Logger: - if type(klass) != types.ClassType: - raise TypeError, "setLoggerClass is expecting a class" - if not issubclass(klass, Logger): - raise TypeError, "logger not derived from logging.Logger: " + \ - klass.__name__ - global _loggerClass - _loggerClass = klass - -class Manager: - """ - There is [under normal circumstances] just one Manager instance, which - holds the hierarchy of loggers. - """ - def __init__(self, root): - """ - Initialize the manager with the root node of the logger hierarchy. - """ - self.root = root - self.disable = 0 - self.emittedNoHandlerWarning = 0 - self.loggerDict = {} - - def getLogger(self, name): - """ - Get a logger with the specified name, creating it if it doesn't - yet exist. If a PlaceHolder existed for the specified name [i.e. - the logger didn't exist but a child of it did], replace it with - the created logger and fix up the parent/child references which - pointed to the placeholder to now point to the logger. - """ - rv = None - _acquireLock() - try: - if self.loggerDict.has_key(name): - rv = self.loggerDict[name] - if isinstance(rv, PlaceHolder): - ph = rv - rv = _loggerClass(name) - rv.manager = self - self.loggerDict[name] = rv - self._fixupChildren(ph, rv) - self._fixupParents(rv) - else: - rv = _loggerClass(name) - rv.manager = self - self.loggerDict[name] = rv - self._fixupParents(rv) - finally: - _releaseLock() - return rv - - def _fixupParents(self, alogger): - """ - Ensure that there are either loggers or placeholders all the way - from the specified logger to the root of the logger hierarchy. - """ - name = alogger.name - i = string.rfind(name, ".") - rv = None - while (i > 0) and not rv: - substr = name[:i] - if not self.loggerDict.has_key(substr): - self.loggerDict[substr] = PlaceHolder(alogger) - else: - obj = self.loggerDict[substr] - if isinstance(obj, Logger): - rv = obj - else: - assert isinstance(obj, PlaceHolder) - obj.append(alogger) - i = string.rfind(name, ".", 0, i - 1) - if not rv: - rv = self.root - alogger.parent = rv - - def _fixupChildren(self, ph, alogger): - """ - Ensure that children of the placeholder ph are connected to the - specified logger. - """ - for c in ph.loggers: - if string.find(c.parent.name, alogger.name) <> 0: - alogger.parent = c.parent - c.parent = alogger - -#--------------------------------------------------------------------------- -# Logger classes and functions -#--------------------------------------------------------------------------- - -class Logger(Filterer): - """ - Instances of the Logger class represent a single logging channel. A - "logging channel" indicates an area of an application. Exactly how an - "area" is defined is up to the application developer. Since an - application can have any number of areas, logging channels are identified - by a unique string. Application areas can be nested (e.g. an area - of "input processing" might include sub-areas "read CSV files", "read - XLS files" and "read Gnumeric files"). To cater for this natural nesting, - channel names are organized into a namespace hierarchy where levels are - separated by periods, much like the Java or Python package namespace. So - in the instance given above, channel names might be "input" for the upper - level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels. - There is no arbitrary limit to the depth of nesting. - """ - def __init__(self, name, level=ALL): - """ - Initialize the logger with a name and an optional level. - """ - Filterer.__init__(self) - self.name = name - self.level = level - self.parent = None - self.propagate = 1 - self.handlers = [] - self.disabled = 0 - - def setLevel(self, lvl): - """ - Set the logging level of this logger. - """ - self.level = lvl - -# def getRoot(self): -# """ -# Get the root of the logger hierarchy. -# """ -# return Logger.root - - def debug(self, msg, *args, **kwargs): - """ - Log 'msg % args' with severity 'DEBUG'. To pass exception information, - use the keyword argument exc_info with a true value, e.g. - - logger.debug("Houston, we have a %s", "thorny problem", exc_info=1) - """ - if self.manager.disable >= DEBUG: - return - if DEBUG >= self.getEffectiveLevel(): - apply(self._log, (DEBUG, msg, args), kwargs) - - def info(self, msg, *args, **kwargs): - """ - Log 'msg % args' with severity 'INFO'. To pass exception information, - use the keyword argument exc_info with a true value, e.g. - - logger.info("Houston, we have a %s", "interesting problem", exc_info=1) - """ - if self.manager.disable >= INFO: - return - if INFO >= self.getEffectiveLevel(): - apply(self._log, (INFO, msg, args), kwargs) - - def warn(self, msg, *args, **kwargs): - """ - Log 'msg % args' with severity 'WARN'. To pass exception information, - use the keyword argument exc_info with a true value, e.g. - - logger.warn("Houston, we have a %s", "bit of a problem", exc_info=1) - """ - if self.manager.disable >= WARN: - return - if self.isEnabledFor(WARN): - apply(self._log, (WARN, msg, args), kwargs) - - def error(self, msg, *args, **kwargs): - """ - Log 'msg % args' with severity 'ERROR'. To pass exception information, - use the keyword argument exc_info with a true value, e.g. - - logger.error("Houston, we have a %s", "major problem", exc_info=1) - """ - if self.manager.disable >= ERROR: - return - if self.isEnabledFor(ERROR): - apply(self._log, (ERROR, msg, args), kwargs) - - def exception(self, msg, *args): - """ - Convenience method for logging an ERROR with exception information - """ - apply(self.error, (msg,) + args, {'exc_info': 1}) - - def critical(self, msg, *args, **kwargs): - """ - Log 'msg % args' with severity 'CRITICAL'. To pass exception - information, use the keyword argument exc_info with a true value, e.g. - - logger.critical("Houston, we have a %s", "major disaster", exc_info=1) - """ - if self.manager.disable >= CRITICAL: - return - if CRITICAL >= self.getEffectiveLevel(): - apply(self._log, (CRITICAL, msg, args), kwargs) - - fatal = critical - - def log(self, lvl, msg, *args, **kwargs): - """ - Log 'msg % args' with the severity 'lvl'. To pass exception - information, use the keyword argument exc_info with a true value, e.g. - logger.log(lvl, "We have a %s", "mysterious problem", exc_info=1) - """ - if self.manager.disable >= lvl: - return - if self.isEnabledFor(lvl): - apply(self._log, (lvl, msg, args), kwargs) - - def findCaller(self): - """ - Find the stack frame of the caller so that we can note the source - file name and line number. - """ - rv = (None, None) - frame = inspect.currentframe().f_back - while frame: - sfn = inspect.getsourcefile(frame) - if sfn: - sfn = os.path.normcase(sfn) - if sfn != _srcfile: - #print frame.f_code.co_code - lineno = inspect.getlineno(frame) - rv = (sfn, lineno) - break - frame = frame.f_back - return rv - - def makeRecord(self, name, lvl, fn, lno, msg, args, exc_info): - """ - A factory method which can be overridden in subclasses to create - specialized LogRecords. - """ - return LogRecord(name, lvl, fn, lno, msg, args, exc_info) - - def _log(self, lvl, msg, args, exc_info=None): - """ - Low-level logging routine which creates a LogRecord and then calls - all the handlers of this logger to handle the record. - """ - if inspect and _srcfile: - _acquireLock() - try: - fn, lno = self.findCaller() - finally: - _releaseLock() - else: - fn, lno = "", 0 - if exc_info: - exc_info = sys.exc_info() - record = self.makeRecord(self.name, lvl, fn, lno, msg, args, exc_info) - self.handle(record) - - def handle(self, record): - """ - Call the handlers for the specified record. This method is used for - unpickled records received from a socket, as well as those created - locally. Logger-level filtering is applied. - """ - if (not self.disabled) and self.filter(record): - self.callHandlers(record) - - def addHandler(self, hdlr): - """ - Add the specified handler to this logger. - """ - if not (hdlr in self.handlers): - self.handlers.append(hdlr) - - def removeHandler(self, hdlr): - """ - Remove the specified handler from this logger. - """ - if hdlr in self.handlers: - hdlr.close() - self.handlers.remove(hdlr) - - def callHandlers(self, record): - """ - Loop through all handlers for this logger and its parents in the - logger hierarchy. If no handler was found, output a one-off error - message to sys.stderr. Stop searching up the hierarchy whenever a - logger with the "propagate" attribute set to zero is found - that - will be the last logger whose handlers are called. - """ - c = self - found = 0 - while c: - for hdlr in c.handlers: - found = found + 1 - if record.levelno >= hdlr.level: - hdlr.handle(record) - if not c.propagate: - c = None #break out - else: - c = c.parent - if (found == 0) and not self.manager.emittedNoHandlerWarning: - sys.stderr.write("No handlers could be found for logger" - " \"%s\"\n" % self.name) - self.manager.emittedNoHandlerWarning = 1 - - def getEffectiveLevel(self): - """ - Loop through this logger and its parents in the logger hierarchy, - looking for a non-zero logging level. Return the first one found. - """ - logger = self - while logger: - if logger.level: - return logger.level - logger = logger.parent - return ALL - - def isEnabledFor(self, lvl): - """ - Is this logger enabled for level lvl? - """ - if self.manager.disable >= lvl: - return 0 - return lvl >= self.getEffectiveLevel() - -class RootLogger(Logger): - """ - A root logger is not that different to any other logger, except that - it must have a logging level and there is only one instance of it in - the hierarchy. - """ - def __init__(self, lvl): - """ - Initialize the logger with the name "root". - """ - Logger.__init__(self, "root", lvl) - -_loggerClass = Logger - -root = RootLogger(DEBUG) -Logger.root = root -Logger.manager = Manager(Logger.root) - -#--------------------------------------------------------------------------- -# Configuration classes and functions -#--------------------------------------------------------------------------- - -BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" - -def basicConfig(): - """ - Do basic configuration for the logging system by creating a - StreamHandler with a default Formatter and adding it to the - root logger. - """ - if len(root.handlers) == 0: - hdlr = StreamHandler() - fmt = Formatter(BASIC_FORMAT) - hdlr.setFormatter(fmt) - root.addHandler(hdlr) - -def fileConfig(fname): - """ - Read the logging configuration from a ConfigParser-format file. This can - be called several times from an application, allowing an end user the - ability to select from various pre-canned configurations (if the - developer provides a mechanism to present the choices and load the chosen - configuration). - """ - import ConfigParser - - cp = ConfigParser.ConfigParser() - cp.read(fname) - #first, do the formatters... - flist = cp.get("formatters", "keys") - if len(flist): - flist = string.split(flist, ",") - formatters = {} - for form in flist: - sectname = "formatter_%s" % form - opts = cp.options(sectname) - if "format" in opts: - fs = cp.get(sectname, "format", 1) - else: - fs = None - if "datefmt" in opts: - dfs = cp.get(sectname, "datefmt", 1) - else: - dfs = None - f = Formatter(fs, dfs) - formatters[form] = f - #next, do the handlers... - #critical section... - _acquireLock() - try: - try: - #first, lose the existing handlers... - _handlers.clear() - #now set up the new ones... - hlist = cp.get("handlers", "keys") - if len(hlist): - hlist = string.split(hlist, ",") - handlers = {} - fixups = [] #for inter-handler references - for hand in hlist: - sectname = "handler_%s" % hand - klass = cp.get(sectname, "class") - opts = cp.options(sectname) - if "formatter" in opts: - fmt = cp.get(sectname, "formatter") - else: - fmt = "" - klass = eval(klass) - args = cp.get(sectname, "args") - args = eval(args) - h = apply(klass, args) - if "level" in opts: - lvl = cp.get(sectname, "level") - h.setLevel(_levelNames[lvl]) - if len(fmt): - h.setFormatter(formatters[fmt]) - #temporary hack for FileHandler and MemoryHandler. - if klass == FileHandler: - maxsize = 0 - if "maxsize" in opts: - ms = cp.getint(sectname, "maxsize") - if ms > 0: - maxsize = ms - if maxsize: - backcount = 0 - if "backcount" in opts: - bc = cp.getint(sectname, "backcount") - if bc > 0: - backcount = bc - h.setRollover(maxsize, backcount) - elif klass == MemoryHandler: - if "target" in opts: - target = cp.get(sectname,"target") - else: - target = "" - if len(target): #the target handler may not be loaded yet, so keep for later... - fixups.append((h, target)) - handlers[hand] = h - #now all handlers are loaded, fixup inter-handler references... - for fixup in fixups: - h = fixup[0] - t = fixup[1] - h.setTarget(handlers[t]) - #at last, the loggers...first the root... - llist = cp.get("loggers", "keys") - llist = string.split(llist, ",") - llist.remove("root") - sectname = "logger_root" - log = root - opts = cp.options(sectname) - if "level" in opts: - lvl = cp.get(sectname, "level") - log.setLevel(_levelNames[lvl]) - for h in root.handlers: - root.removeHandler(h) - hlist = cp.get(sectname, "handlers") - if len(hlist): - hlist = string.split(hlist, ",") - for hand in hlist: - log.addHandler(handlers[hand]) - #and now the others... - #we don't want to lose the existing loggers, - #since other threads may have pointers to them. - #existing is set to contain all existing loggers, - #and as we go through the new configuration we - #remove any which are configured. At the end, - #what's left in existing is the set of loggers - #which were in the previous configuration but - #which are not in the new configuration. - existing = root.manager.loggerDict.keys() - #now set up the new ones... - for log in llist: - sectname = "logger_%s" % log - qn = cp.get(sectname, "qualname") - opts = cp.options(sectname) - if "propagate" in opts: - propagate = cp.getint(sectname, "propagate") - else: - propagate = 1 - logger = getLogger(qn) - if qn in existing: - existing.remove(qn) - if "level" in opts: - lvl = cp.get(sectname, "level") - logger.setLevel(_levelNames[lvl]) - for h in logger.handlers: - logger.removeHandler(h) - logger.propagate = propagate - logger.disabled = 0 - hlist = cp.get(sectname, "handlers") - if len(hlist): - hlist = string.split(hlist, ",") - for hand in hlist: - logger.addHandler(handlers[hand]) - #Disable any old loggers. There's no point deleting - #them as other threads may continue to hold references - #and by disabling them, you stop them doing any logging. - for log in existing: - root.manager.loggerDict[log].disabled = 1 - except: - import traceback - ei = sys.exc_info() - traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) - del ei - finally: - _releaseLock() - -#--------------------------------------------------------------------------- -# Utility functions at module level. -# Basically delegate everything to the root logger. -#--------------------------------------------------------------------------- - -def getLogger(name=None): - """ - Return a logger with the specified name, creating it if necessary. - If no name is specified, return the root logger. - """ - if name: - return Logger.manager.getLogger(name) - else: - return root - -def getRootLogger(): - """ - Return the root logger. Note that getLogger('') now does the same thing, - so this function is deprecated and may disappear in the future. - """ - return root - -def critical(msg, *args, **kwargs): - """ - Log a message with severity 'CRITICAL' on the root logger. - """ - if len(root.handlers) == 0: - basicConfig() - apply(root.critical, (msg,)+args, kwargs) - -fatal = critical - -def error(msg, *args, **kwargs): - """ - Log a message with severity 'ERROR' on the root logger. - """ - if len(root.handlers) == 0: - basicConfig() - apply(root.error, (msg,)+args, kwargs) - -def exception(msg, *args): - """ - Log a message with severity 'ERROR' on the root logger, - with exception information. - """ - apply(error, (msg,)+args, {'exc_info': 1}) - -def warn(msg, *args, **kwargs): - """ - Log a message with severity 'WARN' on the root logger. - """ - if len(root.handlers) == 0: - basicConfig() - apply(root.warn, (msg,)+args, kwargs) - -def info(msg, *args, **kwargs): - """ - Log a message with severity 'INFO' on the root logger. - """ - if len(root.handlers) == 0: - basicConfig() - apply(root.info, (msg,)+args, kwargs) - -def debug(msg, *args, **kwargs): - """ - Log a message with severity 'DEBUG' on the root logger. - """ - if len(root.handlers) == 0: - basicConfig() - apply(root.debug, (msg,)+args, kwargs) - -def disable(level): - """ - Disable all logging calls less severe than 'level'. - """ - root.manager.disable = level - -def shutdown(): - """ - Perform any cleanup actions in the logging system (e.g. flushing - buffers). Should be called at application exit. - """ - for h in _handlers.keys(): - h.flush() - h.close() - -# -# The following code implements a socket listener for on-the-fly -# reconfiguration of logging. -# -# _listener holds the server object doing the listening -_listener = None - -def listen(port=DEFAULT_LOGGING_CONFIG_PORT): - """ - Start up a socket server on the specified port, and listen for new - configurations. These will be sent as a file suitable for processing - by fileConfig(). Returns a Thread object on which you can call start() - to start the server, and which you can join() when appropriate. - To stop the server, call stopListening(). - """ - if not thread: - raise NotImplementedError, "listen() needs threading to work" - - import threading - - class ConfigStreamHandler(StreamRequestHandler): - """ - Handler for a logging configuration request. It expects a - completely new logging configuration and uses fileConfig to - install it. - """ - def handle(self): - """ - Each request is expected to be a 2-byte length, - followed by the config file. Uses fileConfig() to do the - needful. - """ - import tempfile - try: - conn = self.connection - chunk = conn.recv(2) - if len(chunk) == 2: - slen = (ord(chunk[0]) << 8) | ord(chunk[1]) - chunk = self.connection.recv(slen) - while len(chunk) < slen: - chunk = chunk + conn.recv(slen - len(chunk)) - #Apply new configuration. We'd like to be able to - #create a StringIO and pass that in, but unfortunately - #1.5.2 ConfigParser does not support reading file - #objects, only actual files. So we create a temporary - #file and remove it later. - file = tempfile.mktemp(".ini") - f = open(file, "w") - f.write(chunk) - f.close() - fileConfig(file) - os.remove(file) - except socket.error, e: - if type(e.args) != types.TupleType: - raise - else: - errcode = e.args[0] - if errcode != RESET_ERROR: - raise - - class ConfigSocketReceiver(ThreadingTCPServer): - """ - A simple TCP socket-based logging config receiver. - """ - - allow_reuse_address = 1 - - def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT, - handler=None): - ThreadingTCPServer.__init__(self, (host, port), handler) - _acquireLock() - self.abort = 0 - _releaseLock() - self.timeout = 1 - - def serve_until_stopped(self): - import select - abort = 0 - while not abort: - rd, wr, ex = select.select([self.socket.fileno()], - [], [], - self.timeout) - if rd: - self.handle_request() - _acquireLock() - abort = self.abort - _releaseLock() - - def serve(rcvr, hdlr): - server = rcvr(handler=hdlr) - global _listener - _acquireLock() - _listener = server - _releaseLock() - server.serve_until_stopped() - - return threading.Thread(target=serve, args=(ConfigSocketReceiver, ConfigStreamHandler)) - -def stopListening(): - """ - Stop the listening server which was created with a call to listen(). - """ - if _listener: - _acquireLock() - _listener.abort = 1 - _listener = None - _releaseLock() - - -# bicycle repair man stuff - -bike_logger_initialised = 0 - -def init(): - global bike_logger_initialised - if not bike_logger_initialised: - log = getLogger("bike") - h = StreamHandler() - h.setFormatter(Formatter( - fmt="%(pathname)s:%(lineno)s:%(levelname)s %(message)s")) - log.addHandler(h) - bike_logger_initialised = 1 - -if __name__ == "__main__": - print __doc__ diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/mock.py --- a/vim/sadness/bike/bike/mock.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -# -# (c) Dave Kirby 2001 -# dkirby@bigfoot.com -# -# Call interceptor code by Phil Dawes (pdawes@users.sourceforge.net) - -''' -The Mock class emulates any other class for testing purposes. -All method calls are stored for later examination. -The class constructor takes a dictionary of method names and the values -they return. Methods that are not in the dictionary will return None. -''' -import inspect - - -class Mock: - def __init__(self, returnValues=None ): - self.mockCalledMethods = {} - self.mockAllCalledMethods = [] - self.mockReturnValues = returnValues or {} - self.setupMethodInterceptors() - - def setupMethodInterceptors(self): - if self.__class__ != Mock: # check we've been subclassed - methods = inspect.getmembers(self.__class__,inspect.ismethod) - for m in methods: - name = m[0] - self.__dict__[name] = MethodCallInterceptor(name,self) - - def __getattr__( self, name ): - return MockCaller( name, self ) - - def getAllCalls(self): - '''return a list of MockCall objects, - representing all the methods in the order they were called''' - return self.mockAllCalledMethods - - def getNamedCalls(self, methodName ): - '''return a list of MockCall objects, - representing all the calls to the named method in the order they were called''' - return self.mockCalledMethods.get(methodName, [] ) - - def assertNamedCall(self,methodName,*args): - # assert call was made once - assert(len(self.getNamedCalls(methodName)) == 1) - # assert args are correct - argsdict = inspect.getargvalues(inspect.currentframe())[3] - i=0 - for arg in argsdict['args']: - assert(self.getNamedCalls(methodName)[0].getParam(i) == arg) - i += 1 - - def assertCallInOrder(self,methodName,*args): - ''' Convenience method to allow client to check that calls were - made in the right order. Call once for each methodcall''' - - # initialise callIndex. (n.b. __getattr__ method complicates - # this since attrs are MockCaller instances by default) - if type(self.callIndex) != type(1): - self.callIndex=0 - - call = self.getAllCalls()[self.callIndex] - # assert method name is correct - assert(call.getName() == methodName) - # assert args are correct - argsdict = inspect.getargvalues(inspect.currentframe())[3] - i=0 - for arg in argsdict['args']: - assert(call.getParam(i) == arg) - i += 1 - # assert num args are correct - assert(call.getNumParams() == i) - self.callIndex += 1 - - def assertNoMoreCalls(self): - assert(len(self.getAllCalls()) == self.callIndex) - -class MockCall: - def __init__(self, name, params, kwparams ): - self.name = name - self.params = params - self.kwparams = kwparams - def getParam( self, n ): - if type(n) == type(1): - return self.params[n] - elif type(n) == type(''): - return self.kwparams[n] - else: - raise IndexError, 'illegal index type for getParam' - - def getNumParams(self): - return len(self.params) - - - def getName(self): - return self.name - - #pretty-print the method call - def __str__(self): - s = self.name + "(" - sep = '' - for p in self.params: - s = s + sep + repr(p) - sep = ', ' - for k,v in self.kwparams.items(): - s = s + sep + k+ '='+repr(v) - sep = ', ' - s = s + ')' - return s - def __repr__(self): - return self.__str__() - -class MockCaller: - def __init__( self, name, mock): - self.name = name - self.mock = mock - def __call__(self, *params, **kwparams ): - self.recordCall(params,kwparams) - return self.mock.mockReturnValues.get(self.name) - - def recordCall(self,params,kwparams): - thisCall = MockCall( self.name, params, kwparams ) - calls = self.mock.mockCalledMethods.get(self.name, [] ) - if calls == []: - self.mock.mockCalledMethods[self.name] = calls - calls.append(thisCall) - self.mock.mockAllCalledMethods.append(thisCall) - - -# intercepts the call and records it, then delegates to the real call -class MethodCallInterceptor(MockCaller): - - def __call__(self, *params, **kwparams ): - self.recordCall(params,kwparams) - return self.makeCall(params) - - def makeCall(self,params): - argsstr="(self.mock" - for i in range(len(params)): - argsstr += ",params["+`i`+"]" - argsstr+=")" - return eval("self.mock.__class__."+self.name+argsstr) - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/__init__.py --- a/vim/sadness/bike/bike/parsing/__init__.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -#from addtypeinfo import addtypeinfo -#from load import load -#from brmtransformer import parse diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/constants.py --- a/vim/sadness/bike/bike/parsing/constants.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -messages={"PARSING":"Parsing","ADDTYPEINFO":"Deducing Type Information"} - -MAXCALLDEPTH = 10 diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/fastparser.py --- a/vim/sadness/bike/bike/parsing/fastparser.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -#!/usr/bin/env python -from bike.parsing.fastparserast import * -from bike.parsing.parserutils import * -from parser import ParserError -#import exceptions - -indentRE = re.compile("^\s*(\w+)") - -# returns a tree of objects representing nested classes and functions -# in the source -def fastparser(src,modulename="",filename=""): - try: - return fastparser_impl(src,modulename,filename) - except RuntimeError, ex: # if recursive call exceeds maximum depth - if str(ex) == "maximum recursion limit exceeded": - raise ParserError,"maximum recursion depth exceeded when fast-parsing src "+filename - else: - raise - -def fastparser_impl(src,modulename,filename): - lines = src.splitlines(1) - maskedSrc = maskPythonKeywordsInStringsAndComments(src) - maskedLines = maskedSrc.splitlines(1) - root = Module(filename,modulename,lines,maskedSrc) - parentnode = root - lineno = 0 - for line in maskedLines: - lineno+=1 - #print "line",lineno,":",line - m = indentRE.match(line) - if m: - indent = m.start(1) - tokenstr = m.group(1) - if tokenstr == "import" or tokenstr == "from": - while indent <= parentnode.indent: # root indent is -TABWIDTH - parentnode = parentnode.getParent() - try: - parentnode.importlines.append(lineno) - except AttributeError: - parentnode.importlines = [lineno] - elif tokenstr == "class": - m2 = classNameRE.match(line) - if m2: - n = Class(m2.group(1), filename, root, lineno, indent, lines, maskedSrc) - root.flattenedNodes.append(n) - - while indent <= parentnode.indent: - parentnode = parentnode.getParent() - parentnode.addChild(n) - parentnode = n - - elif tokenstr == "def": - m2 = fnNameRE.match(line) - if m2: - n = Function(m2.group(1), filename, root, lineno, indent, lines, maskedSrc) - root.flattenedNodes.append(n) - - while indent <= parentnode.indent: - parentnode = parentnode.getParent() - parentnode.addChild(n) - parentnode = n - - elif indent <= parentnode.indent and \ - tokenstr in ['if','for','while','try']: - parentnode = parentnode.getParent() - while indent <= parentnode.indent: - parentnode = parentnode.getParent() - - return root - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/fastparserast.py --- a/vim/sadness/bike/bike/parsing/fastparserast.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -from __future__ import generators -from parserutils import generateLogicalLines, maskStringsAndComments, maskStringsAndRemoveComments -import re -import os -import compiler -from bike.transformer.save import resetOutputQueue - -TABWIDTH = 4 - -classNameRE = re.compile("^\s*class\s+(\w+)") -fnNameRE = re.compile("^\s*def\s+(\w+)") - -_root = None - -def getRoot(): - global _root - if _root is None: - resetRoot() - return _root - -def resetRoot(root = None): - global _root - _root = root or Root() - _root.unittestmode = False - resetOutputQueue() - - -def getModule(filename_path): - from bike.parsing.load import CantLocateSourceNodeException, getSourceNode - try: - sourcenode = getSourceNode(filename_path) - return sourcenode.fastparseroot - except CantLocateSourceNodeException: - return None - -def getPackage(directory_path): - from bike.parsing.pathutils import getRootDirectory - rootdir = getRootDirectory(directory_path) - if rootdir == directory_path: - return getRoot() - else: - return Package(directory_path, - os.path.basename(directory_path)) - - - - - -class Root: - def __init__(self, pythonpath = None): - # singleton hack to allow functions in query package to appear - # 'stateless' - resetRoot(self) - - # this is to get round a python optimisation which reuses an - # empty list as a default arg. unfortunately the client of - # this method may fill that list, so it's not empty - if not pythonpath: - pythonpath = [] - self.pythonpath = pythonpath - - def __repr__(self): - return "Root()" - #return "Root(%s)"%(self.getChildNodes()) - - - # dummy method - def getChild(self,name): - return None - -class Package: - def __init__(self, path, name): - self.path = path - self.name = name - - def getChild(self,name): - from bike.parsing.newstuff import getModule - return getModule(os.path.join(self.path,name+".py")) - - def __repr__(self): - return "Package(%s,%s)"%(self.path, self.name) - -# used so that linenum can be an attribute -class Line(str): - pass - -class StructuralNode: - def __init__(self, filename, srclines, modulesrc): - self.childNodes = [] - self.filename = filename - self._parent = None - self._modulesrc = modulesrc - self._srclines = srclines - self._maskedLines = None - - def addChild(self, node): - self.childNodes.append(node) - node.setParent(self) - - def setParent(self, parent): - self._parent = parent - - def getParent(self): - return self._parent - - def getChildNodes(self): - return self.childNodes - - def getChild(self,name): - matches = [c for c in self.getChildNodes() if c.name == name] - if matches != []: - return matches[0] - - def getLogicalLine(self,physicalLineno): - return generateLogicalLines(self._srclines[physicalLineno-1:]).next() - - # badly named: actually returns line numbers of import statements - def getImportLineNumbers(self): - try: - return self.importlines - except AttributeError: - return[] - - def getLinesNotIncludingThoseBelongingToChildScopes(self): - srclines = self.getMaskedModuleLines() - lines = [] - lineno = self.getStartLine() - for child in self.getChildNodes(): - lines+=srclines[lineno-1: child.getStartLine()-1] - lineno = child.getEndLine() - lines+=srclines[lineno-1: self.getEndLine()-1] - return lines - - - def generateLinesNotIncludingThoseBelongingToChildScopes(self): - srclines = self.getMaskedModuleLines() - lines = [] - lineno = self.getStartLine() - for child in self.getChildNodes(): - for line in srclines[lineno-1: child.getStartLine()-1]: - yield self.attachLinenum(line,lineno) - lineno +=1 - lineno = child.getEndLine() - for line in srclines[lineno-1: self.getEndLine()-1]: - yield self.attachLinenum(line,lineno) - lineno +=1 - - def generateLinesWithLineNumbers(self,startline=1): - srclines = self.getMaskedModuleLines() - for lineno in range(startline,len(srclines)+1): - yield self.attachLinenum(srclines[lineno-1],lineno) - - def attachLinenum(self,line,lineno): - line = Line(line) - line.linenum = lineno - return line - - def getMaskedModuleLines(self): - from bike.parsing.load import Cache - try: - maskedlines = Cache.instance.maskedlinescache[self.filename] - except: - # make sure src is actually masked - # (could just have keywords masked) - maskedsrc = maskStringsAndComments(self._modulesrc) - maskedlines = maskedsrc.splitlines(1) - Cache.instance.maskedlinescache[self.filename] = maskedlines - return maskedlines - - -class Module(StructuralNode): - def __init__(self, filename, name, srclines, maskedsrc): - StructuralNode.__init__(self, filename, srclines, maskedsrc) - self.name = name - self.indent = -TABWIDTH - self.flattenedNodes = [] - self.module = self - - def getMaskedLines(self): - return self.getMaskedModuleLines() - - def getFlattenedListOfChildNodes(self): - return self.flattenedNodes - - def getStartLine(self): - return 1 - - def getEndLine(self): - return len(self.getMaskedModuleLines())+1 - - def getSourceNode(self): - return self.sourcenode - - def setSourceNode(self, sourcenode): - self.sourcenode = sourcenode - - def matchesCompilerNode(self,node): - return isinstance(node,compiler.ast.Module) and \ - node.name == self.name - - def getParent(self): - if self._parent is not None: - return self._parent - else: - from newstuff import getPackage - return getPackage(os.path.dirname(self.filename)) - - - def __str__(self): - return "bike:Module:"+self.filename - -indentRE = re.compile("^(\s*)\S") -class Node: - # module = the module node - # linenum = starting line number - def __init__(self, name, module, linenum, indent): - self.name = name - self.module = module - self.linenum = linenum - self.endline = None - self.indent = indent - - def getMaskedLines(self): - return self.getMaskedModuleLines()[self.getStartLine()-1:self.getEndLine()-1] - - def getStartLine(self): - return self.linenum - - def getEndLine(self): - if self.endline is None: - physicallines = self.getMaskedModuleLines() - lineno = self.linenum - logicallines = generateLogicalLines(physicallines[lineno-1:]) - - # skip the first line, because it's the declaration - line = logicallines.next() - lineno+=line.count("\n") - - # scan to the end of the fn - for line in logicallines: - #print lineno,":",line, - match = indentRE.match(line) - if match and match.end()-1 <= self.indent: - break - lineno+=line.count("\n") - self.endline = lineno - return self.endline - - # linenum starts at 0 - def getLine(self, linenum): - return self._srclines[(self.getStartLine()-1) + linenum] - - -baseClassesRE = re.compile("class\s+[^(]+\(([^)]+)\):") - -class Class(StructuralNode, Node): - def __init__(self, name, filename, module, linenum, indent, srclines, maskedmodulesrc): - StructuralNode.__init__(self, filename, srclines, maskedmodulesrc) - Node.__init__(self, name, module, linenum, indent) - self.type = "Class" - - - def getBaseClassNames(self): - #line = self.getLine(0) - line = self.getLogicalLine(self.getStartLine()) - match = baseClassesRE.search(line) - if match: - return [s.strip()for s in match.group(1).split(",")] - else: - return [] - - def getColumnOfName(self): - match = classNameRE.match(self.getLine(0)) - return match.start(1) - - def __repr__(self): - return "" % self.name - - def __str__(self): - return "bike:Class:"+self.filename+":"+\ - str(self.getStartLine())+":"+self.name - - def matchesCompilerNode(self,node): - return isinstance(node,compiler.ast.Class) and \ - node.name == self.name - - def __eq__(self,other): - return isinstance(other,Class) and \ - self.filename == other.filename and \ - self.getStartLine() == other.getStartLine() - -# describes an instance of a class -class Instance: - def __init__(self, type): - assert type is not None - self._type = type - - def getType(self): - return self._type - - def __str__(self): - return "Instance(%s)"%(self.getType()) - - -class Function(StructuralNode, Node): - def __init__(self, name, filename, module, linenum, indent, - srclines, maskedsrc): - StructuralNode.__init__(self, filename, srclines, maskedsrc) - Node.__init__(self, name, module, linenum, indent) - self.type = "Function" - - def getColumnOfName(self): - match = fnNameRE.match(self.getLine(0)) - return match.start(1) - - def __repr__(self): - return "" % self.name - - def __str__(self): - return "bike:Function:"+self.filename+":"+\ - str(self.getStartLine())+":"+self.name - - def matchesCompilerNode(self,node): - return isinstance(node,compiler.ast.Function) and \ - node.name == self.name - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/load.py --- a/vim/sadness/bike/bike/parsing/load.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -from bike.globals import * -import os -from bike.parsing.fastparser import fastparser - -class Cache: - def __init__(self): - self.reset() - def reset(self): - self.srcnodecache = {} - self.typecache = {} - self.maskedlinescache = {} - - instance = None - -Cache.instance = Cache() - -class CantLocateSourceNodeException(Exception): pass - -def getSourceNode(filename_path): - #print "getSourceNode:",filename_path - sourcenode = None - - try: - sourcenode = Cache.instance.srcnodecache[filename_path] - except KeyError: - pass - - if sourcenode is None: - from bike.parsing.newstuff import translateFnameToModuleName - sourcenode = SourceFile.createFromFile(filename_path, - translateFnameToModuleName(filename_path)) - if sourcenode is None: - raise CantLocateSourceNodeException(filename_path) - - Cache.instance.srcnodecache[filename_path]=sourcenode - return sourcenode - -class SourceFile: - - def createFromString(filename, modulename, src): - return SourceFile(filename,modulename,src) - createFromString = staticmethod(createFromString) - - def createFromFile(filename,modulename): - try: - f = file(filename) - src = f.read() - f.close() - except IOError: - return None - else: - return SourceFile(filename,modulename,src) - - createFromFile = staticmethod(createFromFile) - - def __init__(self, filename, modulename, src): - - if os.path.isabs(filename): - self.filename = filename - else: - self.filename = os.path.abspath(filename) - self.modulename = modulename - - self.resetWithSource(src) - - def resetWithSource(self, source): - # fastparser ast - self.fastparseroot = fastparser(source,self.modulename,self.filename) - self.fastparseroot.setSourceNode(self) - self._lines = source.splitlines(1) - self.sourcenode = self - - def __repr__(self): - return "Source(%s,%s)"%('source', self.filename) - - def getChildNodes(self): - return self.fastparseroot.getChildNodes() - - def getSource(self): - return "".join(self.getLines()) - - def getLine(self,linenum): - return self.getLines()[linenum-1] - - # TODO: rename me! - def getFlattenedListOfFastParserASTNodes(self): - return self.fastparseroot.getFlattenedListOfChildNodes() - - def getLines(self): - return self._lines - - - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/newstuff.py --- a/vim/sadness/bike/bike/parsing/newstuff.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -from __future__ import generators -# Holding module for scaffolding needed to transition parsing package -# into stateless design -import os -import re -from bike.parsing.pathutils import getRootDirectory, getPackageBaseDirectory, \ - filenameToModulePath, getPathOfModuleOrPackage, getFilesForName -from bike.parsing.fastparserast import Module, Package, getRoot, getPackage, getModule -import sys -from bike.parsing.load import getSourceNode, CantLocateSourceNodeException - - -def translateFnameToModuleName(filename_path): - return filenameToModulePath(filename_path) - - - -# scope is the scope to search from -def getModuleOrPackageUsingFQN(fqn, dirpath=None): - pythonpath = getPythonPath() - #print "getModuleOrPackageUsingFQN",pythonpath,fqn - if dirpath is not None: - assert os.path.isdir(dirpath) - pythonpath = [dirpath] + pythonpath - filename = getPathOfModuleOrPackage(fqn,pythonpath) - #print "getModuleOrPackageUsingFQN - filename",filename - if filename is not None: - if os.path.isdir(filename): - return getPackage(filename) - else: - return getModule(filename) - else: - return None - -def getPythonPath(): - return getRoot().pythonpath - - -def generateModuleFilenamesInPythonPath(contextFilename): - files = [] - rootdir = getRootDirectory(contextFilename) - if rootdir in getPythonPath(): - # just search the pythonpath - for path in getPythonPath(): - for file in getFilesForName(path): - if file not in files: # check for duplicates - files.append(file) - yield file - else: - # search the package hierarchy containing contextFilename - # in addition to pythonpath - basedir = getPackageBaseDirectory(contextFilename) - for path in [basedir] + getPythonPath(): - for file in getFilesForName(path): - if file not in files: # check for duplicates - files.append(file) - yield file - - # and search the files immediately above the package hierarchy - for file in getFilesForName(os.path.join(rootdir,"*.py")): - if file not in files: # check for duplicates - files.append(file) - yield file - -def generateModuleFilenamesInPackage(filenameInPackage): - basedir = getPackageBaseDirectory(filenameInPackage) - for file in getFilesForName(basedir): - yield file - - - -# search all sourcenodes globally from the perspective of file 'contextFilename' -def getSourceNodesContainingRegex(regexstr,contextFilename): - regex = re.compile(regexstr) - for fname in generateModuleFilenamesInPythonPath(contextFilename): - try: - f = file(fname) - src = f.read() - finally: - f.close() - if regex.search(src) is not None: - yield getSourceNode(fname) - - - - -fromRegex = re.compile("^\s*from\s+(\w+)\s+import") -importregex = re.compile("^\s*import\s+(\w+)") - -# fileInPackage is the filename of a file in the package hierarchy -# generates file and directory paths -def generatePackageDependencies(fileInPackage): - rejectPackagePaths = [getPackageBaseDirectory(fileInPackage)] - for fname in generateModuleFilenamesInPackage(fileInPackage): - - try: - f = file(fname) - src = f.read() - finally: - f.close() - - packagepath = None - - for line in src.splitlines(): - match = fromRegex.search(line) or importregex.search(line) - if match is not None: - modulepath = match.group(1) - packagename = modulepath.split('.')[0] - packagepath = getPathOfModuleOrPackage(packagename, - getPythonPath()) - if packagepath is not None and \ - packagepath not in rejectPackagePaths: - rejectPackagePaths.append(packagepath) # avoid duplicates - yield packagepath diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/parserutils.py --- a/vim/sadness/bike/bike/parsing/parserutils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -from __future__ import generators -import re - -escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')") - -# changess \" \' and \\ into ** so that text searches -# for " and ' won't hit escaped ones -def maskEscapedQuotes(src): - return escapedQuotesRE.sub("**", src) - -stringsAndCommentsRE = \ - re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL) - -import string -#transtable = string.maketrans('classdefifforwhiletry', "*********************") - -# performs a transformation on all of the comments and strings so that -# text searches for python keywords won't accidently find a keyword in -# a string or comment -def maskPythonKeywordsInStringsAndComments(src): - src = escapedQuotesRE.sub("**", src) - allstrings = stringsAndCommentsRE.split(src) - # every odd element is a string or comment - for i in xrange(1, len(allstrings), 2): - allstrings[i] = allstrings[i].upper() - #allstrings[i] = allstrings[i].translate(transtable) - return "".join(allstrings) - - -allchars = string.maketrans("", "") -allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:] -allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline)) - - -# replaces all chars in a string or a comment with * (except newlines). -# this ensures that text searches don't mistake comments for keywords, and that all -# matches are in the same line/comment as the original -def maskStringsAndComments(src): - src = escapedQuotesRE.sub("**", src) - allstrings = stringsAndCommentsRE.split(src) - # every odd element is a string or comment - for i in xrange(1, len(allstrings), 2): - if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'): - allstrings[i] = allstrings[i][:3]+ \ - allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \ - allstrings[i][-3:] - else: - allstrings[i] = allstrings[i][0]+ \ - allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \ - allstrings[i][-1] - - return "".join(allstrings) - - -# replaces all chars in a string or a comment with * (except newlines). -# this ensures that text searches don't mistake comments for keywords, and that all -# matches are in the same line/comment as the original -def maskStringsAndRemoveComments(src): - src = escapedQuotesRE.sub("**", src) - allstrings = stringsAndCommentsRE.split(src) - # every odd element is a string or comment - for i in xrange(1, len(allstrings), 2): - if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'): - allstrings[i] = allstrings[i][:3]+ \ - allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \ - allstrings[i][-3:] - elif allstrings[i].startswith("#"): - allstrings[i] = '\n' - else: - allstrings[i] = allstrings[i][0]+ \ - allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \ - allstrings[i][-1] - return "".join(allstrings) - - -implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}')) -emptyHangingBraces = [0,0,0,0,0] -linecontinueRE = re.compile(r"\\\s*(#.*)?$") -multiLineStringsRE = \ - re.compile("(^.*?\"\"\".*?\"\"\".*?$|^.*?'''.*?'''.*?$)", re.DOTALL) - -#def splitLogicalLines(src): -# src = multiLineStringsRE.split(src) - -# splits the string into logical lines. This requires the comments to -# be removed, and strings masked (see other fns in this module) -def splitLogicalLines(src): - physicallines = src.splitlines(1) - return [x for x in generateLogicalLines(physicallines)] - - -class UnbalancedBracesException: pass - -# splits the string into logical lines. This requires the strings -# masked (see other fns in this module) -# Physical Lines *Must* start on a non-continued non-in-a-comment line -# (although detects unbalanced braces) -def generateLogicalLines(physicallines): - tmp = [] - hangingBraces = list(emptyHangingBraces) - hangingComments = 0 - for line in physicallines: - # update hanging braces - for i in range(len(implicitContinuationChars)): - contchar = implicitContinuationChars[i] - numHanging = hangingBraces[i] - hangingBraces[i] = numHanging+line.count(contchar[0]) - \ - line.count(contchar[1]) - - hangingComments ^= line.count('"""') % 2 - hangingComments ^= line.count("'''") % 2 - - if hangingBraces[0] < 0 or \ - hangingBraces[1] < 0 or \ - hangingBraces[2] < 0: - raise UnbalancedBracesException() - - if linecontinueRE.search(line): - tmp.append(line) - elif hangingBraces != emptyHangingBraces: - tmp.append(line) - elif hangingComments: - tmp.append(line) - else: - tmp.append(line) - yield "".join(tmp) - tmp = [] - - -# see above but yields (line,linenum) -# needs physicallines to have linenum attribute -# TODO: refactor with previous function -def generateLogicalLinesAndLineNumbers(physicallines): - tmp = [] - hangingBraces = list(emptyHangingBraces) - hangingComments = 0 - linenum = None - for line in physicallines: - if tmp == []: - linenum = line.linenum - - # update hanging braces - for i in range(len(implicitContinuationChars)): - contchar = implicitContinuationChars[i] - numHanging = hangingBraces[i] - hangingBraces[i] = numHanging+line.count(contchar[0]) - \ - line.count(contchar[1]) - - hangingComments ^= line.count('"""') % 2 - hangingComments ^= line.count("'''") % 2 - - if linecontinueRE.search(line): - tmp.append(line) - elif hangingBraces != emptyHangingBraces: - tmp.append(line) - elif hangingComments: - tmp.append(line) - else: - tmp.append(line) - yield "".join(tmp),linenum - tmp = [] - - - - -# takes a line of code, and decorates it with noops so that it can be -# parsed by the python compiler. -# e.g. "if foo:" -> "if foo: pass" -# returns the line, and the adjustment made to the column pos of the first char -# line must have strings and comments masked -# -# N.B. it only inserts keywords whitespace and 0's -notSpaceRE = re.compile("\s*(\S)") -commentRE = re.compile("#.*$") - -def makeLineParseable(line): - return makeLineParseableWhenCommentsRemoved(commentRE.sub("",line)) - -def makeLineParseableWhenCommentsRemoved(line): - line = line.strip() - if ":" in line: - if line.endswith(":"): - line += " pass" - if line.startswith("try"): - line += "\nexcept: pass" - elif line.startswith("except") or line.startswith("finally"): - line = "try: pass\n" + line - return line - elif line.startswith("else") or line.startswith("elif"): - line = "if 0: pass\n" + line - return line - elif line.startswith("yield"): - return ("return"+line[5:]) - return line diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/pathutils.py --- a/vim/sadness/bike/bike/parsing/pathutils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ - -# A some of this code is take from Pythius - -# Copyright (GPL) 2001 Jurgen Hermann - -from bike.globals import * -import os - -def containsAny(str, set): - """ Check whether 'str' contains ANY of the chars in 'set' - """ - return 1 in [c in str for c in set] - - - -def getPathOfModuleOrPackage(dotted_name, pathlist = None): - """ Get the filesystem path for a module or a package. - - Return the file system path to a file for a module, - and to a directory for a package. Return None if - the name is not found, or is a builtin or extension module. - """ - from bike.parsing.newstuff import getPythonPath - if pathlist is None: - pathlist = getPythonPath() - - import imp - - # split off top-most name - parts = dotted_name.split('.', 1) - - if len(parts) > 1: - # we have a dotted path, import top-level package - try: - file, pathname, description = imp.find_module(parts[0], pathlist) - if file: file.close() - except ImportError: - return None - - # check if it's indeed a package - if description[2] == imp.PKG_DIRECTORY: - # recursively handle the remaining name parts - pathname = getPathOfModuleOrPackage(parts[1], [pathname]) - else: - pathname = None - else: - # plain name - try: - file, pathname, description = imp.find_module(dotted_name, pathlist) - if file: file.close() - if description[2]not in[imp.PY_SOURCE, imp.PKG_DIRECTORY]: - pathname = None - except ImportError: - pathname = None - - return pathname - - -def getFilesForName(name): - """ Get a list of module files for a filename, a module or package name, - or a directory. - """ - import imp - - if not os.path.exists(name): - # check for glob chars - if containsAny(name, "*?[]"): - import glob - files = glob.glob(name) - list = [] - for file in files: - list.extend(getFilesForName(file)) - return list - - # try to find module or package - name = getPathOfModuleOrPackage(name) - if not name: - return[] - - if os.path.isdir(name): - # find all python files in directory - list = [] - os.path.walk(name, _visit_pyfiles, list) - return list - elif os.path.exists(name) and not name.startswith("."): - # a single file - return [name] - - return [] - -def _visit_pyfiles(list, dirname, names): - """ Helper for getFilesForName(). - """ - # get extension for python source files - if not globals().has_key('_py_ext'): - import imp - global _py_ext - _py_ext = [triple[0]for triple in imp.get_suffixes()if triple[2] == imp.PY_SOURCE][0] - - # don't recurse into CVS or Subversion directories - if 'CVS'in names: - names.remove('CVS') - if '.svn'in names: - names.remove('.svn') - - names_copy = [] + names - for n in names_copy: - if os.path.isdir(os.path.join(dirname, n))and \ - not os.path.exists(os.path.join(dirname, n, "__init__.py")): - names.remove(n) - - # add all *.py files to list - list.extend( - [os.path.join(dirname, file) - for file in names - if os.path.splitext(file)[1] == _py_ext and not file.startswith(".")]) - - -# returns the directory which holds the first package of the package -# hierarchy under which 'filename' belongs -def getRootDirectory(filename): - if os.path.isdir(filename): - dir = filename - else: - dir = os.path.dirname(filename) - while dir != "" and \ - os.path.exists(os.path.join(dir, "__init__.py")): - dir = os.path.dirname(dir) - return dir - - - -# Returns the root package directoryname of the package hierarchy -# under which 'filename' belongs -def getPackageBaseDirectory(filename): - if os.path.isdir(filename): - dir = filename - else: - dir = os.path.dirname(filename) - - if not os.path.exists(os.path.join(dir, "__init__.py")): - # parent dir is not a package - return dir - - while dir != "" and \ - os.path.exists(os.path.join(os.path.dirname(dir), "__init__.py")): - dir = os.path.dirname(dir) - return dir - - - -def filenameToModulePath(fname): - directoriesPreceedingRoot = getRootDirectory(fname) - import os - # strip off directories preceeding root package directory - if directoriesPreceedingRoot != "": - mpath = fname.replace(directoriesPreceedingRoot, "") - else: - mpath = fname - - if(mpath[0] == os.path.normpath("/")): - mpath = mpath[1:] - mpath, ext = os.path.splitext(mpath) - mpath = mpath.replace(os.path.normpath("/"), ".") - return mpath - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/setpath.py --- a/vim/sadness/bike/bike/parsing/setpath.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -import sys,os -if not os.path.abspath("../..") in sys.path: - from bike import log - print >> log.warning, "Appending to the system path. This should only happen in unit tests" - sys.path.append(os.path.abspath("../..")) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_fastparser.py --- a/vim/sadness/bike/bike/parsing/test_fastparser.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -#!/usr/bin/env python -import unittest -from fastparser import* -from bike.parsing.load import* -from bike.parsing.fastparserast import* -from bike.testutils import * - -class TestFastParser(BRMTestCase): - def test_doesntGetClassDeclsInMLStrings(self): - src = trimLines(''' - """ - class foo bah - """ - ''') - root = fastparser(src) - assert root.getChildNodes() == [] - - def test_evaluatesMLStringWithQuoteInIt(self): - src = trimLines(''' - """some ml comment inclosing a " """ - def foo: - pass - " hello " - ''') - root = fastparser(src) - assert root.getChildNodes() != [] - - def test_handlesClassDefsWithTwoSpacesInDecl(self): - src = trimLines(''' - class foo: pass - ''') - root = fastparser(src) - assert root.getChildNodes() != [] - - def test_handlesFnDefsWithTwoSpacesInDecl(self): - src = trimLines(''' - def foo: pass - ''') - root = fastparser(src) - assert root.getChildNodes() != [] - - -MLStringWithQuoteInIt = """ -\"\"\"some ml comment inclosing a \" \"\"\" -def foo: - pass -\" hello \" -""" - -def load(path): - files = getFilesForName(path) - for fname in files: - src = file(fname).read() - fastparser(src) - #print fname - #myroot = parseFile(fname) - - - -def fastparsetreeToString(root): - class stringholder: pass - s = stringholder() - s.mystr = "" - s.tabstr = "" - def t2s(node): - if isinstance(node, Class): - s.mystr+=s.tabstr+"class "+node.name+"\n" - s.tabstr+="\t" - for n in node.getChildNodes(): - t2s(n) - s.tabstr = s.tabstr[:-1] - - elif isinstance(node, Function): - s.mystr+=s.tabstr+"function "+node.name+"\n" - s.tabstr+="\t" - for n in node.getChildNodes(): - t2s(n) - s.tabstr = s.tabstr[:-1] - - - for n in root.getChildNodes(): - t2s(n) - return s.mystr - - -def compilerParseTreeToString(root): - try: - class TreeVisitor: - def __init__(self): - self.mystr = "" - self.tabstr = "" - - def visitClass(self, node): - self.mystr+=self.tabstr+"class "+node.name+"\n" - self.tabstr+="\t" - for child in node.getChildNodes(): - self.visit(child) - self.tabstr = self.tabstr[:-1] - - def visitFunction(self, node): - self.mystr+=self.tabstr+"function "+node.name+"\n" - self.tabstr+="\t" - for child in node.getChildNodes(): - self.visit(child) - self.tabstr = self.tabstr[:-1] - - return compiler.walk(root, TreeVisitor()).mystr - - except: - log.exception("ex") - import sys - sys.exit(0) - - -def compareCompilerWithFastparserOverPath(path): - from bike.parsing.load import getFilesForName - files = getFilesForName(path) - for fname in files: - if fname.endswith("bdist_wininst.py"): continue - log.info(fname) - src = file(fname).read() - try: - compiler_root = compiler.parse(src) - except SyntaxError: - continue - fastparse_root = fastparser(src) - str1 = fastparsetreeToString(fastparse_root) - str2 = compilerParseTreeToString(compiler_root) - assert str1 == str2, "\n"+"-"*70+"\n"+str1+"-"*70+"\n"+str2 - - -def timeParseOfPythonLibrary(path): - import time - t1 = time.time() - files = getFilesForName(path) - import sys - for fname in files: - if fname.endswith("bdist_wininst.py"): continue - src = file(fname).read() - fastparser(src) - print "\n", time.time()-t1 - - -if __name__ == "__main__": - from bike import logging - logging.init() - log = logging.getLogger("bike") - log.setLevel(logging.INFO) - # add soak tests to end of test - class Z_SoakTestFastparser(BRMTestCase): - - def test_A_timeParseOfPythonLibrary(self): - timeParseOfPythonLibrary("/usr/local/lib/python2.2") - - def test_parsesPythonLibraryCorrectly(self): - print "" - compareCompilerWithFastparserOverPath("/usr/local/lib/python2.2") - - unittest.main() - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_fastparserast.py --- a/vim/sadness/bike/bike/parsing/test_fastparserast.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -#!/usr/bin/env python -import unittest -from fastparserast import * -from fastparser import fastparser -from bike.query.getTypeOf import getTypeOf -from bike.testutils import * - -class TestGetModule(BRMTestCase): - - def test_getRootWorksAfterDefinedByCreateSourceNodeAt(self): - src=trimLines(""" - class TheClass: - pass - a = TheClass() - """) - root = createSourceNodeAt(src,"mymodule") - assert root == getRoot() - - def test_returnsNoneIfModuleDoesntExist(self): - assert getModule(tmpfile) == None - - -class TestGetEndLine(BRMTestCase): - def test_returnsEndLineWithSimpleFunction(self): - src = trimLines(""" - class TheClass: - def theMethod(): - pass - def foo(): - b = TheClass() - return b - a = foo() - a.theMethod() - """) - root = fastparser(src) - fn = getTypeOf(root,"foo") - self.assertEqual(fn.getEndLine(),7) - - def test_worksWithFunctionsThatHaveEmptyLinesInThem(self): - src = fnWithEmptyLineInIt - root = fastparser(src) - fn = getTypeOf(root,"TheClass.theFunction") - self.assertEqual(fn.getEndLine(),8) - -class TestGetBaseClassNames(BRMTestCase): - def test_worksForClassHierarchy(self): - src = trimLines(""" - class root: - def theMethod(): - pass - - class a(root): - def theMethod(): - pass - - class b(root): - pass - - class TheClass(a,b): - def theMethod(): - pass - - rootinstance = root() - rootinstance.theMethod() - """) - #classes = getASTNodeFromSrc(src,"Source").fastparseroot.getChildNodes() - classes = createAST(src).fastparseroot.getChildNodes() - self.assertEqual(classes[3].getBaseClassNames(),['a','b']) - - def test_returnsEmptyListForClassWithNoBases(self): - src = trimLines(""" - class root: - pass - """) - #classes = getASTNodeFromSrc(src,"Source").fastparseroot.getChildNodes() - classes = createAST(src).fastparseroot.getChildNodes() - self.assertEqual(classes[0].getBaseClassNames(),[]) - - -class TestGetMaskedLines(BRMTestCase): - def test_doit(self): - src =trimLines(""" - class foo: #bah - pass - """) - mod = createAST(src).fastparseroot - lines = mod.getMaskedModuleLines() - assert lines[0] == "class foo: #***\n" - - -class TestGetLinesNotIncludingThoseBelongingToChildScopes(BRMTestCase): - def test_worksForModule(self): - src =trimLines(""" - class TheClass: - def theMethod(): - pass - def foo(): - b = TheClass() - return b - a = foo() - a.theMethod() - """) - mod = createAST(src).fastparseroot - self.assertEqual(''.join(mod.getLinesNotIncludingThoseBelongingToChildScopes()), - trimLines(""" - a = foo() - a.theMethod() - """)) - - def test_worksForModuleWithSingleLineFunctions(self): - src=trimLines(""" - a = blah() - def foo(): pass - b = 1 - """) - mod = createAST(src).fastparseroot - lines = mod.getLinesNotIncludingThoseBelongingToChildScopes() - self.assertEqual(''.join(lines), - trimLines(""" - a = blah() - b = 1 - """)) - - - def test_worksForSingleLineFunction(self): - src=trimLines(""" - a = blah() - def foo(): pass - b = 1 - """) - fn = createAST(src).fastparseroot.getChildNodes()[0] - lines = fn.getLinesNotIncludingThoseBelongingToChildScopes() - self.assertEqual(''.join(lines), - trimLines(""" - def foo(): pass - """)) - - -fnWithEmptyLineInIt = """ -class TheClass: - def theFunction(): - a = foo() - - print 'a' - - # end of function -""" - -if __name__ == "__main__": - unittest.main() - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_load.py --- a/vim/sadness/bike/bike/parsing/test_load.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import compiler -import os - -from bike import testdata -from bike.testutils import * -from bike.mock import Mock - -from pathutils import getPathOfModuleOrPackage -from load import * -import load as loadmodule - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_newstuff.py --- a/vim/sadness/bike/bike/parsing/test_newstuff.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +0,0 @@ -#!/usr/bin/env python -import setpath -import os -import unittest -from bike.testutils import * -from bike.parsing.fastparserast import getRoot -from bike.parsing.newstuff import getModuleOrPackageUsingFQN,\ - generateModuleFilenamesInPythonPath, getSourceNodesContainingRegex,\ - generatePackageDependencies - - -class TestGetModuleOrPackageUsingFQN(BRMTestCase): - def test_worksForFullPath(self): - try: - createPackageStructure("pass","pass") - self.assertEqual(getModuleOrPackageUsingFQN("a.b.bah").filename, - pkgstructureFile2) - finally: - removePackageStructure() - - def test_worksForPackage(self): - try: - createPackageStructure("pass","pass") - self.assertEqual(getModuleOrPackageUsingFQN("a.b").path, - pkgstructureChilddir) - finally: - removePackageStructure() - - -class TestGenerateModuleFilenamesInPythonPath(BRMTestCase): - def test_works(self): - try: - createPackageStructure("pass","pass") - fnames = [f for f in \ - generateModuleFilenamesInPythonPath(pkgstructureFile2)] - - - assert os.path.join(pkgstructureBasedir,"__init__.py") in fnames - assert pkgstructureFile1 in fnames - assert os.path.join(pkgstructureChilddir,"__init__.py") in fnames - assert pkgstructureFile2 in fnames - assert len(fnames) == 5 - finally: - removePackageStructure() - - - - def test_doesntTraverseIntoNonPackages(self): - try: - createPackageStructure("pass","pass") - nonPkgDir = os.path.join(pkgstructureChilddir,"c") - newfile = os.path.join(nonPkgDir,"baz.py") - # N.B. don't put an __init__.py in it, so isnt a package - os.makedirs(nonPkgDir) - writeFile(newfile,"pass") - fnames = [f for f in \ - generateModuleFilenamesInPythonPath(pkgstructureFile2)] - assert newfile not in fnames - finally: - #os.remove(initfile) - os.remove(newfile) - os.removedirs(nonPkgDir) - removePackageStructure() - - - def test_doesScanFilesInTheRootDirectory(self): - try: - createPackageStructure("pass","pass","pass") - fnames = [f for f in \ - generateModuleFilenamesInPythonPath(pkgstructureFile2)] - assert pkgstructureFile0 in fnames - finally: - #os.remove(initfile) - removePackageStructure() - - def test_returnsOtherFilesInSameNonPackageDirectory(self): - try: - oldpath = getRoot().pythonpath - getRoot().pythonpath = [] # clear the python path - writeTmpTestFile("") - newtmpfile = os.path.join(tmproot,"baz.py") - writeFile(newtmpfile, "") - fnames = [f for f in \ - generateModuleFilenamesInPythonPath(tmpfile)] - assert newtmpfile in fnames - finally: - os.remove(newtmpfile) - deleteTmpTestFile() - getRoot().pythonpath = oldpath - - - - def test_doesntTraverseIntoNonPackagesUnderRoot(self): - try: - os.makedirs(pkgstructureBasedir) - writeFile(pkgstructureFile1,"pass") - fnames = [f for f in \ - generateModuleFilenamesInPythonPath(pkgstructureFile2)] - assert pkgstructureFile1 not in fnames - finally: - os.remove(pkgstructureFile1) - os.removedirs(pkgstructureBasedir) - - - def test_doesntGenerateFilenamesMoreThanOnce(self): - try: - createPackageStructure("pass","pass") - newfile = os.path.join(pkgstructureChilddir,"baz.py") - writeFile(newfile,"pass") - fnames = [f for f in \ - generateModuleFilenamesInPythonPath(pkgstructureFile2)] - matched = [f for f in fnames if f == newfile] - self.assertEqual(1, len(matched)) - finally: - os.remove(newfile) - removePackageStructure() - -class TestGetSourceNodesContainingRegex(BRMTestCase): - def test_works(self): - try: - createPackageStructure("# testregexfoobah","pass") - srcfiles = [s for s in - getSourceNodesContainingRegex("testregexfoobah", - pkgstructureFile2)] - self.assertEqual(pkgstructureFile1,srcfiles[0].filename) - finally: - removePackageStructure() - -class TestGenerateModuleFilenamesInPythonPath2(BRMTestCase): - def test_getsAllFilenamesInSameHierarchyAsContextFile(self): - try: - oldpath = getRoot().pythonpath - getRoot().pythonpath = [] # clear the python path - createPackageStructure("","") - fnames = [f for f in - generateModuleFilenamesInPythonPath(pkgstructureFile1)] - self.assert_(pkgstructureFile0 in fnames) - self.assert_(pkgstructureFile1 in fnames) - self.assert_(pkgstructureFile2 in fnames) - finally: - getRoot().pythonpath = oldpath - removePackageStructure() - - def test_getsFilenamesInSubPackagesIfCtxFilenameIsInTheRoot(self): - try: - oldpath = getRoot().pythonpath - getRoot().pythonpath = [] # clear the python path - createPackageStructure("","") - fnames = [f for f in - generateModuleFilenamesInPythonPath(pkgstructureFile0)] - self.assert_(pkgstructureFile1 in fnames) - self.assert_(pkgstructureFile2 in fnames) - finally: - getRoot().pythonpath = oldpath - removePackageStructure() - - def test_doesntTraverseOtherPackagesOffOfTheRoot(self): - try: - oldpath = getRoot().pythonpath - getRoot().pythonpath = [] # clear the python path - createPackageStructure("","") - os.makedirs(os.path.join(pkgstructureRootDir, "c")) - writeFile(os.path.join(pkgstructureRootDir, "c", "__init__.py"), "# ") - bazfile = os.path.join(pkgstructureRootDir, "c", "baz.py") - writeFile(bazfile, "pass") - fnames = [f for f in - generateModuleFilenamesInPythonPath(pkgstructureFile1)] - self.assert_(pkgstructureFile0 in fnames) - self.assert_(pkgstructureFile1 in fnames) - self.assert_(pkgstructureFile2 in fnames) - self.assert_(bazfile not in fnames) - finally: - getRoot().pythonpath = oldpath - os.remove(os.path.join(pkgstructureRootDir, "c", "baz.py")) - os.remove(os.path.join(pkgstructureRootDir, "c", "__init__.py")) - os.removedirs(os.path.join(pkgstructureRootDir, "c")) - removePackageStructure() - - -class TestGetPackageDependencies(BRMTestCase): - - def test_followsImportModule(self): - try: - createPackageStructure("","import c.bing") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([pkgstructureBasedir2],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - - def test_followsFromImportPackage(self): - try: - createPackageStructure("","import c") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([pkgstructureBasedir2],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - - - def test_followsFromImportStar(self): - try: - createPackageStructure("","from c import *") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([pkgstructureBasedir2],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - def test_followsFromImportModule(self): - try: - createPackageStructure("","from c import bing") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([pkgstructureBasedir2],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - - def test_doesntBreakIfImportIsInAMultilineString(self): - try: - createPackageStructure("",trimLines(""" - ''' - from aoeuaoeu import aocxaoieicxoe - ''' - """)) - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - def test_doesntBreakIfImportIsCommented(self): - try: - createPackageStructure("","#from aoeuaoeu import aocxaoieicxoe") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - - def test_doesntBreakIfCantFindImport(self): - try: - createPackageStructure("","from aoeuaoeu import aocxaoieicxoe") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - - def test_doesntIncludeCurrentPackage(self): - try: - createPackageStructure("","import a.foo") - createSecondPackageStructure("") - dependencies = [d for d in - generatePackageDependencies(pkgstructureFile2)] - self.assertEqual([],dependencies) - finally: - removeSecondPackageStructure() - removePackageStructure() - - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_parserutils.py --- a/vim/sadness/bike/bike/parsing/test_parserutils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -#!/usr/bin/env python -import unittest -from parserutils import * -from bike.testutils import * - -class TestRemoveEscapedQuotes(BRMTestCase): - - def testMaskEscapedQuotes_MasksEscapedQuotes(self): - src = '\" \\\\\\\" \' \\\\\\\\\" \' \'' - self.assertEqual(maskEscapedQuotes(src),'" **** \' ****" \' \'') - -class TestMungePythonKeywordsInStrings(BRMTestCase): - def test_mungesKeywords(self): - src = '\"\"\"class try while\"\"\" class2 try2 while2 \'\'\' def if for \'\'\' def2 if2 for2' - self.assertEqual(maskPythonKeywordsInStringsAndComments(src), - '"""CLASS TRY WHILE""" class2 try2 while2 \'\'\' DEF IF FOR \'\'\' def2 if2 for2') - - -class TestSplitLines(BRMTestCase): - def test_handlesExplicitlyContinuedLineWithComment(self): - self.assertEqual(splitLogicalLines(explicitlyContinuedLineWithComment), - ['\n', 'z = a + b + \\ # comment\n c + d\n', 'pass\n']) - - def test_handlesImplicitlyContinuedLine(self): - self.assertEqual(splitLogicalLines(implicitlyContinuedLine), - ['\n', 'z = a + b + (\n c + d)\n', 'pass\n']) - - def test_handlesNestedImplicitlyContinuedLine(self): - self.assertEqual(splitLogicalLines(implicitlyContinuedLine2), - ['\n', 'z = a + b + ( c + [d\n + e]\n + f) # comment\n', 'pass\n']) - - - def test_handlesMultiLineStrings(self): - self.assertEqual(splitLogicalLines(multilineComment), - ['\n', "''' this is an mlc\nso is this\n'''\n", 'pass\n']) - - -class TestMakeLineParseable(BRMTestCase): - def test_worksWithIfStatement(self): - src = "if foo:" - self.assertEqual(makeLineParseable(src),("if foo: pass")) - - def test_worksWithTryStatement(self): - src = "try :" - self.assertEqual(makeLineParseable(src),("try : pass\nexcept: pass")) - - def test_worksOnTryStatementWithCodeInlined(self): - src = "try : a = 1" - self.assertEqual(makeLineParseable(src),("try : a = 1\nexcept: pass")) - - def test_worksWithExceptStatement(self): - src = "except :" - self.assertEqual(makeLineParseable(src),("try: pass\nexcept : pass")) - - def test_worksWithFinallyStatement(self): - src = "finally:" - self.assertEqual(makeLineParseable(src),("try: pass\nfinally: pass")) - - def test_worksWithIfStatement(self): - src = "if foo:" - self.assertEqual(makeLineParseable(src),("if foo: pass")) - - def test_worksWithElseStatement(self): - src = "else :" - self.assertEqual(makeLineParseable(src),("if 0: pass\nelse : pass")) - - def test_worksWithElifStatement(self): - src = "elif foo:" - self.assertEqual(makeLineParseable(src),("if 0: pass\nelif foo: pass")) - - -def runOverPath(path): - import compiler - from parser import ParserError - from bike.parsing.load import getFilesForName - files = getFilesForName(path) - for fname in files: - print fname - src = file(fname).read() - #print src - src = maskStringsAndRemoveComments(src) - - for logicalline in splitLogicalLines(src): - #print "logicalline=",logicalline - logicalline = logicalline.strip() - logicalline = makeLineParseable(logicalline) - try: - compiler.parse(logicalline) - except ParserError: - print "ParserError on logicalline:",logicalline - except: - log.exception("caught exception") - - -explicitlyContinuedLineWithComment = """ -z = a + b + \ # comment - c + d -pass -""" - -implicitlyContinuedLine = """ -z = a + b + ( - c + d) -pass -""" - - -implicitlyContinuedLine2 = """ -z = a + b + ( c + [d - + e] - + f) # comment -pass -""" - -multilineComment = """ -''' this is an mlc -so is this -''' -pass -""" - -if __name__ == "__main__": - from bike import logging - logging.init() - log = logging.getLogger("bike") - log.setLevel(logging.INFO) - - # add soak tests to end of test - class Z_SoakTest(BRMTestCase): - def test_linesRunThroughPythonParser(self): - print "" - #print splitLogicalLines(file('/usr/local/lib/python2.2/aifc.py').read()) - #runOverPath('/usr/local/lib/python2.2/test/badsyntax_nocaret.py') - runOverPath('/usr/local/lib/python2.2/') - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_pathutils.py --- a/vim/sadness/bike/bike/parsing/test_pathutils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import compiler -import os - -from bike import testdata -from bike.testutils import * -from bike.mock import Mock - -from pathutils import getPathOfModuleOrPackage -from pathutils import * -import pathutils as loadmodule - -class TestGetFilesForName(BRMTestCase): - def testGetFilesForName_recursivelyReturnsFilesInBreadthFirstOrder(self): - createPackageStructure("pass", "pass") - - files = getFilesForName(pkgstructureBasedir) - for f in files: - assert f in \ - [os.path.join(pkgstructureBasedir, '__init__.py'), - os.path.join(pkgstructureBasedir, 'foo.py'), - os.path.join(pkgstructureChilddir, '__init__.py'), - os.path.join(pkgstructureChilddir, 'bah.py')] - - def testGetFilesForName_globsStars(self): - createPackageStructure("pass", "pass") - assert getFilesForName(os.path.join(pkgstructureBasedir, "fo*")) == [os.path.join(pkgstructureBasedir, 'foo.py')] - removePackageStructure() - - def testGetFilesForName_doesntListFilesWithDotAtFront(self): - writeFile(os.path.join(".foobah.py"),"") - files = getFilesForName("a") - self.assertEqual([],files) - - - - -class TestGetRootDirectory(BRMTestCase): - def test_returnsParentDirectoryIfFileNotInPackage(self): - try: - # this doesnt have __init__.py file, so - # isnt package - os.makedirs("a") - writeFile(os.path.join("a", "foo.py"), "pass") - dir = loadmodule.getRootDirectory(os.path.join("a", "foo.py")) - assert dir == "a" - finally: - os.remove(os.path.join("a", "foo.py")) - os.removedirs(os.path.join("a")) - - def test_returnsFirstNonPackageParentDirectoryIfFileInPackage(self): - try: - os.makedirs(os.path.join("root", "a", "b")) - writeFile(os.path.join("root", "a", "__init__.py"), "# ") - writeFile(os.path.join("root", "a", "b", "__init__.py"), "# ") - writeFile(os.path.join("root", "a", "b", "foo.py"), "pass") - dir = loadmodule.getRootDirectory(os.path.join("root", "a", "b", "foo.py")) - assert dir == "root" - finally: - os.remove(os.path.join("root", "a", "__init__.py")) - os.remove(os.path.join("root", "a", "b", "__init__.py")) - os.remove(os.path.join("root", "a", "b", "foo.py")) - os.removedirs(os.path.join("root", "a", "b")) - - def test_returnsFirstNonPackageParentDirectoryIfPathIsAPackage(self): - try: - os.makedirs(os.path.join("root", "a", "b")) - writeFile(os.path.join("root", "a", "__init__.py"), "# ") - writeFile(os.path.join("root", "a", "b", "__init__.py"), "# ") - writeFile(os.path.join("root", "a", "b", "foo.py"), "pass") - dir = loadmodule.getRootDirectory(os.path.join("root", "a", "b")) - assert dir == "root" - finally: - os.remove(os.path.join("root", "a", "__init__.py")) - os.remove(os.path.join("root", "a", "b", "__init__.py")) - os.remove(os.path.join("root", "a", "b", "foo.py")) - os.removedirs(os.path.join("root", "a", "b")) - - def test_returnsDirIfDirIsTheRootDirectory(self): - try: - os.makedirs(os.path.join("root", "a", "b")) - writeFile(os.path.join("root", "a", "__init__.py"), "# ") - writeFile(os.path.join("root", "a", "b", "__init__.py"), "# ") - writeFile(os.path.join("root", "a", "b", "foo.py"), "pass") - dir = loadmodule.getRootDirectory("root") - assert dir == "root" - finally: - os.remove(os.path.join("root", "a", "__init__.py")) - os.remove(os.path.join("root", "a", "b", "__init__.py")) - os.remove(os.path.join("root", "a", "b", "foo.py")) - os.removedirs(os.path.join("root", "a", "b")) - - -class getPackageBaseDirectory(BRMTestCase): - def test_returnsBasePackageIfFileInPackageHierarchy(self): - try: - createPackageStructure("","") - dir = loadmodule.getPackageBaseDirectory(pkgstructureFile2) - self.assertEqual(pkgstructureBasedir, dir) - finally: - removePackageStructure() - - def test_returnsFileDirectoryIfFileNotInPackage(self): - try: - createPackageStructure("","") - dir = loadmodule.getPackageBaseDirectory(pkgstructureFile0) - self.assertEqual(pkgstructureRootDir, dir) - finally: - removePackageStructure() - - -class TestGetPathOfModuleOrPackage(BRMTestCase): - def test_worksForFullPath(self): - try: - createPackageStructure("pass","pass") - import sys - self.assertEqual(getPathOfModuleOrPackage("a.b.bah", - [pkgstructureRootDir]), - pkgstructureFile2) - finally: - removePackageStructure() - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_utils.py --- a/vim/sadness/bike/bike/parsing/test_utils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from utils import * - -class Test_CarCdrEtc(unittest.TestCase): - def test_carReturnsTheFirstElementOfTheFqn(self): - fqn = "apple.pear.foo" - assert fqn_car(fqn) == "apple" - - def test_carReturnsElementInOneElementFqn(self): - fqn = "apple" - assert fqn_car(fqn) == "apple" - - def test_cdrReturnsTheAllElementsOfTheFqnExceptFirst(self): - fqn = "apple.pear.foo" - assert fqn_cdr(fqn) == "pear.foo" - - def test_cdrReturnsEmptyStringForOneElementFqn(self): - fqn = "apple" - assert fqn_cdr(fqn) == "" - - def test_rcarReturnsTheLastElementOfTheFqn(self): - fqn = "apple.pear.foo" - assert fqn_rcar(fqn) == "foo" - - def test_rcarReturnsElementInOneElementFqn(self): - fqn = "apple" - assert fqn_rcar(fqn) == "apple" - - def test_rdrReturnsTheAllElementsOfTheFqnExceptLast(self): - fqn = "apple.pear.foo" - assert fqn_rcdr(fqn) == "apple.pear" - - def test_rdrReturnsEmptyStringForOneElementFqn(self): - fqn = "apple" - assert fqn_rcdr(fqn) == "" - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/test_visitor.py --- a/vim/sadness/bike/bike/parsing/test_visitor.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -#!/usr/bin/env python -from __future__ import generators -import setpath -import unittest -import visitor -from bike.testutils import * - -class TestVisitor(BRMTestCase): - def test_callsVistorFunctions(self): - tree = createTree() - - class TreeVisitor: - def __init__(self): - self.txt = [] - - def visitAClass(self,node): - self.txt.append("visitAClass") - self.txt.append(node.txt) - return self.visitChildren(node) - - def visitCClass(self,node): - self.txt.append("visitCClass") - self.txt.append(node.txt) - - def getTxt(self): - return ",".join(self.txt) - - self.assertEqual(visitor.walk(tree,TreeVisitor()).getTxt(), - "visitAClass,aclass,visitCClass,cclass0,visitCClass,cclass1,visitCClass,cclass2") - - - def test_callsVisitorFunctionsWithYield(self): - tree = createTree() - - class TreeVisitor: - def __init__(self): - self.txt = [] - - def visitAClass(self,node): - self.txt.append("visitAClass") - self.txt.append(node.txt) - yield node - for i in self.visitChildren(node): - yield i - - def visitCClass(self,node): - self.txt.append("visitCClass") - self.txt.append(node.txt) - if 0: yield 1 - - def getTxt(self): - return ",".join(self.txt) - - for node in visitor.walkAndGenerate(tree,TreeVisitor()): - assert node.txt == "aclass" - - -def createTree(): - n = AClass("aclass") - for i in xrange(3): - b = n.addChildNode(BClass("bclass%d" % i)) - for j in xrange(20): - b = b.addChildNode(BClass("bclass%d" % i)) - b.addChildNode(CClass("cclass%d" % i)) - return n - -class node(object): - def __init__(self,txt): - self._childNodes=[] - self.txt = txt - - def addChildNode(self,node): - self._childNodes.append(node) - return node - - def getChildNodes(self): - return [x for x in self._childNodes] - - -class AClass(node): - pass - -class BClass(node): - pass - -class CClass(node): - pass - -if __name__ == "__main__": - - # add perf test at end of tests - class Z_SoakTestFastparser(BRMTestCase): - def test_parsesPythonLibraryCorrectly(self): - - class TreeVisitor: - pass - - import time - - tree = createTree() - - t1 = time.time() - for i in xrange(1000): - visitor.walk(tree,TreeVisitor()) - print "tree without yield",time.time()-t1 - - t1 = time.time() - for i in xrange(1000): - for node in visitor.walkAndGenerate(tree,TreeVisitor()): - pass - print "tree with yield",time.time()-t1 - - - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/testall.py --- a/vim/sadness/bike/bike/parsing/testall.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -#!/usr/bin/env python -import setpath - -import unittest - -#import all the tests -from test_load import * -from test_newstuff import * -from test_parserutils import * -from test_fastparser import * -from test_fastparserast import * - -if __name__ == "__main__": - from bike import logging - logging.init() - log = logging.getLogger("bike") - log.setLevel(logging.WARN) - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/utils.py --- a/vim/sadness/bike/bike/parsing/utils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -# get the first element of a fully qualified python path -#(e.g. _car('a.b.c.d') = 'a') -def fqn_car(fqn): - try: - return fqn[:fqn.index(".")] - except ValueError: # i.e. no dots in fqn - return fqn - -# get the other elements of a fully qualified python path -#(e.g. _cdr('a.b.c.d') = 'b.c.d') -def fqn_cdr(fqn): - try: - return fqn[fqn.index(".")+1:] - except ValueError: # i.e. no dots in fqn - return "" - -# reverse of above _rcar("a.b.c.d") = "d" -def fqn_rcar(fqn): - try: - return fqn[fqn.rindex(".")+1:] - except ValueError: # i.e. no dots in fqn - return fqn - - -# reverse of above _rcdr("a.b.c.d") = "a.b.c" -def fqn_rcdr(fqn): - try: - return fqn[:fqn.rindex(".")] - except ValueError: # i.e. no dots in fqn - return "" diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/parsing/visitor.py --- a/vim/sadness/bike/bike/parsing/visitor.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -from __future__ import generators - -class TreeWalker(object): - VERBOSE = 0 - - def __init__(self): - self.node = None - self._cache = {} - - def default(self, node, *args): - for child in node.getChildNodes(): - self.dispatch(child, *args) - - def dispatch(self, node, *args): - self.node = node - klass = node.__class__ - meth = self._cache.get(klass, None) - if meth is None: - className = klass.__name__ - meth = getattr(self.visitor, 'visit' + className, self.default) - self._cache[klass] = meth - return meth(node, *args) - - def preorder(self, tree, visitor, *args): - """Do preorder walk of tree using visitor""" - self.visitor = visitor - visitor.visit = self.dispatch - visitor.visitChildren = self.default - return self.dispatch(tree, *args) - -class GeneratingTreeWalker(TreeWalker): - - def default(self, node, *args): - for child in node.getChildNodes(): - for i in self.dispatch(child, *args): - yield i - - -def walk(tree, visitor): - walker = TreeWalker() - walker.preorder(tree, visitor) - return walker.visitor - - -def walkAndGenerate(tree,visitor): - walker = GeneratingTreeWalker() - return walker.preorder(tree, visitor) - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/__init__.py --- a/vim/sadness/bike/bike/query/__init__.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -# \ No newline at end of file diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/common.py --- a/vim/sadness/bike/bike/query/common.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,333 +0,0 @@ -from __future__ import generators -from bike.globals import * -from bike.parsing.fastparserast import getRoot, Function, Class, Module, getModule -from bike.parsing.parserutils import generateLogicalLines, makeLineParseable, UnbalancedBracesException, generateLogicalLinesAndLineNumbers -from bike.parsing.newstuff import getSourceNodesContainingRegex -from bike.parsing import visitor -from bike import log -import compiler -from compiler.ast import Getattr, Name -import re - -class Match: - def __repr__(self): - return ",".join([self.filename, str(self.lineno), str(self.colno), - str(self.confidence)]) - def __eq__(self,other): - if self is None or other is None: - return False - return self.filename == other.filename and \ - self.lineno == other.lineno and \ - self.colno == other.colno - -def getScopeForLine(sourceNode, lineno): - scope = None - childnodes = sourceNode.getFlattenedListOfFastParserASTNodes() - if childnodes == []: - return sourceNode.fastparseroot #module node - - scope = sourceNode.fastparseroot - - for node in childnodes: - if node.linenum > lineno: break - scope = node - - if scope.getStartLine() != scope.getEndLine(): # is inline - while scope.getEndLine() <= lineno: - scope = scope.getParent() - return scope - - - -# global from the perspective of 'contextFilename' -def globalScanForMatches(contextFilename, matchFinder, targetname): - for sourcenode in getSourceNodesContainingRegex(targetname, contextFilename): - print >> log.progress, "Scanning", sourcenode.filename - searchscope = sourcenode.fastparseroot - for match in scanScopeForMatches(sourcenode,searchscope, - matchFinder,targetname): - yield match - - -def scanScopeForMatches(sourcenode,scope,matchFinder,targetname): - lineno = scope.getStartLine() - for line in generateLogicalLines(scope.getMaskedLines()): - if line.find(targetname) != -1: - doctoredline = makeLineParseable(line) - ast = compiler.parse(doctoredline) - scope = getScopeForLine(sourcenode, lineno) - matchFinder.reset(line) - matchFinder.setScope(scope) - matches = visitor.walk(ast, matchFinder).getMatches() - for index, confidence in matches: - match = Match() - match.filename = sourcenode.filename - match.sourcenode = sourcenode - x, y = indexToCoordinates(line, index) - match.lineno = lineno+y - match.colno = x - match.colend = match.colno+len(targetname) - match.confidence = confidence - yield match - lineno+=line.count("\n") - - -def walkLinesContainingStrings(scope,astWalker,targetnames): - lineno = scope.getStartLine() - for line in generateLogicalLines(scope.getMaskedLines()): - if lineContainsOneOf(line,targetnames): - doctoredline = makeLineParseable(line) - ast = compiler.parse(doctoredline) - astWalker.lineno = lineno - matches = visitor.walk(ast, astWalker) - lineno+=line.count("\n") - - -def lineContainsOneOf(line,targetnames): - for name in targetnames: - if line.find(name) != -1: - return True - return False - - -# translates an idx in a logical line into physical line coordinates -# returns x and y coords -def indexToCoordinates(src, index): - y = src[: index].count("\n") - startOfLineIdx = src.rfind("\n", 0, index)+1 - x = index-startOfLineIdx - return x, y - - - -# interface for MatchFinder classes -# implement the visit methods -class MatchFinder: - def setScope(self, scope): - self.scope = scope - - def reset(self, line): - self.matches = [] - self.words = re.split("(\w+)", line) # every other one is a non word - self.positions = [] - i = 0 - for word in self.words: - self.positions.append(i) - #if '\n' in word: # handle newlines - # i = len(word[word.index('\n')+1:]) - #else: - i+=len(word) - self.index = 0 - - def getMatches(self): - return self.matches - - # need to visit childnodes in same order as they appear - def visitPrintnl(self,node): - if node.dest: - self.visit(node.dest) - for n in node.nodes: - self.visit(n) - - def visitName(self, node): - self.popWordsUpTo(node.name) - - def visitClass(self, node): - self.popWordsUpTo(node.name) - for base in node.bases: - self.visit(base) - - def zipArgs(self, argnames, defaults): - """Takes a list of argument names and (possibly a shorter) list of - default values and zips them into a list of pairs (argname, default). - Defaults are aligned so that the last len(defaults) arguments have - them, and the first len(argnames) - len(defaults) pairs have None as a - default. - """ - fixed_args = len(argnames) - len(defaults) - defaults = [None] * fixed_args + list(defaults) - return zip(argnames, defaults) - - def visitFunction(self, node): - self.popWordsUpTo(node.name) - for arg, default in self.zipArgs(node.argnames, node.defaults): - self.popWordsUpTo(arg) - if default is not None: - self.visit(default) - self.visit(node.code) - - def visitGetattr(self,node): - self.visit(node.expr) - self.popWordsUpTo(node.attrname) - - def visitAssName(self, node): - self.popWordsUpTo(node.name) - - def visitAssAttr(self, node): - self.visit(node.expr) - self.popWordsUpTo(node.attrname) - - def visitImport(self, node): - for name, alias in node.names: - for nameelem in name.split("."): - self.popWordsUpTo(nameelem) - if alias is not None: - self.popWordsUpTo(alias) - - def visitFrom(self, node): - for elem in node.modname.split("."): - self.popWordsUpTo(elem) - for name, alias in node.names: - self.popWordsUpTo(name) - if alias is not None: - self.popWordsUpTo(alias) - - def visitLambda(self, node): - for arg, default in self.zipArgs(node.argnames, node.defaults): - self.popWordsUpTo(arg) - if default is not None: - self.visit(default) - self.visit(node.code) - - def visitGlobal(self, node): - for name in node.names: - self.popWordsUpTo(name) - - def popWordsUpTo(self, word): - if word == "*": - return # won't be able to find this - posInWords = self.words.index(word) - idx = self.positions[posInWords] - self.words = self.words[posInWords+1:] - self.positions = self.positions[posInWords+1:] - - def appendMatch(self,name,confidence=100): - idx = self.getNextIndexOfWord(name) - self.matches.append((idx, confidence)) - - def getNextIndexOfWord(self,name): - return self.positions[self.words.index(name)] - -class CouldNotLocateNodeException(Exception): pass - -def translateSourceCoordsIntoASTNode(filename,lineno,col): - module = getModule(filename) - maskedlines = module.getMaskedModuleLines() - lline,backtrackchars = getLogicalLine(module, lineno) - doctoredline = makeLineParseable(lline) - ast = compiler.parse(doctoredline) - idx = backtrackchars+col - nodefinder = ASTNodeFinder(lline,idx) - node = compiler.walk(ast, nodefinder).node - if node is None: - raise CouldNotLocateNodeException("Could not translate editor coordinates into source node") - return node - -def getLogicalLine(module, lineno): - # we know that the scope is the start of a logical line, so - # we search from there - scope = getScopeForLine(module.getSourceNode(), lineno) - linegenerator = \ - module.generateLinesWithLineNumbers(scope.getStartLine()) - for lline,llinenum in \ - generateLogicalLinesAndLineNumbers(linegenerator): - if llinenum > lineno: - break - prevline = lline - prevlinenum = llinenum - - backtrackchars = 0 - for i in range(prevlinenum,lineno): - backtrackchars += len(module.getSourceNode().getLines()[i-1]) - return prevline, backtrackchars - - - -class ASTNodeFinder(MatchFinder): - # line is a masked line of text - # lineno and col are coords - def __init__(self,line,col): - self.line = line - self.col = col - self.reset(line) - self.node = None - - def visitName(self,node): - if self.checkIfNameMatchesColumn(node.name): - self.node = node - self.popWordsUpTo(node.name) - - def visitGetattr(self,node): - self.visit(node.expr) - if self.checkIfNameMatchesColumn(node.attrname): - self.node = node - self.popWordsUpTo(node.attrname) - - def visitFunction(self, node): - if self.checkIfNameMatchesColumn(node.name): - self.node = node - self.popWordsUpTo(node.name) - - for arg, default in self.zipArgs(node.argnames, node.defaults): - if self.checkIfNameMatchesColumn(arg): - self.node = Name(arg) - self.popWordsUpTo(arg) - if default is not None: - self.visit(default) - self.visit(node.code) - - - visitAssName = visitName - visitAssAttr = visitGetattr - - def visitClass(self, node): - if self.checkIfNameMatchesColumn(node.name): - self.node = node - self.popWordsUpTo(node.name) - for base in node.bases: - self.visit(base) - - - def checkIfNameMatchesColumn(self,name): - idx = self.getNextIndexOfWord(name) - #print "name",name,"idx",idx,"self.col",self.col - if idx <= self.col and idx+len(name) > self.col: - return 1 - return 0 - - def visitFrom(self, node): - for elem in node.modname.split("."): - self.popWordsUpTo(elem) - for name, alias in node.names: - if self.checkIfNameMatchesColumn(name): - self.node = self._manufactureASTNodeFromFQN(name) - return - self.popWordsUpTo(name) - if alias is not None: - self.popWordsUpTo(alias) - - # gets round the fact that imports etc dont contain nested getattr - # nodes for fqns (e.g. import a.b.bah) by converting the fqn - # string into a getattr instance - def _manufactureASTNodeFromFQN(self,fqn): - if "." in fqn: - assert 0, "getattr not supported yet" - else: - return Name(fqn) - -def isAMethod(scope,node): - return isinstance(node,compiler.ast.Function) and \ - isinstance(scope,Class) - -def convertNodeToMatchObject(node,confidence=100): - m = Match() - m.sourcenode = node.module.getSourceNode() - m.filename = node.filename - if isinstance(node,Module): - m.lineno = 1 - m.colno = 0 - elif isinstance(node,Class) or isinstance(node,Function): - m.lineno = node.getStartLine() - m.colno = node.getColumnOfName() - m.confidence = confidence - return m diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/findDefinition.py --- a/vim/sadness/bike/bike/query/findDefinition.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -from __future__ import generators -from bike.query.common import Match, MatchFinder, \ - getScopeForLine, indexToCoordinates, \ - translateSourceCoordsIntoASTNode, scanScopeForMatches, \ - isAMethod, convertNodeToMatchObject, walkLinesContainingStrings -from bike.parsing.parserutils import generateLogicalLines,\ - generateLogicalLinesAndLineNumbers, \ - splitLogicalLines, makeLineParseable -import compiler -from compiler.ast import Getattr, Name, AssName, AssAttr -from bike.parsing.fastparserast import getRoot, Package, Class, \ - Module, Function, Instance -import re -from bike.query.getTypeOf import getTypeOfExpr, UnfoundType, \ - isWordInLine, resolveImportedModuleOrPackage -from bike.parsing import visitor -from bike.parsing.visitor import walkAndGenerate - -from bike.parsing.parserutils import makeLineParseable,splitLogicalLines -from bike.parsing.newstuff import getSourceNodesContainingRegex -from bike.parsing.load import getSourceNode -from bike import log - - -class CantFindDefinitionException: - pass - - -def findAllPossibleDefinitionsByCoords(filepath,lineno,col): - - #try: - node = translateSourceCoordsIntoASTNode(filepath,lineno,col) - #except: - # import traceback - # traceback.print_exc() - - if node is None: - raise "selected node type not supported" - scope = getScopeForLine(getSourceNode(filepath),lineno) - match = findDefinitionFromASTNode(scope,node) - if match is not None: - yield match - if isinstance(node,Getattr) and (match is None or match.confidence != 100): - root = getRoot() - name = node.attrname - for match in scanPythonPathForMatchingMethodNames(name,filepath): - yield match - print >>log.progress,"done" - - -def findDefinitionFromASTNode(scope,node): - assert node is not None - if isinstance(node,Name) or isinstance(node,AssName): - while 1: - # try scope children - childscope = scope.getChild(node.name) - if childscope is not None: - return convertNodeToMatchObject(childscope,100) - - if isinstance(scope,Package): - scope = scope.getChild("__init__") - - # try arguments and assignments - match = scanScopeAST(scope,node.name, - AssignmentAndFnArgsSearcher(node.name)) - if match is not None: - return match - - # try imports - match = searchImportedModulesForDefinition(scope,node) - if match is not None: - return match - - - if not isinstance(scope,Module): - # try parent scope - scope = scope.getParent() - else: - break - assert isinstance(scope,Module) - - elif isinstance(node,Getattr) or isinstance(node,AssAttr): - exprtype = getTypeOfExpr(scope,node.expr) - if not (exprtype is None or isinstance(exprtype,UnfoundType)): - if isinstance(exprtype,Instance): - exprtype = exprtype.getType() - match = findDefinitionOfAttributeFromASTNode(exprtype, - node.attrname) - else: - match = findDefinitionFromASTNode(exprtype, - Name(node.attrname)) - if match is not None: - return match - - elif isinstance(node,compiler.ast.Function) or \ - isinstance(node,compiler.ast.Class): - if isAMethod(scope,node): - match = findDefinitionOfAttributeFromASTNode(scope, - node.name) - else: - match = findDefinitionFromASTNode(scope,Name(node.name)) - if match is not None: - return match - - - type = getTypeOfExpr(scope,node) - if type is not None and (not isinstance(type,UnfoundType)) and \ - (not isinstance(type,Instance)): - return convertNodeToMatchObject(type,100) - else: - return None - - -def findDefinitionOfAttributeFromASTNode(type,name): - assert isinstance(type,Class) - attrfinder = AttrbuteDefnFinder([type],name) - - # first scan the method names: - for child in type.getChildNodes(): - if child.name == name: - return convertNodeToMatchObject(child,100) - # then scan the method source for attribues - for child in type.getChildNodes(): - if isinstance(child,Function): - try: - return scanScopeForMatches(child.module.getSourceNode(), - child, attrfinder, - name).next() - except StopIteration: - continue - - -class AttrbuteDefnFinder(MatchFinder): - def __init__(self,targetClasses,targetAttribute): - self.targetClasses = targetClasses - self.targetAttributeName = targetAttribute - - def visitAssAttr(self, node): - for c in node.getChildNodes(): - self.visit(c) - - if node.attrname == self.targetAttributeName: - exprtype = getTypeOfExpr(self.scope,node.expr) - if isinstance(exprtype,Instance) and \ - exprtype.getType() in self.targetClasses: - self.appendMatch(self.targetAttributeName) - #else: - # self.appendMatch(self.targetAttributeName,50) - self.popWordsUpTo(node.attrname) - - - - -def searchImportedModulesForDefinition(scope,node): - lines = scope.module.getSourceNode().getLines() - for lineno in scope.getImportLineNumbers(): - logicalline = getLogicalLine(lines,lineno) - logicalline = makeLineParseable(logicalline) - ast = compiler.parse(logicalline) - class ImportVisitor: - def __init__(self,node): - self.target = node - self.match = None - assert isinstance(self.target,Name), \ - "Getattr not supported" - - def visitFrom(self, node): - module = resolveImportedModuleOrPackage(scope,node.modname) - if module is None: # couldn't find module - return - - if node.names[0][0] == '*': # e.g. from foo import * - match = findDefinitionFromASTNode(module,self.target) - if match is not None: - self.match = match - return - - for name, alias in node.names: - if alias is None and name == self.target.name: - match = findDefinitionFromASTNode(module,self.target) - if match is not None: - self.match = match - return - - - match = visitor.walk(ast, ImportVisitor(node)).match - if match: - return match - # loop - - -def getLogicalLine(lines,lineno): - return generateLogicalLines(lines[lineno-1:]).next() - -class AssignmentAndFnArgsSearcher(MatchFinder): - def __init__(self,name): - self.targetname = name - self.match = None - - def visitAssName(self, node): - if node.name == self.targetname: - idx = self.getNextIndexOfWord(self.targetname) - self.match = idx - return - - def visitFunction(self, node): - self.popWordsUpTo(node.name) - for arg, default in self.zipArgs(node.argnames, node.defaults): - if arg == self.targetname: - idx = self.getNextIndexOfWord(self.targetname) - self.match = idx - return - self.popWordsUpTo(arg) - if default is not None: - self.visit(default) - self.visit(node.code) - - def getMatch(self): - return self.match - - - -# scans for lines containing keyword, and then runs the visitor over -# the parsed AST for that line -def scanScopeAST(scope,keyword,matchfinder): - lines = scope.generateLinesNotIncludingThoseBelongingToChildScopes() - match = None - for line,linenum in generateLogicalLinesAndLineNumbers(lines): - if isWordInLine(keyword, line): - doctoredline = makeLineParseable(line) - ast = compiler.parse(doctoredline) - matchfinder.reset(line) - match = visitor.walk(ast,matchfinder).getMatch() - if match is not None: - column,yoffset = indexToCoordinates(line,match) - m = createMatch(scope,linenum + yoffset,column) - return m - return None - -def createMatch(scope,lineno,x): - m = Match() - m.sourcenode = scope.module.getSourceNode() - m.filename = m.sourcenode.filename - m.lineno = lineno - m.colno = x - m.confidence = 100 - return m - -# scan for methods globally (from perspective of 'perspectiveFilename') -def scanPythonPathForMatchingMethodNames(name, contextFilename): - class MethodFinder: - def __init__(self,srcnode): - self.matches = [] - self.srcnode = srcnode - def visitFunction(self,node): - node = getScopeForLine(self.srcnode, self.lineno) - if isinstance(node.getParent(),Class): - if node.name == name: - self.matches.append(convertNodeToMatchObject(node,50)) - - for srcnode in getSourceNodesContainingRegex(name,contextFilename): - m = MethodFinder(srcnode) - walkLinesContainingStrings(srcnode.fastparseroot,m,[name]) - for match in m.matches: - yield match - - -def getIndexOfWord(line,targetword): - words = re.split("(\w+)", line) - idx = 0 - for word in words: - if word == targetword: - break - idx += len(word) - return idx - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/findReferences.py --- a/vim/sadness/bike/bike/query/findReferences.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -from __future__ import generators -from bike.globals import * -from bike.parsing.fastparserast import Module, Class, Function, getRoot, Instance -from bike.query.common import Match, MatchFinder,\ - getScopeForLine, indexToCoordinates, \ - translateSourceCoordsIntoASTNode, scanScopeForMatches,\ - globalScanForMatches, isAMethod, convertNodeToMatchObject -from compiler.ast import AssName,Name,Getattr,AssAttr -import compiler -from findDefinition import findDefinitionFromASTNode -from bike.query.getTypeOf import getTypeOfExpr, UnfoundType -from bike.query.relationships import getRootClassesOfHierarchy -from bike import log -from bike.parsing.load import getSourceNode - - -class CouldntFindDefinitionException(Exception): - pass - -def findReferencesIncludingDefn(filename,lineno,col): - return findReferences(filename,lineno,col,1) - - -def findReferences(filename,lineno,col,includeDefn=0): - sourcenode = getSourceNode(filename) - node = translateSourceCoordsIntoASTNode(filename,lineno,col) - assert node is not None - scope,defnmatch = getDefinitionAndScope(sourcenode,lineno,node) - - try: - for match in findReferencesIncludingDefn_impl(sourcenode,node, - scope,defnmatch): - if not includeDefn and match == defnmatch: - continue # don't return definition - else: - yield match - except CouldntFindDefinitionException: - raise CouldntFindDefinitionException("Could not find definition. Please locate manually (maybe using find definition) and find references from that") - -def findReferencesIncludingDefn_impl(sourcenode,node,scope,defnmatch): - if isinstance(node,Name) or isinstance(node,AssName): - return generateRefsToName(node.name,scope,sourcenode,defnmatch) - elif isinstance(node,Getattr) or isinstance(node,AssAttr): - exprtype = getTypeOfExpr(scope,node.expr) - if exprtype is None or isinstance(exprtype,UnfoundType): - raise CouldntFindDefinitionException() - - if isinstance(exprtype,Instance): - exprtype = exprtype.getType() - return generateRefsToAttribute(exprtype,node.attrname) - - else: - targetname = node.attrname - return globalScanForMatches(sourcenode.filename, - NameRefFinder(targetname, defnmatch), - targetname, ) - if match is not None: - return match - elif isinstance(node,compiler.ast.Function) or \ - isinstance(node,compiler.ast.Class): - return handleClassOrFunctionRefs(scope, node, defnmatch) - else: - assert 0,"Seed to references must be Name,Getattr,Function or Class" - -def handleClassOrFunctionRefs(scope, node, defnmatch): - if isAMethod(scope,node): - for ref in generateRefsToAttribute(scope,node.name): - yield ref - else: - #yield convertNodeToMatchObject(node,100) - yield defnmatch - for ref in generateRefsToName(node.name,scope, - scope.module.getSourceNode(), - defnmatch): - yield ref - -def getDefinitionAndScope(sourcenode,lineno,node): - scope = getScopeForLine(sourcenode,lineno) - if scope.getStartLine() == lineno and \ - scope.matchesCompilerNode(node): # scope is the node - return scope.getParent(), convertNodeToMatchObject(scope,100) - defnmatch = findDefinitionFromASTNode(scope,node) - if defnmatch is None: - raise CouldntFindDefinitionException() - scope = getScopeForLine(sourcenode,defnmatch.lineno) - return scope,defnmatch - -def generateRefsToName(name,scope,sourcenode,defnmatch): - assert scope is not None - if isinstance(scope,Function): - # search can be limited to scope - return scanScopeForMatches(sourcenode,scope, - NameRefFinder(name,defnmatch), - name) - else: - return globalScanForMatches(sourcenode.filename, - NameRefFinder(name,defnmatch), - name) - - -class NameRefFinder(MatchFinder): - def __init__(self, targetstr,targetMatch): - self.targetstr = targetstr - self.targetMatch = targetMatch - - def visitName(self, node): - if node.name == self.targetstr: - potentualMatch = findDefinitionFromASTNode(self.scope, node) - if potentualMatch is not None and \ - potentualMatch == self.targetMatch: - self.appendMatch(node.name) - self.popWordsUpTo(node.name) - - visitAssName = visitName - - def visitFunction(self, node): - self.popWordsUpTo(node.name) - for arg, default in self.zipArgs(node.argnames, node.defaults): - if arg == self.targetstr: - self.appendMatch(arg) - self.popWordsUpTo(arg) - if default is not None: - self.visit(default) - self.visit(node.code) - - - def visitFrom(self, node): - for elem in node.modname.split("."): - self.popWordsUpTo(elem) - - for name, alias in node.names: - if name == self.targetstr: - if alias is not None: - pretendNode = Name(alias) - else: - pretendNode = Name(name) - if findDefinitionFromASTNode(self.scope, pretendNode) \ - == self.targetMatch: - self.appendMatch(name) - self.popWordsUpTo(name) - if alias is not None: - self.popWordsUpTo(alias) - - - def visitGetattr(self, node): - for c in node.getChildNodes(): - self.visit(c) - if node.attrname == self.targetstr: - defn = findDefinitionFromASTNode(self.scope, node) - if defn is not None and defn == self.targetMatch: - self.appendMatch(node.attrname) - self.popWordsUpTo(node.attrname) - - - def visitImport(self, node): - for name, alias in node.names: - if name.split(".")[-1] == self.targetstr: - getattr = self.createGetattr(name) - if findDefinitionFromASTNode(self.scope, getattr) == self.targetMatch: - self.appendMatch(self.targetstr) - for nameelem in name.split("."): - self.popWordsUpTo(nameelem) - if alias is not None: - self.popWordsUpTo(alias) - - - def createGetattr(self,fqn): - node = Name(fqn[0]) - for name in fqn.split(".")[1:]: - node = Getattr(node,name) - return node - -def generateRefsToAttribute(classobj,attrname): - rootClasses = getRootClassesOfHierarchy(classobj) - attrRefFinder = AttrbuteRefFinder(rootClasses,attrname) - for ref in globalScanForMatches(classobj.filename, attrRefFinder, attrname): - yield ref - print >>log.progress,"Done" - - -class AttrbuteRefFinder(MatchFinder): - def __init__(self,rootClasses,targetAttribute): - self.rootClasses = rootClasses - self.targetAttributeName = targetAttribute - - - def visitGetattr(self, node): - for c in node.getChildNodes(): - self.visit(c) - - if node.attrname == self.targetAttributeName: - exprtype = getTypeOfExpr(self.scope,node.expr) - - if isinstance(exprtype,Instance) and \ - self._isAClassInTheSameHierarchy(exprtype.getType()): - self.appendMatch(self.targetAttributeName) - elif isinstance(exprtype,UnfoundType) or \ - exprtype is None: # couldn't find type, so not sure - self.appendMatch(self.targetAttributeName,50) - else: - pass # definately not a match - self.popWordsUpTo(node.attrname) - - visitAssAttr = visitGetattr - - def visitFunction(self,node): # visit methods - if node.name == self.targetAttributeName: - parentScope = self.scope.getParent() - #print parentScope - #print self.targetClasses - if isinstance(parentScope,Class) and \ - self._isAClassInTheSameHierarchy(parentScope): - self.appendMatch(node.name) - - for c in node.getChildNodes(): - self.visit(c) - - def _isAClassInTheSameHierarchy(self,classobj): - #return classobj in self.targetClasses - targetRootClasses = getRootClassesOfHierarchy(classobj) - for rootclass in self.rootClasses: - if rootclass in targetRootClasses: - return True - return False diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/getAllRelatedClasses.py --- a/vim/sadness/bike/bike/query/getAllRelatedClasses.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ - - -""" - -def getAllRelatedClasses(root,classfqn): - classobj = getTypeOf(root,classfqn) - rootClasses = _getRootClasses(classobj) - #print rootClasses - relatedClasses = [] + rootClasses - for rootClass in rootClasses: - relatedClasses += _getAllSubClasses(rootClass,root) - return relatedClasses - -def _getRootClasses(klass): - if klass is None: # i.e. dont have base class in our ast - return None - if klass.getBaseClassNames() == []: # i.e. is a root class - return[klass] - else: - rootclasses = [] - for base in klass.getBaseClassNames(): - baseclass = getTypeOf(klass,base) - rootclass = _getRootClasses(baseclass) - if rootclass is None: # base class not in our ast - rootclass = [klass] - rootclasses+=rootclass - return rootclasses - - -def _getAllSubClasses(baseclass, root, subclasses = []): - class ClassVisitor: - def visitSource(self,node): - self.visit(node.fastparseroot) - - def visitClass(self, node): - for basename in node.getBaseClassNames(): - if basename.find(baseclass.name) != -1 and \ - getTypeOf(node,basename) == baseclass: - subclasses.append(node) - _getAllSubClasses(node,root,subclasses) - for child in node.getChildNodes(): - self.visit(child) - - walk(root, ClassVisitor()) - return subclasses - -""" diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/getPackageDependencies.py --- a/vim/sadness/bike/bike/query/getPackageDependencies.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -#!/usr/bin/env python - -# fileInPackage is the filename of a file in the package hierarchy -def getPackageDependencies(fileInPackage): - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/getReferencesToModule.py --- a/vim/sadness/bike/bike/query/getReferencesToModule.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -from __future__ import generators -from bike.query.common import Match, globalScanForMatches, getScopeForLine, MatchFinder -from getTypeOf import getTypeOf, getTypeOfExpr -import compiler -import re - -def getReferencesToModule(root, fqn): - - modulename = fqn.split(".")[-1] - moduleobj = getTypeOf(root, fqn) - moduleRefFinder = ModuleRefFinder(moduleobj) - - for ref in globalScanForMatches(moduleRefFinder, modulename): - yield ref - - -class ModuleRefFinder(MatchFinder): - def __init__(self, targetmodule): - self.targetmodule = targetmodule - - def visitName(self, node): - if node.name == self.targetmodule.name: - if getTypeOfExpr(self.scope, node) == self.targetmodule: - self.appendMatch(node.name) - self.popWordsUpTo(node.name) - - def visitImport(self, node): - for name, alias in node.names: - if name.split(".")[-1] == self.targetmodule.name: - if getTypeOf(self.scope, name) == self.targetmodule: - self.appendMatch(self.targetmodule.name) - for nameelem in name.split("."): - self.popWordsUpTo(nameelem) - if alias is not None: - self.popWordsUpTo(alias) - - def visitGetattr(self, node): - for c in node.getChildNodes(): - self.visit(c) - if node.attrname == self.targetmodule.name: - if getTypeOfExpr(self.scope, node) == self.targetmodule: - self.appendMatch(self.targetmodule.name) - self.popWordsUpTo(node.attrname) - - def visitFrom(self, node): - for elem in node.modname.split("."): - if elem == self.targetmodule.name: - getTypeOf(self.scope, elem) == self.targetmodule - self.appendMatch(self.targetmodule.name) - self.popWordsUpTo(elem) - - for name, alias in node.names: - if name == self.targetmodule.name: - if alias and \ - getTypeOf(self.scope, alias) == self.targetmodule: - self.appendMatch(self.targetmodule.name) - elif getTypeOf(self.scope, name) == self.targetmodule: - self.appendMatch(self.targetmodule.name) - if name != "*": - self.popWordsUpTo(name) - if alias is not None: - self.popWordsUpTo(alias) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/getTypeOf.py --- a/vim/sadness/bike/bike/query/getTypeOf.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,377 +0,0 @@ -# getTypeOf(scope,fqn) and getTypeOfExpr(scope,ast) - -from bike.parsing.fastparserast import Class, Function, Module, Root, getRoot, Package, Instance, getModule -from bike.parsing.parserutils import generateLogicalLines, makeLineParseable,splitLogicalLines, makeLineParseable -from bike.parsing import visitor -from bike import log -from bike.parsing.newstuff import getModuleOrPackageUsingFQN -from bike.parsing.pathutils import getPackageBaseDirectory -from bike.parsing.load import Cache -import os -import re -import compiler - -# used if an assignment exists, but cant find type -# e.g. a = SomeFunctionNotLoaded() -# (as opposed to 'None' if cant find an assignment) -class UnfoundType: pass - - -getTypeOfStack = [] - -# name is the fqn of the reference, scope is the scope ast object from -# which the question is being asked. -# returns an fastparser-ast object representing the type -# or None if type not found -def getTypeOf(scope, fqn): - if isinstance(scope, Root): - assert False, "Can't use getTypeOf to resolve from Root. Use getModuleOrPackageUsingFQN instead" - - - #print "getTypeOf:"+fqn+" -- "+str(scope) - #print - #print str(getTypeOfStack) - #print - if (fqn,scope) in getTypeOfStack: # loop protection - return None - - # this is crap! - hashcode = str(scope)+fqn - - try: - getTypeOfStack.append((fqn,scope)) - - try: - type = Cache.instance.typecache[hashcode] - except KeyError: - type = getTypeOf_impl(scope, fqn) - Cache.instance.typecache[hashcode] = type - return type - finally: - del getTypeOfStack[-1] - - - -def getTypeOf_impl(scope, fqn): - #print "getTypeOf_impl",scope,fqn - if fqn == "None": - return None - - if "."in fqn: - rcdr = ".".join(fqn.split(".")[:-1]) - rcar = fqn.split(".")[-1] - newscope = getTypeOf(scope,rcdr) - if newscope is not None: - return getTypeOf(newscope, rcar) - else: - #print "couldnt find "+rcdr+" in "+str(scope) - pass - - assert scope is not None - #assert not ("." in fqn) - - if isinstance(scope,UnfoundType): - return UnfoundType() - - if isinstance(scope, Package): - #assert 0,scope - return handlePackageScope(scope, fqn) - elif isinstance(scope,Instance): - return handleClassInstanceAttribute(scope, fqn) - else: - return handleModuleClassOrFunctionScope(scope,fqn) - - - -def handleModuleClassOrFunctionScope(scope,name): - if name == "self" and isinstance(scope,Function) and \ - isinstance(scope.getParent(),Class): - return Instance(scope.getParent()) - - matches = [c for c in scope.getChildNodes()if c.name == name] - if matches != []: - return matches[0] - - type = scanScopeSourceForType(scope, name) - if type != None: - return type - - #print "name = ",name,"scope = ",scope - type = getImportedType(scope, name) # try imported types - #print "type=",type - if type != None: - return type - parentScope = scope.getParent() - while isinstance(parentScope,Class): - # don't search class scope, since this is not accessible except - # through self (is this true?) - parentScope = parentScope.getParent() - - if not (isinstance(parentScope,Package) or isinstance(parentScope,Root)): - return getTypeOf(parentScope, name) - - -def handleClassInstanceAttribute(instance, attrname): - theClass = instance.getType() - - # search methods and inner classes - match = theClass.getChild(attrname) - if match: - return match - - #search methods for assignments with self.foo getattrs - for child in theClass.getChildNodes(): - if not isinstance(child,Function): - continue - res = scanScopeAST(child,attrname, - SelfAttributeAssignmentVisitor(child,attrname)) - if res is not None: - return res - -def handlePackageScope(package, fqn): - #print "handlePackageScope",package,fqn - child = package.getChild(fqn) - if child: - return child - - if isinstance(package,Root): - return getModuleOrPackageUsingFQN(fqn) - - # try searching the fs - node = getModuleOrPackageUsingFQN(fqn,package.path) - if node: - return node - - - - - # try the package init module - initmod = package.getChild("__init__") - if initmod is not None: - type = getImportedType(initmod, fqn) - if type: - return type - # maybe fqn is absolute - return getTypeOf(getRoot(), fqn) - - -wordRE = re.compile("\w+") -def isWordInLine(word, line): - if line.find(word) != -1: - words = wordRE.findall(line) - if word in words: - return 1 - return 0 - -def getImportedType(scope, fqn): - lines = scope.module.getSourceNode().getLines() - for lineno in scope.getImportLineNumbers(): - logicalline = generateLogicalLines(lines[lineno-1:]).next() - logicalline = makeLineParseable(logicalline) - ast = compiler.parse(logicalline) - match = visitor.walk(ast, ImportVisitor(scope,fqn)).match - if match: - return match - #else loop - -class ImportVisitor: - def __init__(self,scope,fqn): - self.match = None - self.targetfqn = fqn - self.scope = scope - - def visitImport(self, node): - # if target fqn is an import, then it must be a module or package - for name, alias in node.names: - if name == self.targetfqn: - self.match = resolveImportedModuleOrPackage(self.scope,name) - elif alias is not None and alias == self.targetfqn: - self.match = resolveImportedModuleOrPackage(self.scope,name) - - def visitFrom(self, node): - if node.names[0][0] == '*': # e.g. from foo import * - if not "."in self.targetfqn: - module = resolveImportedModuleOrPackage(self.scope, - node.modname) - if module: - self.match = getTypeOf(module, self.targetfqn) - else: - for name, alias in node.names: - if alias == self.targetfqn or \ - (alias is None and name == self.targetfqn): - scope = resolveImportedModuleOrPackage(self.scope, - node.modname) - if scope is not None: - if isinstance(scope,Package): - self.match = getModuleOrPackageUsingFQN(name,scope.path) - else: - assert isinstance(scope,Module) - self.match = getTypeOf(scope, name) - - - - -class TypeNotSupportedException: - def __init__(self,msg): - self.msg = msg - - def __str__(self): - return self.msg - -# attempts to evaluate the type of the expression -def getTypeOfExpr(scope, ast): - if isinstance(ast, compiler.ast.Name): - return getTypeOf(scope, ast.name) - - elif isinstance(ast, compiler.ast.Getattr) or \ - isinstance(ast, compiler.ast.AssAttr): - - # need to do this in order to match foo.bah.baz as - # a string in import statements - fqn = attemptToConvertGetattrToFqn(ast) - if fqn is not None: - return getTypeOf(scope,fqn) - - expr = getTypeOfExpr(scope, ast.expr) - if expr is not None: - attrnametype = getTypeOf(expr, ast.attrname) - return attrnametype - return None - - elif isinstance(ast, compiler.ast.CallFunc): - node = getTypeOfExpr(scope,ast.node) - if isinstance(node,Class): - return Instance(node) - elif isinstance(node,Function): - return getReturnTypeOfFunction(node) - else: - #raise TypeNotSupportedException, \ - # "Evaluation of "+str(ast)+" not supported. scope="+str(scope) - print >> log.warning, "Evaluation of "+str(ast)+" not supported. scope="+str(scope) - return None - - -def attemptToConvertGetattrToFqn(ast): - fqn = ast.attrname - ast = ast.expr - while isinstance(ast,compiler.ast.Getattr): - fqn = ast.attrname + "." + fqn - ast = ast.expr - if isinstance(ast,compiler.ast.Name): - return ast.name + "." + fqn - else: - return None - - -getReturnTypeOfFunction_stack = [] -def getReturnTypeOfFunction(function): - if function in getReturnTypeOfFunction_stack: # loop protection - return None - try: - getReturnTypeOfFunction_stack.append(function) - return getReturnTypeOfFunction_impl(function) - finally: - del getReturnTypeOfFunction_stack[-1] - -def getReturnTypeOfFunction_impl(function): - return scanScopeAST(function,"return",ReturnTypeVisitor(function)) - - -# does parse of scope sourcecode to deduce type -def scanScopeSourceForType(scope, name): - return scanScopeAST(scope,name,AssignmentVisitor(scope,name)) - - -# scans for lines containing keyword, and then runs the visitor over -# the parsed AST for that line -def scanScopeAST(scope,keyword,astvisitor): - lines = scope.getLinesNotIncludingThoseBelongingToChildScopes() - src = ''.join(lines) - match = None - #print "scanScopeAST:"+str(scope) - for line in splitLogicalLines(src): - if isWordInLine(keyword, line): - #print "scanning for "+keyword+" in line:"+line[:-1] - doctoredline = makeLineParseable(line) - ast = compiler.parse(doctoredline) - match = visitor.walk(ast,astvisitor).getMatch() - if match: - return match - return match - - -class AssignmentVisitor: - def __init__(self,scope,targetName): - self.match=None - self.scope = scope - self.targetName = targetName - - def getMatch(self): - return self.match - - def visitAssign(self,node): - if isinstance(node.expr,compiler.ast.CallFunc): - for assnode in node.nodes: - if isinstance(assnode,compiler.ast.AssName) and \ - assnode.name == self.targetName: - self.match = getTypeOfExpr(self.scope,node.expr) - if self.match is None: - self.match = UnfoundType() - - - -class SelfAttributeAssignmentVisitor: - def __init__(self,scope,targetName): - self.match=None - self.scope = scope - self.targetName = targetName - - def getMatch(self): - return self.match - - def visitAssign(self,node): - if isinstance(node.expr,compiler.ast.CallFunc): - for assnode in node.nodes: - if isinstance(assnode,compiler.ast.AssAttr) and \ - isinstance(assnode.expr,compiler.ast.Name) and \ - assnode.expr.name == "self" and \ - assnode.attrname == self.targetName: - self.match = getTypeOfExpr(self.scope,node.expr) - #print "here!",self.match.getType().fqn - - -class ReturnTypeVisitor: - def __init__(self,fn): - self.match=None - self.fn = fn - - def getMatch(self): - return self.match - - def visitReturn(self,node): - try: - self.match = getTypeOfExpr(self.fn,node.value) - except TypeNotSupportedException, ex: - pass - - -def resolveImportedModuleOrPackage(scope,fqn): - # try searching from directory containing scope module - path = os.path.dirname(scope.module.filename) - node = getModuleOrPackageUsingFQN(fqn,path) - if node is not None: - return node - - # try searching in same package hierarchy - basedir = getPackageBaseDirectory(scope.module.filename) - if fqn.split('.')[0] == os.path.split(basedir)[-1]: - # base package in fqn matches base directory - restOfFqn = ".".join(fqn.split('.')[1:]) - node = getModuleOrPackageUsingFQN(restOfFqn,basedir) - if node is not None: - return node - - # try searching the python path - node = getModuleOrPackageUsingFQN(fqn) - if node is not None: - return node diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/relationships.py --- a/vim/sadness/bike/bike/query/relationships.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -# queries to do with module/class/function relationships -from __future__ import generators -from bike.globals import * -from getTypeOf import getTypeOf, getTypeOfExpr -from bike.parsing.newstuff import generateModuleFilenamesInPythonPath, generateModuleFilenamesInPackage, getPythonPath -from bike.parsing.pathutils import getPackageBaseDirectory -from bike.query.common import MatchFinder, walkLinesContainingStrings, getScopeForLine -from bike import log -from bike.parsing.fastparserast import Module -import re - -def getRootClassesOfHierarchy(klass): - if klass is None: # i.e. dont have base class in our ast - return None - if klass.getBaseClassNames() == []: # i.e. is a root class - return [klass] - else: - rootclasses = [] - for base in klass.getBaseClassNames(): - baseclass = getTypeOf(klass,base) - rootclass = getRootClassesOfHierarchy(baseclass) - if rootclass is None: # base class not in our ast - rootclass = [klass] - rootclasses+=rootclass - return rootclasses - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/setpath.py --- a/vim/sadness/bike/bike/query/setpath.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -import sys,os -if not os.path.abspath("..") in sys.path: - from bike import log - print >> log.warning, "Appending to the system path. This should only happen in unit tests" - sys.path.append(os.path.abspath("..")) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_common.py --- a/vim/sadness/bike/bike/query/test_common.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -import compiler -from bike.testutils import * -from bike.parsing.load import getSourceNode -from bike.parsing.fastparser import fastparser -from bike.parsing.fastparserast import Module, Class -from common import indexToCoordinates, getScopeForLine, walkLinesContainingStrings, translateSourceCoordsIntoASTNode - - -class TestGetScopeForLine(BRMTestCase): - - def test_worksWithFunctionScope(self): - src = trimLines(""" - class a: - def foo(): - pass - """) - node = createAST(src) - self.assertEqual(getScopeForLine(node,3).name,"foo") - - def test_worksWithModuleScope(self): - src = trimLines(""" - class TheClass: - pass - a = TheClass() - """) - node = createAST(src) - assert isinstance(getScopeForLine(node,3),Module) - - def test_worksWithInlineClass(self): - src = trimLines(""" - class TheClass: pass""") - node = createAST(src) - assert isinstance(getScopeForLine(node,1),Class) - - -class TestIndexToCoordinates(BRMTestCase): - - def test_worksOnSingleLineString(self): - src = trimLines(''' - foo bah - ''') - x,y = indexToCoordinates(src,src.index("bah")) - self.assertEqual(x,4) - self.assertEqual(y,0) - x,y = indexToCoordinates(src,src.index("foo")) - self.assertEqual(x,0) - self.assertEqual(y,0) - - def test_worksOnMultilLineString(self): - src = trimLines(''' - foo bah - baz boh - ''') - x,y = indexToCoordinates(src,src.index("boh")) - self.assertEqual(x,4) - self.assertEqual(y,1) - - -class TestTranslateSourceCoordsIntoASTNode(BRMTestCase): - - def test_worksOnImport(self): - src = trimLines(''' - from foo import bar, baz - ''') - createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - node = translateSourceCoordsIntoASTNode(filename, 1, 17) - assert node.name == 'bar' - - def test_worksOnMultiline(self): - src = trimLines(""" - def foo(x, - y, - z): - return x*y*z - """) - createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - node = translateSourceCoordsIntoASTNode(filename, 3, 8) - assert node.name == 'z' - - - - -class TestMatchFinder(BRMTestCase): - - def test_visitLambda(self): - from common import MatchFinder - finder = MatchFinder() - src = '''x = lambda a, b, c=None, d=None: (a + b) and c or d''' - ast = compiler.parse(src) - finder.reset(src) - compiler.walk(ast, finder) - - -class TestWalkLinesContainingStrings(BRMTestCase): - def test_walksClasses(self): - src=trimLines(""" - class TestClass(a, - baseclass): - pass - """) - class MyWalker: - def visitClass(self, node): - self.basenames = [] - for name in node.bases: - self.basenames.append(name.name) - - writeTmpTestFile(src) - srcnode = getSourceNode(tmpfile) - walker = MyWalker() - walkLinesContainingStrings(srcnode.fastparseroot,walker, - "baseclass") - self.assertEqual(["a","baseclass"],walker.basenames) - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_findDefinition.py --- a/vim/sadness/bike/bike/query/test_findDefinition.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,632 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os - -from bike import testdata -from bike.query.findDefinition import findAllPossibleDefinitionsByCoords -from bike.query.getTypeOf import getTypeOf,resolveImportedModuleOrPackage -from bike.parsing.newstuff import getModuleOrPackageUsingFQN -from bike.parsing.fastparserast import getRoot -from bike.testutils import * - -class TestFindDefinitionByCoords(BRMTestCase): - - def test_findsClassRef(self): - src=trimLines(""" - class TheClass: - pass - a = TheClass() - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),3,6)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - def tests_findsMethodRef(self): - src=trimLines(""" - class TheClass: - def theMethod(self): - pass - a = TheClass() - a.theMethod() - """) - - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),5,3)] - - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 2 - assert defn[0].colno == 8 - assert defn[0].confidence == 100 - - - def test_returnsOtherMethodsWithSameName(self): - src=trimLines(""" - class TheClass: - def theMethod(self): - pass - a = SomeOtherClass() - a.theMethod() - """) - - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),5,3)] - - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 2 - assert defn[0].colno == 8 - assert defn[0].confidence == 50 - - - - - def test_findsTemporaryDefinition(self): - src=trimLines(""" - a = 3 - b = a + 1 - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),2,4)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - def test_findsArgumentDefinition(self): - src=trimLines(""" - def someFunction(a): - b = a + 1 - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),2,8)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 1 - assert defn[0].colno == 17 - assert defn[0].confidence == 100 - - def test_findsClassInstanceDefinition(self): - src=trimLines(""" - class TheClass(): - pass - a = TheClass() - print a - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),4,6)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 3 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - def test_findsDefinitionInParentScope(self): - src=trimLines(""" - a = 3 - def foo(self): - b = a + 1 - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),3,8)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - def test_findsDefinitionWithinFunction(self): - src=trimLines(""" - def foo(yadda): - a = someFunction() - print a - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),3,10)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 2 - assert defn[0].colno == 4 - assert defn[0].confidence == 100 - - - def test_findsDefinitionFromSubsequentAssignment(self): - src=trimLines(""" - def foo(yadda): - a = 3 - print a - a = 5 - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),4,4)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 2 - assert defn[0].colno == 4 - assert defn[0].confidence == 100 - - def test_findsDefinitionFromDefinition(self): - src=trimLines(""" - def foo(yadda): - a = 3 - print a - a = 5 - """) - createSourceNodeAt(src,"mymodule") - defn = [x for x in findAllPossibleDefinitionsByCoords(os.path.abspath("mymodule.py"),4,4)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 2 - assert defn[0].colno == 4 - assert defn[0].confidence == 100 - - - def test_findsClassRefUsingFromImportStatement(self): - src=trimLines(""" - from a.b.bah import TheClass - """) - classsrc=trimLines(""" - class TheClass: - pass - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(classsrc, "a.b.bah") - module = getModuleOrPackageUsingFQN("a.foo") - filename = os.path.abspath(os.path.join("a","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,1,21)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - - def test_findsVariableRefUsingFromImportStatement(self): - importsrc=trimLines(""" - from a.b.bah import mytext - print mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - root = createSourceNodeAt(importsrc,"a.foo") - root = createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,6)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - - def test_findsVariableRefUsingImportStatement(self): - importsrc=trimLines(""" - import a.b.bah - print a.b.bah.mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - root = createSourceNodeAt(importsrc,"a.foo") - root = createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,14)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - - def test_findsVariableRefUsingFromImportStarStatement(self): - importsrc=trimLines(""" - from a.b.bah import * - print mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - createSourceNodeAt(importsrc,"a.foo") - createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,6)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - def test_findsVariableRefUsingFromPackageImportModuleStatement(self): - importsrc=trimLines(""" - from a.b import bah - print bah.mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - root = createSourceNodeAt(importsrc,"a.b.foo") - root = createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","b","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,10)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - def test_findsImportedVariableRefInAFunctionArg(self): - importsrc=trimLines(""" - from a.b import bah - someFunction(bah.mytext) - """) - src=trimLines(""" - mytext = 'hello' - """) - root = createSourceNodeAt(importsrc,"a.b.foo") - root = createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","b","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,17)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - - def test_findsVariableRefUsingFromImportStatementInFunction(self): - importsrc=trimLines(""" - def foo: - from a.b.bah import mytext - print mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - root = createSourceNodeAt(importsrc,"a.foo") - root = createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,3,10)] - assert defn[0].filename == os.path.abspath(os.path.join("a","b","bah.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - def test_findsVariableRefByImportingModule(self): - importsrc=trimLines(""" - import a.b.bah - print a.b.bah.mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - defn = self.helper(importsrc, src, 2, 14) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - - def test_findsVariableRefByImportingModuleWithFrom(self): - importsrc=trimLines(""" - from a.b import bah - someFunction(bah.mytext) - """) - src=trimLines(""" - mytext = 'hello' - """) - - defn = self.helper(importsrc, src, 2, 17) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 1 - assert defn[0].colno == 0 - assert defn[0].confidence == 100 - - - def helper(self, src, classsrc, line, col): - try: - createPackageStructure(src,classsrc) - filename = pkgstructureFile1 - #Root(None,None,[pkgstructureRootDir]) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,line,col)] - finally: - removePackageStructure() - return defn - - def test_doesntfindVariableRefOfUnimportedModule(self): - importsrc=trimLines(""" - # a.b.bah not imported - print a.b.bah.mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - root = createSourceNodeAt(importsrc,"a.b.foo") - root = createSourceNodeAt(src, "a.b.bah") - filename = os.path.abspath(os.path.join("a","b","foo.py")) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,14)] - self.assertEqual(defn,[]) - - - - def test_findsSelfAttributeDefinition(self): - src=trimLines(""" - class MyClass: - def __init__(self): - self.a = 'hello' - def myMethod(self): - print self.a - """) - root = createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,5,18)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 3 - assert defn[0].colno == 12 - assert defn[0].confidence == 100 - - def test_findsSelfAttributeDefinitionFromSamePlace(self): - src=trimLines(""" - class MyClass: - def __init__(self): - self.a = 'hello' - def myMethod(self): - print self.a - """) - root = createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,3,12)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 3 - assert defn[0].colno == 12 - assert defn[0].confidence == 100 - - - def test_findsSelfAttributeDefinition(self): - src=trimLines(""" - class MyClass: - def someOtherFn(self): - pass - def load(self, source): - # fastparser ast - self.fastparseroot = fastparser(source,self.modulename) - """) - root = createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,6,14)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 6 - assert defn[0].colno == 13 - assert defn[0].confidence == 100 - - - def test_findsDefnOfInnerClass(self): - src = trimLines(""" - class TheClass: - class TheClass: - pass - a = TheClass.TheClass() - """) - root = createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,4,14)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 2 - assert defn[0].colno == 10 - assert defn[0].confidence == 100 - - def test_findsDefnOfOuterClass(self): - src = trimLines(""" - class TheClass: - class TheClass: - pass - a = TheClass.TheClass() - """) - root = createSourceNodeAt(src,"mymodule") - filename = os.path.abspath("mymodule.py") - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,4,4)] - assert defn[0].filename == os.path.abspath("mymodule.py") - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - - def test_findsClassDeclaredIn__init__Module(self): - importsrc=trimLines(""" - class TheClass: - pass - """) - src=trimLines(""" - from a import TheClass - c = TheClass() - """) - - - - root = createSourceNodeAt(importsrc,"a.__init__") - root = createSourceNodeAt(src, "mymodule") - filename = os.path.abspath("mymodule.py") - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,2,6)] - assert defn[0].filename == os.path.abspath(os.path.join("a", - "__init__.py")) - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - -class TestFindDefinitionUsingFiles(BRMTestCase): - def test_findsASimpleDefinitionUsingFiles(self): - src=trimLines(""" - class TheClass: - pass - a = TheClass() - """) - writeTmpTestFile(src) - defn = [x for x in findAllPossibleDefinitionsByCoords(tmpfile,3,6)] - assert defn[0].filename == tmpfile - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - - def test_findsDefinitionInAnotherModuleUsingFiles(self): - src=trimLines(""" - from a.b.bah import TheClass - """) - classsrc=trimLines(""" - class TheClass: - pass - """) - defn = self.helper(src, classsrc, 1, 21) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - - - def test_findsDefinitionInAnotherRelativeModuleUsingFiles(self): - src=trimLines(""" - from b.bah import TheClass - """) - classsrc=trimLines(""" - class TheClass: - pass - """) - defn = self.helper(src, classsrc,1,21) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - def test_findsMethodDefinitionInAnotherModuleUsingFiles(self): - src=trimLines(""" - from b.bah import TheClass - a = TheClass() - a.theMethod() - """) - classsrc=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - defn = self.helper(src, classsrc, 3, 2) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 2 - assert defn[0].colno == 8 - assert defn[0].confidence == 100 - - def test_findsDefinitonOfMethodWhenUseIsOnAMultiLine(self): - classsrc=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - src=trimLines(""" - from b.bah import TheClass - a = TheClass() - i,j = (32, - a.theMethod()) # <--- find me! - something=somethingelse - """) - defn = self.helper(src, classsrc, 4, 9) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 2 - assert defn[0].colno == 8 - assert defn[0].confidence == 100 - - - def test_findsDefinitionWhenUseIsOnAMultilineAndNextLineBalancesBrace(self): - classsrc=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - src=trimLines(""" - from b.bah import TheClass - c = TheClass() - f1, f2 = (c.func1, - c.theMethod) - f1, f2 = (c.func1, - c.theMethod) - """) - defn = self.helper(src, classsrc, 4, 10) - self.assertEqual(pkgstructureFile2,defn[0].filename) - self.assertEqual(2,defn[0].lineno) - self.assertEqual(8,defn[0].colno) - self.assertEqual(100,defn[0].confidence) - - def test_worksIfFindingDefnOfRefInSlashMultiline(self): - classsrc=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - src=trimLines(""" - from b.bah import TheClass - c = TheClass() - f1, f2 = c.func1 \\ - ,c.theMethod - """) - defn = self.helper(src, classsrc, 4, 10) - self.assertEqual(pkgstructureFile2,defn[0].filename) - self.assertEqual(2,defn[0].lineno) - self.assertEqual(8,defn[0].colno) - self.assertEqual(100,defn[0].confidence) - - def test_findsDefnInSameNonPackageDirectory(self): - try: - getRoot().pythonpath = [] # clear the python path - classsrc = trimLines(""" - def testFunction(): - print 'hello' - """) - src = trimLines(""" - from baz import testFunction - """) - writeTmpTestFile(src) - newtmpfile = os.path.join(tmproot,"baz.py") - writeFile(newtmpfile, classsrc) - refs = [x for x in findAllPossibleDefinitionsByCoords(tmpfile,1,16)] - assert refs[0].filename == newtmpfile - assert refs[0].lineno == 1 - finally: - os.remove(newtmpfile) - deleteTmpTestFile() - - - def test_findsDefnInPackageSubDirectoryAndRootNotInPath(self): - src=trimLines(""" - from b.bah import TheClass - """) - classsrc=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - getRoot().pythonpath = [] # clear the python path - defn = self.helper(src, classsrc, 1, 18) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - def test_findsDefnInSamePackageHierarchyAndRootNotInPath(self): - src=trimLines(""" - from a.b.bah import TheClass - """) - classsrc=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - getRoot().pythonpath = [] # clear the python path - defn = self.helper(src, classsrc, 1, 20) - assert defn[0].filename == pkgstructureFile2 - assert defn[0].lineno == 1 - assert defn[0].colno == 6 - assert defn[0].confidence == 100 - - def helper(self, src, classsrc, line, col): - try: - createPackageStructure(src,classsrc) - filename = pkgstructureFile1 - #Root(None,None,[pkgstructureRootDir]) - defn = [x for x in findAllPossibleDefinitionsByCoords(filename,line,col)] - finally: - removePackageStructure() - return defn - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_findReferences.py --- a/vim/sadness/bike/bike/query/test_findReferences.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,516 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * -#from bike.testutils import trimLines, createSourceNodeAt, \ -# createSourceNodeAt_old, BRMTestCase -from bike import testdata -from findReferences import findReferences, findReferencesIncludingDefn -from bike.query.getTypeOf import getTypeOf - -class helpers: - def helper(self,src,lineno,colno): - writeTmpTestFile(src) - refs = [x for x in findReferences(tmpfile,lineno,colno)] - return refs - - def helper2(self,src,lineno,colno): - writeTmpTestFile(src) - refs = [x for x in findReferencesIncludingDefn(tmpfile,lineno, - colno)] - return refs - - def helper3(self, src, importedsrc, line, col): - createPackageStructure(src,importedsrc) - filename = pkgstructureFile2 - refs = [x for x in findReferences(filename,line,col) - if x.confidence == 100] - return refs - - def helper4(self, src, importedsrc, line, col): - createPackageStructure(src,importedsrc) - filename = pkgstructureFile1 - refs = [x for x in findReferences(filename,line,col) - if x.confidence == 100] - return refs - - - -class TestFindReferences(BRMTestCase,helpers): - def test_findsSimpleReferencesGivenAssignment(self): - src=trimLines(""" - def foo(): - a = 3 - print a - """) - refs = self.helper(src,3,10) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 3 - assert refs[0].colno == 10 - assert refs[0].confidence == 100 - - - - def test_findsSimpleReferencesGivenReference(self): - src=trimLines(""" - def foo(): - a = 3 - print a - """) - - refs = self.helper2(src,3,10) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 2 - assert refs[0].colno == 4 - assert refs[0].confidence == 100 - - - def test_findsReferencesToOtherAssignments(self): - src=trimLines(""" - def foo(): - a = 3 - a = 4 - """) - refs = self.helper(src,2,4) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 3 - assert refs[0].colno == 4 - assert refs[0].confidence == 100 - - def test_findsFunctionArg(self): - src=trimLines(""" - def foo(a): - print a - """) - refs = self.helper2(src,2,10) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 1 - assert refs[0].colno == 8 - assert refs[0].confidence == 100 - - def test_findsFunctionArgWithDefault(self): - src=trimLines(""" - def foo(a=None, b=None): - print a, b - """) - refs = self.helper(src,1,4) - self.assertEquals(refs, []) - - def test_findsFunctionArgWithDefault2(self): - src=trimLines(""" - def foo(a=None, b=None): - print a, b - """) - refs = self.helper2(src,2,13) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 1 - assert refs[0].colno == 16 - assert refs[0].confidence == 100 - - - def test_findsReferencesGivenFunctionArg(self): - src=trimLines(""" - def foo(a): - print a - """) - refs = self.helper(src,1,8) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 2 - assert refs[0].colno == 10 - assert refs[0].confidence == 100 - - - def test_findsVariableRefInImportStatementUsingFromImportStatement(self): - importsrc=trimLines(""" - from a.b.bah import mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - refs = self.helper3(importsrc,src,1,1) - assert refs[0].filename == pkgstructureFile1 - assert refs[0].lineno == 1 - assert refs[0].colno == 20 - assert refs[0].confidence == 100 - - - - def test_findsVariableRefUsingFromImportStatement(self): - importsrc=trimLines(""" - from a.b.bah import mytext - print mytext - """) - src=trimLines(""" - mytext = 'hello' - """) - refs = self.helper3(importsrc,src,1,1) - assert refs[0].filename == pkgstructureFile1 - assert refs[1].lineno == 2 - assert refs[1].colno == 6 - assert refs[1].confidence == 100 - - def test_findsImportedVariableRefInAFunctionArg(self): - importsrc=trimLines(""" - from a.b import bah - someFunction(bah.mytext) - """) - src=trimLines(""" - mytext = 'hello' - """) - refs = self.helper3(importsrc,src,1,1) - assert refs[0].filename == pkgstructureFile1 - assert refs[0].lineno == 2 - assert refs[0].colno == 17 - assert refs[0].confidence == 100 - - def test_getsReferenceOfSimpleMethodCall(self): - src = trimLines(""" - from b.bah import TheClass - a = TheClass() - a.theMethod() - """) - - refs = self.helper4(src,testdata.TheClass,3,2) - assert refs[0].filename == pkgstructureFile1 - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,2) - - - def test_findsRefToSelfAttribute(self): - src=trimLines(""" - class MyClass: - def __init__(self): - self.a = 'hello' - def myMethod(self): - print self.a - """) - refs = self.helper(src,3,12) - assert refs[0].filename == tmpfile - assert refs[0].lineno == 5 - assert refs[0].colno == 18 - assert refs[0].confidence == 100 - - -class FindReferencesToMethod(BRMTestCase,helpers): - def test_findsReferenceOfSimpleMethodCall(self): - src = trimLines(""" - from b.bah import TheClass - a = TheClass() - a.theMethod() - """) - refs = self.helper3(src,testClass,2,8) - assert refs[0].filename == pkgstructureFile1 - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,2) - self.assertEqual(refs[0].colno,2) - - def test_getsReferenceOfMethodCallFromClassImportedWithAlias(self): - src = trimLines(""" - from b.bah import TheClass as MyTheClass - - def foo(): - a = MyTheClass() - a.theMethod() - """) - refs = self.helper3(src,testClass,2,8) - assert refs[0].filename == pkgstructureFile1 - self.assertEqual(refs[0].lineno,5) - self.assertEqual(refs[0].colno,6) - - - def test_getsReferenceOfMethodCallWhenInstanceReturnedByFunction(self): - src = trimLines(""" - from b.bah import TheClass - - def foo(): - return TheClass() - a = foo() - a.theMethod() - """) - refs = self.helper3(src,testClass,2,8) - assert refs[0].filename == pkgstructureFile1 - self.assertEqual(refs[0].lineno,6) - self.assertEqual(refs[0].colno,2) - - def test_getsReferenceOfMethodCallInSameClass(self): - src = trimLines(""" - class TheClass: - def theMethod(self): - pass - def anotherMethod(self): - self.theMethod() - """) - refs = self.helper4(src,testClass,2,8) - assert refs[0].filename == pkgstructureFile1 - self.assertEqual(refs[0].lineno,5) - self.assertEqual(refs[0].colno,13) - - def test_getsReferenceOfMethodOnBaseClassInstance(self): - src = trimLines(""" - class root: - def theMethod(self): - pass - - class a(root): - def theMethod(self): - pass - - class b(root): - pass - - class TheClass(b): - def theMethod(self): - pass - - rootinstance = root() - rootinstance.theMethod() - """) - refs = self.helper4(src,"pass",2,8) - self.assertEqual(refs[2].filename,pkgstructureFile1) - self.assertEqual(refs[2].lineno,17) - self.assertEqual(refs[2].colno,13) - - def test_doesntGetReferenceToMethodWhenObjectCreatedInChildScopeToMethodReference(self): - src = trimLines(""" - from b.bah import TheClass - a = AnotherClass() - def foo(): - a = TheClass() - a.theMethod() - """) - refs = self.helper3(src,testClass,2,8) - assert refs == [] - - def test_renamesMethodReferenceOfInstanceCreatedInSubsequentFunction(self): - src = trimLines(""" - class TheClass: - def theMethod(): - pass - class NotTheClass: - def theMethod(): - pass - - def foo(): - a = bah() - a.theMethod() - - def bah(): - return TheClass() - """) - refs = self.helper4(src,"pass",2,8) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,10) - self.assertEqual(refs[0].colno,6) - - - def test_getsReferenceInMiddleOfBiggerCompoundCall(self): - src = trimLines(""" - class TheClass: - def theMethod(self): return AnotherClass() - TheClass().theMethod().anotherMethod() - """) - - refs = self.helper4(src,"pass",2,8) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,11) - self.assertEqual(refs[0].colend,20) - - def test_doesntBarfWhenObjectIsArrayMember(self): - src = trimLines(""" - class TheClass: - def theMethod(self): - pass - a[0] = TheClass() - a[0].theMethod() - """) - refs = self.helper4(src,"pass",2,8) - # should get to here without exception - -class FindReferencesToClass(BRMTestCase, helpers): - def test_returnsEmptyListIfNoReferences(self): - src = trimLines(""" - class MyClass: - pass - a = TheClass() - """) - refs = self.helper4(src,"pass",1,6) - assert refs == [] - - - def test_findsSimpleReferenceInSameModule(self): - src = trimLines(""" - class TheClass: - pass - a = TheClass() - """) - refs = self.helper4(src,"pass",1,6) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,4) - self.assertEqual(refs[0].confidence,100) - - def test_doesntBarfOnSingleLineSourceWithInlineClass(self): - src=trimLines(""" - from b.bah import TheClass - a = TheClass() - """) - refs = self.helper3(src,"class TheClass: pass",1,6) - assert refs != [] - - def test_findsReferenceToClassImportedInSameClassScope(self): - src=trimLines(""" - class AnotherClass: - from b.bah import TheClass - TheClass.baz = 0 - """) - refs = self.helper3(src,"class TheClass: pass",1,6) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,22) - - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[1].lineno,3) - self.assertEqual(refs[1].colno,4) - - def testFindsClassReferenceWhenScopeIsSameNameAsClass(self): - src = trimLines(""" - class TheClass: - class TheClass: - pass - a = TheClass.TheClass() - """) - refs = self.helper4(src,"pass",2,10) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,4) - self.assertEqual(refs[0].colno,13) - self.assertEqual(refs[0].confidence,100) - - def testFindsClassReferenceWhenChildIsSameNameAsClass(self): - src = trimLines(""" - class TheClass: - class TheClass: - pass - a = TheClass.TheClass() - """) - refs = self.helper4(src,"pass",1,6) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,4) - self.assertEqual(refs[0].colno,4) - self.assertEqual(refs[0].confidence,100) - - -class TestFindReferencesIncludingDefn(BRMTestCase,helpers): - def test_findsMethodDecl(self): - src=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - refs = self.helper2(src,2,8) - self.assertEqual(refs[0].filename,tmpfile) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,8) - self.assertEqual(refs[0].confidence,100) - - - -class TestFindReferencesUsingFiles(BRMTestCase): - def test_findsSimpleReferencesUsingFiles(self): - src=trimLines(""" - def foo(): - a = 3 - print a - """) - refs = self.helper("pass",src,2,4) - assert refs[0].filename == pkgstructureFile2 - assert refs[0].lineno == 3 - assert refs[0].colno == 10 - assert refs[0].confidence == 100 - - def test_findsReferenceInModuleWhichImportsClassWithFromAndAlias(self): - src = trimLines(""" - from b.bah import TheClass as MyTheClass - def foo(): - a = MyTheClass() - """) - refs = self.helper(src,testClass,1,6) - self.assertEqual(refs[0].filename,pkgstructureFile1) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,18) - self.assertEqual(refs[0].confidence,100) - - - def test_doesntBarfWhenCantLocatePackageWhenTryingToFindBaseClass(self): - src = trimLines(""" - from doesntexist import baseclass - class foo(baseclass): - def myMethod(self): - pass - """) - refs = self.helper("",src,3,8) - - def test_doesntBarfWhenComesAcrossAPrintNl(self): - src = trimLines(""" - class TheClass: - pass - - print >>foo, TheClass - """) - refs = self.helper("",src,1,6) - - - def test_returnsOtherFilesInSameNonPackageDirectory(self): - try: - getRoot().pythonpath = [] # clear the python path - classsrc = trimLines(""" - def testFunction(): - print 'hello' - """) - src = trimLines(""" - from baz import testFunction - """) - writeTmpTestFile(src) - newtmpfile = os.path.join(tmproot,"baz.py") - writeFile(newtmpfile, classsrc) - refs = [x for x in findReferences(newtmpfile,1,4)] - - assert refs[0].filename == tmpfile - assert refs[0].lineno == 1 - finally: - os.remove(newtmpfile) - deleteTmpTestFile() - - - - - def helper(self, src, classsrc, line, col): - try: - createPackageStructure(src,classsrc) - filename = pkgstructureFile2 - refs = [x for x in findReferences(filename,line,col)] - finally: - removePackageStructure() - return refs - - - - -testClass = trimLines(""" -class TheClass: - def theMethod(self): - pass - def differentMethod(self): - pass - -class DifferentClass: - def theMethod(self): - pass -""") - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_getPackageDependencies.py --- a/vim/sadness/bike/bike/query/test_getPackageDependencies.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * - -class TestGetPackageDependencies(BRMTestCase): - def test_foo(self): - assert 0 diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_getReferencesToClass.py --- a/vim/sadness/bike/bike/query/test_getReferencesToClass.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,280 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * -from bike.query.findReferences import findReferences -from bike.parsing.fastparserast import Module - -class TestGetReferencesToClass(BRMTestCase): - def test_returnsEmptyListIfNoReferences(self): - src = trimLines(""" - class MyClass: - pass - a = TheClass() - """) - root = createSourceNodeAt(src,"mymodule") - refs = [x for x in findReferences(os.path.abspath("mymodule.py"),1,6)] - self.assertEqual(refs,[]) - - def test_findsSimpleReferenceInSameModule(self): - src = trimLines(""" - class TheClass: - pass - a = TheClass() - """) - root = createSourceNodeAt(src,"mymodule") - refs = [x for x in findReferences(os.path.abspath("mymodule.py"),1,6)] - self.assertEqual(refs[0].filename,os.path.abspath("mymodule.py")) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,4) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferencesInModuleWhichImportsClass(self): - src = trimLines(""" - import b.bah - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - refs = [x for x in findReferences(os.path.abspath("a/b/bah.py"),1,6)] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,14) - self.assertEqual(refs[0].confidence,100) - - - def test_findsReferenceInModuleWhichImportsClassWithFrom(self): - src = trimLines(""" - from b.bah import TheClass - def foo(): - a = TheClass() - a.theMethod() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,18) - self.assertEqual(refs[0].confidence,100) - - self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a/foo.py"))) - self.assertEqual(refs[1].lineno,3) - self.assertEqual(refs[1].colno,8) - self.assertEqual(refs[1].confidence,100) - - def test_findsReferenceToClassImportedInSameClassScope(self): - src=trimLines(""" - class AnotherClass: - from b.bah import TheClass - TheClass.baz = 0 - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - assert refs != [] - - def test_findsReferenceInModuleWhichImportsClassWithFromAndAlias(self): - src = trimLines(""" - from b.bah import TheClass as MyTheClass - def foo(): - a = MyTheClass() - a.theMethod() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,18) - self.assertEqual(refs[0].confidence,100) - - - def test_findsReferenceInModuleWhichImportsClassWithImportAs(self): - src = trimLines(""" - from b.bah import TheClass as MyTheClass - def foo(): - a = MyTheClass() - a.theMethod() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,18) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferenceInModuleWhichImportsClassWithFromImportStar(self): - src = trimLines(""" - from b.bah import * - a = TheClass() - a.theMethod() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,4) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferenceInModuleWhichImportsClassWithFromImportStar2(self): - src = trimLines(""" - from a.b.bah import * - a = TheClass() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,4) - self.assertEqual(refs[0].confidence,100) - - - def test_findsClassReferenceInInstanceCreation(self): - src = trimLines(""" - class TheClass: - def theMethod(self): pass - TheClass().theMethod() - """) - root = createSourceNodeAt(src, "a.foo") - filename = os.path.abspath("a/foo.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,0) - self.assertEqual(refs[0].confidence,100) - - - def test_findsClassReferenceInInstanceCreationWithFQN(self): - src = trimLines(""" - import b.bah - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,14) - self.assertEqual(refs[0].confidence,100) - - def test_doesntfindReferenceInModuleWhichDoesntImportClass(self): - src = trimLines(""" - a = TheClass() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - assert refs == [] - - def test_findsReferenceInClassBases(self): - src =trimLines(""" - from b.bah import TheClass - class DerivedClass(TheClass): - pass - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[1].lineno,2) - self.assertEqual(refs[1].colno,19) - self.assertEqual(refs[1].confidence,100) - - - - def test_findsReferenceInMultiLineImportStatement(self): - src =trimLines(""" - from b.bah import foo, \\ - TheFooBah, TheClass, Foobah, SomethingElse - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,21) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferenceWhenModulenameSameAsClassMethodName(self): - # asserts that brm doesnt search class scope after not finding name - # in method scope (since class scope is invisible unless called on 'self' - src =trimLines(""" - from a.b import bah - class baz: - def bah(self): - print bah.TheClass - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,4) - self.assertEqual(refs[0].colno,18) - self.assertEqual(refs[0].confidence,100) - - - def test_doesntBarfOnFromImportStarWhenNameIsInFromClause(self): - src = trimLines(""" - from a.b.bah import TheClass - a = TheClass() - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(ClassTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,1,6)] - - -ClassTestdata = trimLines(""" -class TheClass: - def theMethod(self): - pass - def differentMethod(self): - pass - -class DifferentClass: - def theMethod(self): - pass -""") - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_getReferencesToMethod.py --- a/vim/sadness/bike/bike/query/test_getReferencesToMethod.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * -from bike.query.findReferences import findReferences -from bike.parsing.fastparserast import Module - -class TestGetReferencesToMethod(BRMTestCase): - - def test_getsReferenceOfSimpleMethodCall(self): - src = trimLines(""" - from b.bah import TheClass - a = TheClass() - a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(MethodTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - self.assertEqual(refs[0].filename, - os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,2) - self.assertEqual(refs[0].colno,2) - - def test_getsReferenceOfMethodCallFromClassImportedWithAlias(self): - src = trimLines(""" - from b.bah import TheClass as MyTheClass - - def foo(): - a = MyTheClass() - a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(MethodTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - self.assertEqual(refs[0].filename, - os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,5) - self.assertEqual(refs[0].colno,6) - - - def test_getsReferenceOfMethodCallWhenInstanceReturnedByFunction(self): - src = trimLines(""" - from b.bah import TheClass - - def foo(): - return TheClass() - a = foo() - a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(MethodTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - self.assertEqual(refs[0].filename, - os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,6) - self.assertEqual(refs[0].colno,2) - - def test_getsReferenceOfMethodCallInSameClass(self): - src = trimLines(""" - class TheClass: - def theMethod(self): - pass - def anotherMethod(self): - self.theMethod() - """) - - root = createSourceNodeAt(src,"a.foo") - filename = os.path.abspath("a/foo.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - self.assertEqual(refs[0].filename, - os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,5) - self.assertEqual(refs[0].colno,13) - - def test_getsReferenceOfMethodOnBaseClassInstance(self): - src = trimLines(""" - class root: - def theMethod(): - pass - - class a(root): - def theMethod(): - pass - - class b(root): - pass - - class TheClass(b): - def theMethod(self): - pass - - rootinstance = root() - rootinstance.theMethod() - """) - - refs =self.helper4(src,"pass",2,8) - self.assertEqual(refs[2].filename,pkgstructureFile1) - self.assertEqual(refs[2].lineno,17) - self.assertEqual(refs[2].colno,13) - - def helper4(self, src, importedsrc, line, col): - try: - createPackageStructure(src,importedsrc) - filename = pkgstructureFile1 - refs = [x for x in findReferences(filename,line,col) - if x.confidence == 100] - finally: - removePackageStructure() - return refs - - def test_doesntGetReferenceToMethodWhenObjectCreatedInChildScopeToMethodReference(self): - src = trimLines(""" - from b.bah import TheClass - a = AnotherClass() - def foo(): - a = TheClass() - a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(MethodTestdata, "a.b.bah") - filename = os.path.abspath("a/b/bah.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - assert len(refs) == 0 - - def test_renamesMethodReferenceOfInstanceCreatedInSubsequentFunction(self): - src = trimLines(""" - class TheClass: - def theMethod(): - pass - class NotTheClass: - def theMethod(): - pass - - def foo(): - a = bah() - a.theMethod() - - def bah(): - return TheClass() - """) - root = createSourceNodeAt(src,"a.foo") - filename = os.path.abspath("a/foo.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - self.assertEqual(refs[0].filename, - os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,10) - self.assertEqual(refs[0].colno,6) - - - def test_getsReferenceInMiddleOfBiggerCompoundCall(self): - src = trimLines(""" - class TheClass: - def theMethod(self): return AnotherClass() - TheClass().theMethod().anotherMethod() - """) - - root = createSourceNodeAt(src,"a.foo") - filename = os.path.abspath("a/foo.py") - refs = [x for x in findReferences(filename,2,8) - if x.confidence == 100] - self.assertEqual(refs[0].filename, - os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,3) - self.assertEqual(refs[0].colno,11) - self.assertEqual(refs[0].colend,20) - - -MethodTestdata = trimLines(""" -class TheClass: - def theMethod(self): - pass - def differentMethod(self): - pass - -class DifferentClass: - def theMethod(self): - pass -""") - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_getReferencesToModule.py --- a/vim/sadness/bike/bike/query/test_getReferencesToModule.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * -from bike.query.getReferencesToModule import * -from bike.parsing.fastparserast import Module - -class TestGetReferencesToModule(BRMTestCase): - - def test_returnsEmptyListIfNoReferences(self): - src = trimLines(""" - class MyClass: - pass - a = TheClass() - """) - root = createSourceNodeAt(src,"mymodule") - self.assertEqual([x for x in getReferencesToModule(root,"myothermodule")],[]) - - def test_findsReferencesInModuleWhichImportsModule(self): - src = trimLines(""" - import b.bah - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,9) - self.assertEqual(refs[0].confidence,100) - - self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[1].lineno,3) - self.assertEqual(refs[1].colno,10) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferenceInModuleWhichImportsModuleWithFrom(self): - src = trimLines(""" - from b import bah - def foo(): - a = bah.TheClass() - a.theMethod() - """) - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,14) - self.assertEqual(refs[0].confidence,100) - - self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a/foo.py"))) - self.assertEqual(refs[1].lineno,3) - self.assertEqual(refs[1].colno,8) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferenceInModuleWhichImportsModuleWithFromAndAlias(self): - src = trimLines(""" - from b import bah as mymodule - def foo(): - a = mymodule.MyTheClass() - a.theMethod() - """) - - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,14) - self.assertEqual(refs[0].confidence,100) - - """ # mymodule.MyTheClass - self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[1].lineno,3) - self.assertEqual(refs[1].colno,10) - self.assertEqual(refs[1].confidence,100) - """ - - def test_findsReferenceInModuleWhichImportsModuleWithFromImportStar(self): - src = trimLines(""" - from b.bah import * - a = TheClass() - a.theMethod() - """) - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,7) - self.assertEqual(refs[0].confidence,100) - - ''' Dont think this is a valid test, since cant import a module with - from package import * - def test_findsReferenceInModuleWhichImportsClassWithFromImportStar2(self): - src = trimLines(""" - from a.b import * - a = bah.TheClass() - """) - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,4) - self.assertEqual(refs[0].confidence,100) - ''' - - def test_findsReferenceInClassBases(self): - src =trimLines(""" - from b import bah - class DerivedClass(bah.TheClass): - pass - """) - - root = createSourceNodeAt(src, "a.foo") - root = createSourceNodeAt(testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - self.assertEqual(refs[1].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[1].lineno,2) - self.assertEqual(refs[1].colno,19) - self.assertEqual(refs[1].confidence,100) - - def test_findsReferenceInMultiLineImportStatement(self): - src =trimLines(""" - from b import foo, \\ - TheFooBah, TheClass, TheBastard, SomethingElse, bah - """) - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,2) - self.assertEqual(refs[0].colno,58) - self.assertEqual(refs[0].confidence,100) - - def test_findsReferenceWhenModulenameSameAsClassMethodName(self): - # asserts that brm doesnt search class scope after not finding name - # in method scope (since class scope is invisible unless called on 'self' - src =trimLines(""" - from a.b import bah - class baz: - def bah(self): - print bah.TheClass - """) - - root = createSourceNodeAt( src, "a.foo") - root = createSourceNodeAt( testdata.TheClass, "a.b.bah") - refs = [x for x in getReferencesToModule(root,"a.b.bah")] - - self.assertEqual(refs[0].filename,os.path.abspath(os.path.join("a","foo.py"))) - self.assertEqual(refs[0].lineno,1) - self.assertEqual(refs[0].colno,16) - self.assertEqual(refs[0].confidence,100) - - assert (len(refs))==2 - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_getTypeOf.py --- a/vim/sadness/bike/bike/query/test_getTypeOf.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * -from bike.query.getTypeOf import getTypeOf, UnfoundType,\ - attemptToConvertGetattrToFqn -from bike.parsing.fastparserast import Class, Function, Instance -from bike.parsing.newstuff import getModuleOrPackageUsingFQN -from compiler.ast import Getattr,CallFunc,Name - -class TestGetTypeOf(BRMTestCase): - def test_getsTypeOfSimpleClassInstanceReference(self): - src = trimLines(""" - from b.bah import TheClass - a = TheClass() - a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(testdata.TheClass, "a.b.bah") - module = getModuleOrPackageUsingFQN("a.foo") - res = getTypeOf(module,"a") - assert isinstance(res,Instance) - assert isinstance(res.getType(),Class) - assert res.getType().name == "TheClass" - - def test_getsTypeOfImportedClassReference(self): - src = trimLines(""" - import b.bah - a = b.bah.TheClass() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(testdata.TheClass, "a.b.bah") - module = getModuleOrPackageUsingFQN("a.foo") - res = getTypeOf(module,"a") - assert isinstance(res,Instance) - assert isinstance(res.getType(),Class) - assert res.getType().name == "TheClass" - - def test_getsTypeOfClassReferenceFromImportedPackage(self): - src = trimLines(""" - import b - a = b.bah.TheClass() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(testdata.TheClass, "a.b.bah") - module = getModuleOrPackageUsingFQN("a.foo") - res = getTypeOf(module,"a") - assert isinstance(res,Instance) - assert isinstance(res.getType(),Class) - assert res.getType().name == "TheClass" - - def test_getsTypeOfInstanceThatIsAnAttributeOfSelf(self): - src = trimLines(""" - class TheClass: - def theMethod(self): - pass - - class AnotherClass: - def __init__(self): - self.a = TheClass() - def anotherFn(self): - self.a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - module = getModuleOrPackageUsingFQN('a.foo') - theclass = getTypeOf(module,"TheClass") - fn = getTypeOf(module,"AnotherClass.anotherFn") - self.assertEqual(getTypeOf(fn,"self.a").getType().name, "TheClass") - #self.assertEqual(getTypeOf(fn,"self.a").getType(), theclass) - - - - def test_doesntGetTypeDefinedInChildFunction(self): - src = trimLines(""" - from b.bah import TheClass - a = AnotherClass() - def foo(): - a = TheClass() - a.theMethod() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(testdata.TheClass, "a.b.bah") - - themodule = getModuleOrPackageUsingFQN("a.foo") - assert isinstance(getTypeOf(themodule,"a"),UnfoundType) - - - def test_getsTypeOfClassReferencedViaAlias(self): - src = trimLines(""" - from b.bah import TheClass as FooBah - FooBah() - """) - root = createSourceNodeAt(src,"a.foo") - root = createSourceNodeAt(testdata.TheClass, "a.b.bah") - themodule = getModuleOrPackageUsingFQN("a.foo") - self.assertEqual(getTypeOf(themodule,"FooBah").name,"TheClass") - self.assertEqual(getTypeOf(themodule,"FooBah").filename, - os.path.abspath(os.path.join("a","b","bah.py"))) - - - def test_getsTypeOfClassImportedFromPackageScope(self): - initfile = trimLines(""" - from bah import TheClass - """) - src = trimLines(""" - from a import b - b.TheClass() - """) - createSourceNodeAt(src,"a.foo") - createSourceNodeAt(testdata.TheClass, "a.b.bah") - createSourceNodeAt(initfile,"a.b.__init__") - themodule = getModuleOrPackageUsingFQN("a.foo") - self.assertEqual(getTypeOf(themodule,"b.TheClass").name,"TheClass") - self.assertEqual(getTypeOf(themodule,"b.TheClass").filename, - os.path.abspath(os.path.join("a","b","bah.py"))) - - - def test_attemptToConvertGetattrToFqn_returnsNoneIfFails(self): - ast = Getattr(CallFunc(Name("foo"),[],[],[]),"hello") - assert attemptToConvertGetattrToFqn(ast) is None - - def test_attemptToConvertGetattrToFqn_works(self): - ast = Getattr(Getattr(Name("foo"),"bah"),"hello") - assert attemptToConvertGetattrToFqn(ast) == "foo.bah.hello" - - - def test_handlesRecursionProblem(self): - src = trimLines(""" - def fn(root): - node = root - node = node.getPackage('something') - """) - root = createSourceNodeAt(src,"a.foo") - m = getModuleOrPackageUsingFQN("a.foo") - fn = getTypeOf(m,"fn") - getTypeOf(fn,"node") # stack overflow! - - - def test_doesntGotIntoRecursiveLoopWhenEvaluatingARecursiveFunction(self): - src = trimLines(""" - def fn(v): - if v < 45: - return fn(root+1) - val = fn(3) - """) - root = createSourceNodeAt(src,"a.foo") - mod = getModuleOrPackageUsingFQN("a.foo") - getTypeOf(mod,"val") # stack overflow! - - def test_getsModuleImportedWithFrom(self): - importsrc=trimLines(""" - from a.b import bah - """) - src=trimLines(""" - mytext = 'hello' - """) - type = self.helper(importsrc,src,'bah') - self.assertEqual(pkgstructureFile2,type.filename) - - def helper(self,importsrc,src,name): - try: - createPackageStructure(importsrc,src) - from bike.parsing.newstuff import getModule - scope = getModule(pkgstructureFile1) - return getTypeOf(scope,name) - finally: - removePackageStructure() - - - def test_getsTypeOfClassImportedAsAlias(self): - importsrc = trimLines(""" - from b.bah import TheClass as MyTheClass - - def foo(): - a = MyTheClass() - a.theMethod() - """) - src=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - type = self.helper(importsrc,src,'MyTheClass') - self.assertEqual("TheClass",type.name) - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/test_relationships.py --- a/vim/sadness/bike/bike/query/test_relationships.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -import os -from bike import testdata -from bike.testutils import * -from bike.query.getTypeOf import getTypeOf -from bike.parsing.fastparserast import Module -from bike.query.relationships import getRootClassesOfHierarchy -from bike.parsing.newstuff import getModule - - -class TestGetRootClassesOfHierarchy(BRMTestCase): - def test_getsRootClassFromDerivedClass(self): - src = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass(BaseClass): - pass - - """) - rootclasses = self.helper(src,"DerivedClass") - self.assertEqual("TheClass",rootclasses[0].name) - self.assertEqual(len(rootclasses),1) - - def test_getsRootClassFromDerivedDerivedClass(self): - src = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass(BaseClass): - pass - class DerivedDerivedClass(DerivedClass): - pass - """) - rootclasses = self.helper(src,"DerivedDerivedClass") - self.assertEqual("TheClass",rootclasses[0].name) - self.assertEqual(len(rootclasses),1) - - - def test_getsRootClassFromDiamondOfClasses(self): - src = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass(BaseClass): - pass - class DerivedDerivedClass(DerivedClass,BaseClass): - pass - """) - rootclasses = self.helper(src,"DerivedDerivedClass") - self.assertEqual("TheClass",rootclasses[0].name) - self.assertEqual("TheClass",rootclasses[1].name) - self.assertEqual(len(rootclasses),2) - - - def test_getsRootClassesFromMultipleInheritance(self): - src = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass: - pass - class DerivedDerivedClass(DerivedClass,BaseClass): - pass - """) - rootclasses = self.helper(src,"DerivedDerivedClass") - self.assertEqual("DerivedClass",rootclasses[0].name) - self.assertEqual("TheClass",rootclasses[1].name) - self.assertEqual(len(rootclasses),2) - - def test_getsRootClassesFromMultipleInheritanceWithNewStyleClass(self): - src = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass(Object): - pass - class DerivedDerivedClass(DerivedClass,BaseClass): - pass - """) - rootclasses = self.helper(src,"DerivedDerivedClass") - self.assertEqual("DerivedClass",rootclasses[0].name) - self.assertEqual("TheClass",rootclasses[1].name) - self.assertEqual(len(rootclasses),2) - - - def helper(self,src,classname): - try: - createPackageStructure(src,testdata.TheClass) - classobj = getTypeOf(getModule(pkgstructureFile1),classname) - return getRootClassesOfHierarchy(classobj) - finally: - removePackageStructure() - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/query/testall.py --- a/vim/sadness/bike/bike/query/testall.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -#!/usr/bin/env python - -import setpath - -from test_common import * -from test_getReferencesToClass import * -from test_getReferencesToMethod import * -#from test_getReferencesToModule import * -from test_findDefinition import * -from test_findReferences import * -from test_relationships import * -from test_getTypeOf import * - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/__init__.py --- a/vim/sadness/bike/bike/refactor/__init__.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/extractMethod.py --- a/vim/sadness/bike/bike/refactor/extractMethod.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,363 +0,0 @@ -import re -import compiler -from bike.parsing import visitor -from bike.query.common import getScopeForLine -from bike.parsing.parserutils import generateLogicalLines, \ - makeLineParseable, maskStringsAndRemoveComments -from parser import ParserError -from bike.parsing.fastparserast import Class -from bike.transformer.undo import getUndoStack -from bike.refactor.utils import getTabWidthOfLine, getLineSeperator, \ - reverseCoordsIfWrongWayRound -from bike.transformer.save import queueFileToSave -from bike.parsing.load import getSourceNode -TABSIZE = 4 - -class coords: - def __init__(self, line, column): - self.column = column - self.line = line - def __str__(self): - return "("+str(self.column)+","+str(self.line)+")" - -commentRE = re.compile(r"#.*?$") - -class ParserException(Exception): pass - -def extractMethod(filename, startcoords, endcoords, newname): - ExtractMethod(getSourceNode(filename), - startcoords, endcoords, newname).execute() - -class ExtractMethod(object): - def __init__(self,sourcenode, startcoords, endcoords, newname): - self.sourcenode = sourcenode - - startcoords, endcoords = \ - reverseCoordsIfWrongWayRound(startcoords,endcoords) - - self.startline = startcoords.line - self.endline = endcoords.line - self.startcol = startcoords.column - self.endcol= endcoords.column - - self.newfn = NewFunction(newname) - - self.getLineSeperator() - self.adjustStartColumnIfLessThanTabwidth() - self.adjustEndColumnIfStartsANewLine() - self.fn = self.getFunctionObject() - self.getRegionToBuffer() - #print "-"*80 - #print self.extractedLines - #print "-"*80 - self.deduceIfIsMethodOrFunction() - - def execute(self): - self.deduceArguments() - getUndoStack().addSource(self.sourcenode.filename, - self.sourcenode.getSource()) - srclines = self.sourcenode.getLines() - newFnInsertPosition = self.fn.getEndLine()-1 - self.insertNewFunctionIntoSrcLines(srclines, self.newfn, - newFnInsertPosition) - self.writeCallToNewFunction(srclines) - - src = "".join(srclines) - queueFileToSave(self.sourcenode.filename,src) - - def getLineSeperator(self): - line = self.sourcenode.getLines()[self.startline-1] - linesep = getLineSeperator(line) - self.linesep = linesep - - def adjustStartColumnIfLessThanTabwidth(self): - tabwidth = getTabWidthOfLine(self.sourcenode.getLines()[self.startline-1]) - if self.startcol < tabwidth: self.startcol = tabwidth - - def adjustEndColumnIfStartsANewLine(self): - if self.endcol == 0: - self.endline -=1 - nlSize = len(self.linesep) - self.endcol = len(self.sourcenode.getLines()[self.endline-1])-nlSize - - - def getFunctionObject(self): - return getScopeForLine(self.sourcenode,self.startline) - - - def getTabwidthOfParentFunction(self): - line = self.sourcenode.getLines()[self.fn.getStartLine()-1] - match = re.match("\s+",line) - if match is None: - return 0 - else: - return match.end(0) - - # should be in the transformer module - def insertNewFunctionIntoSrcLines(self,srclines,newfn,insertpos): - tabwidth = self.getTabwidthOfParentFunction() - - while re.match("\s*"+self.linesep,srclines[insertpos-1]): - insertpos -= 1 - - srclines.insert(insertpos, self.linesep) - insertpos +=1 - - fndefn = "def "+newfn.name+"(" - - if self.isAMethod: - fndefn += "self" - if newfn.args != []: - fndefn += ", "+", ".join(newfn.args) - else: - fndefn += ", ".join(newfn.args) - - fndefn += "):"+self.linesep - - - srclines.insert(insertpos,tabwidth*" "+fndefn) - insertpos +=1 - - tabwidth += TABSIZE - - - if self.extractedCodeIsAnExpression(srclines): - assert len(self.extractedLines) == 1 - - fnbody = [tabwidth*" "+ "return "+self.extractedLines[0]] - - - else: - fnbody = [tabwidth*" "+line for line in self.extractedLines] - if newfn.retvals != []: - fnbody.append(tabwidth*" "+"return "+ - ", ".join(newfn.retvals) + self.linesep) - - for line in fnbody: - srclines.insert(insertpos,line) - insertpos +=1 - - - def writeCallToNewFunction(self, srclines): - startline = self.startline - endline = self.endline - startcol = self.startcol - endcol= self.endcol - - fncall = self.constructFunctionCallString(self.newfn.name, self.newfn.args, - self.newfn.retvals) - - self.replaceCodeWithFunctionCall(srclines, fncall, - startline, endline, startcol, endcol) - - - def replaceCodeWithFunctionCall(self, srclines, fncall, - startline, endline, startcol, endcol): - if startline == endline: # i.e. extracted code part of existing line - line = srclines[startline-1] - srclines[startline-1] = self.replaceSectionOfLineWithFunctionCall(line, - startcol, endcol, fncall) - else: - self.replaceLinesWithFunctionCall(srclines, startline, endline, fncall) - - - def replaceLinesWithFunctionCall(self, srclines, startline, endline, fncall): - tabwidth = getTabWidthOfLine(srclines[startline-1]) - line = tabwidth*" " + fncall + self.linesep - srclines[startline-1:endline] = [line] - - - - def replaceSectionOfLineWithFunctionCall(self, line, startcol, endcol, fncall): - line = line[:startcol] + fncall + line[endcol:] - if not line.endswith(self.linesep): - line+=self.linesep - return line - - - - def constructFunctionCallString(self, fnname, fnargs, retvals): - fncall = fnname + "("+", ".join(fnargs)+")" - if self.isAMethod: - fncall = "self." + fncall - - if retvals != []: - fncall = ", ".join(retvals) + " = "+fncall - return fncall - - - def deduceArguments(self): - lines = self.fn.getLinesNotIncludingThoseBelongingToChildScopes() - - # strip off comments - lines = [commentRE.sub(self.linesep,line) for line in lines] - extractedLines = maskStringsAndRemoveComments("".join(self.extractedLines)).splitlines(1) - - linesbefore = lines[:(self.startline - self.fn.getStartLine())] - linesafter = lines[(self.endline - self.fn.getStartLine()) + 1:] - - # split into logical lines - linesbefore = [line for line in generateLogicalLines(linesbefore)] - extractedLines = [line for line in generateLogicalLines(extractedLines)] - linesafter = [line for line in generateLogicalLines(linesafter)] - - if self.startline == self.endline: - # need to include the line code is extracted from - line = generateLogicalLines(lines[self.startline - self.fn.getStartLine():]).next() - linesbefore.append(line[:self.startcol] + "dummyFn()" + line[self.endcol:]) - assigns = getAssignments(linesbefore) - fnargs = getFunctionArgs(linesbefore) - candidateArgs = assigns + fnargs - refs = getVariableReferencesInLines(extractedLines) - self.newfn.args = [ref for ref in refs if ref in candidateArgs] - - assignsInExtractedBlock = getAssignments(extractedLines) - usesAfterNewFunctionCall = getVariableReferencesInLines(linesafter) - usesInPreceedingLoop = getVariableReferencesInLines( - self.getPreceedingLinesInLoop(linesbefore,line)) - self.newfn.retvals = [ref for ref in usesInPreceedingLoop+usesAfterNewFunctionCall - if ref in assignsInExtractedBlock] - - def getPreceedingLinesInLoop(self,linesbefore,firstLineToExtract): - if linesbefore == []: return [] - tabwidth = getTabWidthOfLine(firstLineToExtract) - rootTabwidth = getTabWidthOfLine(linesbefore[0]) - llines = [line for line in generateLogicalLines(linesbefore)] - startpos = len(llines)-1 - loopTabwidth = tabwidth - for idx in range(startpos,0,-1): - line = llines[idx] - if re.match("(\s+)for",line) is not None or \ - re.match("(\s+)while",line) is not None: - candidateLoopTabwidth = getTabWidthOfLine(line) - if candidateLoopTabwidth < loopTabwidth: - startpos = idx - return llines[startpos:] - - - - - - - def getRegionToBuffer(self): - startline = self.startline - endline = self.endline - startcol = self.startcol - endcol= self.endcol - - - self.extractedLines = self.sourcenode.getLines()[startline-1:endline] - - match = re.match("\s*",self.extractedLines[0]) - tabwidth = match.end(0) - - self.extractedLines = [line[startcol:] for line in self.extractedLines] - - # above cropping can take a blank line's newline off. - # this puts it back - for idx in range(len(self.extractedLines)): - if self.extractedLines[idx] == '': - self.extractedLines[idx] = self.linesep - - if startline == endline: - # need to crop the end - # (n.b. if region is multiple lines, then whole lines are taken) - self.extractedLines[-1] = self.extractedLines[-1][:endcol-startcol] - - if self.extractedLines[-1][-1] != '\n': - self.extractedLines[-1] += self.linesep - - def extractedCodeIsAnExpression(self,lines): - if len(self.extractedLines) == 1: - charsBeforeSelection = lines[self.startline-1][:self.startcol] - if re.match("^\s*$",charsBeforeSelection) is not None: - return 0 - if re.search(":\s*$",charsBeforeSelection) is not None: - return 0 - return 1 - return 0 - - def deduceIfIsMethodOrFunction(self): - if isinstance(self.fn.getParent(),Class): - self.isAMethod = 1 - else: - self.isAMethod = 0 - - -# holds information about the new function -class NewFunction: - def __init__(self,name): - self.name = name - - -# lines = list of lines. -# Have to have strings masked and comments removed -def getAssignments(lines): - class AssignVisitor: - def __init__(self): - self.assigns = [] - - def visitAssTuple(self, node): - for a in node.nodes: - if a.name not in self.assigns: - self.assigns.append(a.name) - - def visitAssName(self, node): - if node.name not in self.assigns: - self.assigns.append(node.name) - - def visitAugAssign(self, node): - if isinstance(node.node, compiler.ast.Name): - if node.node.name not in self.assigns: - self.assigns.append(node.node.name) - - assignfinder = AssignVisitor() - for line in lines: - doctoredline = makeLineParseable(line) - try: - ast = compiler.parse(doctoredline) - except ParserError: - raise ParserException("couldnt parse:"+doctoredline) - visitor.walk(ast, assignfinder) - return assignfinder.assigns - - -# lines = list of lines. -# Have to have strings masked and comments removed -def getFunctionArgs(lines): - if lines == []: return [] - - class FunctionVisitor: - def __init__(self): - self.result = [] - def visitFunction(self, node): - for n in node.argnames: - if n != "self": - self.result.append(n) - fndef = generateLogicalLines(lines).next() - doctoredline = makeLineParseable(fndef) - try: - ast = compiler.parse(doctoredline) - except ParserError: - raise ParserException("couldnt parse:"+doctoredline) - return visitor.walk(ast, FunctionVisitor()).result - - - -# lines = list of lines. Have to have strings masked and comments removed -def getVariableReferencesInLines(lines): - class NameVisitor: - def __init__(self): - self.result = [] - def visitName(self, node): - if node.name not in self.result: - self.result.append(node.name) - reffinder = NameVisitor() - for line in lines: - doctoredline = makeLineParseable(line) - try: - ast = compiler.parse(doctoredline) - except ParserError: - raise ParserException("couldnt parse:"+doctoredline) - visitor.walk(ast, reffinder) - return reffinder.result diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/extractVariable.py --- a/vim/sadness/bike/bike/refactor/extractVariable.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -from bike.parsing.parserutils import maskStringsAndRemoveComments -from bike.transformer.undo import getUndoStack -from parser import ParserError -import compiler -from bike.refactor.extractMethod import coords -from bike.refactor.utils import getTabWidthOfLine, getLineSeperator,\ - reverseCoordsIfWrongWayRound -from bike.transformer.save import queueFileToSave -from bike.parsing.load import getSourceNode - - -def extractLocalVariable(filename, startcoords, endcoords, varname): - sourceobj = getSourceNode(filename) - if startcoords.line != endcoords.line: - raise "Can't do multi-line extracts yet" - startcoords, endcoords = \ - reverseCoordsIfWrongWayRound(startcoords,endcoords) - line = sourceobj.getLine(startcoords.line) - tabwidth = getTabWidthOfLine(line) - linesep = getLineSeperator(line) - region = line[startcoords.column:endcoords.column] - - getUndoStack().addSource(sourceobj.filename,sourceobj.getSource()) - sourceobj.getLines()[startcoords.line-1] = \ - line[:startcoords.column] + varname + line[endcoords.column:] - - defnline = tabwidth*" " + varname + " = " + region + linesep - - sourceobj.getLines().insert(startcoords.line-1,defnline) - - queueFileToSave(sourceobj.filename,"".join(sourceobj.getLines())) - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/inlineVariable.py --- a/vim/sadness/bike/bike/refactor/inlineVariable.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -from bike.query.findDefinition import findAllPossibleDefinitionsByCoords -from bike.query.findReferences import findReferences -from bike.parsing.parserutils import maskStringsAndRemoveComments, linecontinueRE -from bike.transformer.undo import getUndoStack -from bike.transformer.save import queueFileToSave -from parser import ParserError -from bike.parsing.load import getSourceNode -import compiler -import re - - -def inlineLocalVariable(filename, lineno,col): - sourceobj = getSourceNode(filename) - return inlineLocalVariable_old(sourceobj, lineno,col) - -def inlineLocalVariable_old(sourcenode,lineno,col): - definition, region, regionlinecount = getLocalVariableInfo(sourcenode, lineno, col) - addUndo(sourcenode) - replaceReferences(sourcenode, findReferences(sourcenode.filename, definition.lineno, definition.colno), region) - delLines(sourcenode, definition.lineno-1, regionlinecount) - updateSource(sourcenode) - -def getLocalVariableInfo(sourcenode, lineno, col): - definition = findDefinition(sourcenode, lineno, col) - region, linecount = getRegionToInline(sourcenode, definition) - return definition, region, linecount - -def findDefinition(sourcenode, lineno, col): - definition = findAllPossibleDefinitionsByCoords(sourcenode.filename, - lineno,col).next() - assert definition.confidence == 100 - return definition - -def getRegionToInline(sourcenode, defn): - line, linecount = getLineAndContinues(sourcenode, defn.lineno) - start, end = findRegionToInline(maskStringsAndRemoveComments(line)) - return line[start:end], linecount - -def findRegionToInline(maskedline): - match = re.compile("[^=]+=\s*(.+)$\n", re.DOTALL).match(maskedline) - assert match - return match.start(1), match.end(1) - -# Possible refactoring: move to class of sourcenode -def getLineAndContinues(sourcenode, lineno): - line = sourcenode.getLine(lineno) - - linecount = 1 - while linecontinueRE.search(line): - line += sourcenode.getLine(lineno + linecount) - linecount += 1 - - return line, linecount - -def addUndo(sourcenode): - getUndoStack().addSource(sourcenode.filename,sourcenode.getSource()) - -def replaceReferences(sourcenode, references, replacement): - for reference in safeReplaceOrder( references ): - replaceReference(sourcenode, reference, replacement) - -def safeReplaceOrder( references ): - """ - When inlining a variable, if multiple instances occur on the line, then the - last reference must be replaced first. Otherwise the remaining intra-line - references will be incorrect. - """ - def safeReplaceOrderCmp(self, other): - return -cmp(self.colno, other.colno) - - result = list(references) - result.sort(safeReplaceOrderCmp) - return result - - -def replaceReference(sourcenode, ref, replacement): - """ sourcenode.getLines()[ref.lineno-1][ref.colno:ref.colend] = replacement - But strings don't support slice assignment as they are immutable. :( - """ - sourcenode.getLines()[ref.lineno-1] = \ - replaceSubStr(sourcenode.getLines()[ref.lineno-1], - ref.colno, ref.colend, replacement) - -def replaceSubStr(str, start, end, replacement): - return str[:start] + replacement + str[end:] - -# Possible refactoring: move to class of sourcenode -def delLines(sourcenode, lineno, linecount=1): - del sourcenode.getLines()[lineno:lineno+linecount] - -def updateSource(sourcenode): - queueFileToSave(sourcenode.filename,"".join(sourcenode.getLines())) - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/moveToModule.py --- a/vim/sadness/bike/bike/refactor/moveToModule.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -import bike.globals -from bike.parsing.load import getSourceNode -from bike.parsing.fastparserast import Module -from bike.query.common import getScopeForLine, convertNodeToMatchObject -from bike.transformer.save import queueFileToSave, save -from bike.transformer.undo import getUndoStack -from bike.refactor.extractMethod import getVariableReferencesInLines -from bike.refactor.utils import getLineSeperator -from bike.query.findDefinition import findDefinitionFromASTNode -from bike.query.findReferences import findReferences -from bike.parsing.pathutils import filenameToModulePath -from compiler.ast import Name -import re - -def moveClassToNewModule(origfile,line,newfile): - srcnode = getSourceNode(origfile) - targetsrcnode = getSourceNode(newfile) - classnode = getScopeForLine(srcnode,line) - classlines = srcnode.getLines()[classnode.getStartLine()-1: - classnode.getEndLine()-1] - getUndoStack().addSource(srcnode.filename, - srcnode.getSource()) - getUndoStack().addSource(targetsrcnode.filename, - targetsrcnode.getSource()) - - srcnode.getLines()[classnode.getStartLine()-1: - classnode.getEndLine()-1] = [] - - targetsrcnode.getLines().extend(classlines) - - queueFileToSave(srcnode.filename,srcnode.getSource()) - queueFileToSave(targetsrcnode.filename,targetsrcnode.getSource()) - - -exactFromRE = "(from\s+\S+\s+import\s+%s)(.*)" -fromRE = "from\s+\S+\s+import\s+(.*)" - -def moveFunctionToNewModule(origfile,line,newfile): - - srcnode = getSourceNode(origfile) - targetsrcnode = getSourceNode(newfile) - scope = getScopeForLine(srcnode,line) - - linesep = getLineSeperator(srcnode.getLines()[0]) - - matches =[m for m in findReferences(origfile, line, scope.getColumnOfName())] - - origFileImport = [] - fromline = 'from %s import %s'%(filenameToModulePath(newfile),scope.name) - - for match in matches: - if match.filename == origfile: - origFileImport = fromline + linesep - else: - s = getSourceNode(match.filename) - m = s.fastparseroot - if match.lineno in m.getImportLineNumbers(): - getUndoStack().addSource(s.filename, - s.getSource()) - - maskedline = m.getLogicalLine(match.lineno) - origline = s.getLines()[match.lineno-1] - reMatch = re.match(exactFromRE%(scope.name),maskedline) - if reMatch and not (',' in reMatch.group(2) or \ - '\\' in reMatch.group(2)): - # i.e. line is 'from module import foo' - - if match.filename == newfile: - #remove the import - s.getLines()[match.lineno-1:match.lineno] = [] - pass - else: - restOfOrigLine = origline[len(reMatch.group(1)):] - s.getLines()[match.lineno-1] = fromline + restOfOrigLine - - elif re.match(fromRE,maskedline): - # i.e. line is 'from module import foo,bah,baz' - #remove the element from the import stmt - line = removeNameFromMultipleImportLine(scope.name, origline) - s.getLines()[match.lineno-1] = line - #and add a new line - nextline = match.lineno + maskedline.count('\\') + 1 - s.getLines()[nextline-1:nextline-1] = [fromline+linesep] - - queueFileToSave(s.filename,s.getSource()) - - - refs = getVariableReferencesInLines(scope.getMaskedLines()) - - scopeLines = srcnode.getLines()[scope.getStartLine()-1: - scope.getEndLine()-1] - importModules = deduceImportsForNewFile(refs, scope) - importlines = composeNewFileImportLines(importModules, linesep) - - - - getUndoStack().addSource(srcnode.filename, - srcnode.getSource()) - getUndoStack().addSource(targetsrcnode.filename, - targetsrcnode.getSource()) - - srcnode.getLines()[scope.getStartLine()-1: - scope.getEndLine()-1] = origFileImport - - targetsrcnode.getLines().extend(importlines+scopeLines) - - queueFileToSave(srcnode.filename,srcnode.getSource()) - queueFileToSave(targetsrcnode.filename,targetsrcnode.getSource()) - -def removeNameFromMultipleImportLine(name, origline): - def replacefn(match): - return match.group(1) - line = re.sub('(\W)%s\s*?,'%(name),replacefn,origline) - return line - - - - -def composeNewFileImportLines(importModules, linesep): - importlines = [] - for mpath in importModules: - importlines += "from %s import %s"%(mpath, - ', '.join(importModules[mpath])) - importlines += linesep - return importlines - -def deduceImportsForNewFile(refs, scope): - importModules = {} - for ref in refs: - match = findDefinitionFromASTNode(scope,Name(ref)) - - if match.filename == scope.module.filename: - tgtscope = getScopeForLine(getSourceNode(match.filename), - match.lineno) - while tgtscope != scope and not isinstance(tgtscope,Module): - tgtscope = tgtscope.getParent() - - if not isinstance(tgtscope,Module): - continue # was defined in this function - - mpath = filenameToModulePath(match.filename) - if mpath in importModules: - importModules[mpath].append(ref) - else: - importModules[mpath] = [ref] - return importModules - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/rename.py --- a/vim/sadness/bike/bike/refactor/rename.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -from bike.transformer.WordRewriter import WordRewriter -from bike.query.findReferences import findReferencesIncludingDefn -from bike.transformer.save import save - -def rename(filename,lineno,col,newname,promptcallback=None): - strrewrite = WordRewriter() - for match in findReferencesIncludingDefn(filename,lineno,col): - #print "rename match ",match - if match.confidence == 100 or promptUser(promptcallback,match): - strrewrite.rewriteString(match.sourcenode, - match.lineno,match.colno,newname) - strrewrite.commit() - -def promptUser(promptCallback,match): - if promptCallback is not None and \ - promptCallback(match.filename, match.lineno, match.colno, match.colend): - return 1 - return 0 - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/setpath.py --- a/vim/sadness/bike/bike/refactor/setpath.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -import sys,os -if not os.path.abspath("../..") in sys.path: - from bike import log - print >> log.warning, "Appending to the system path. This should only happen in unit tests" - sys.path.append(os.path.abspath("../..")) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_extractMethod.py --- a/vim/sadness/bike/bike/refactor/test_extractMethod.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,791 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest - -from bike.refactor.extractMethod import ExtractMethod, \ - extractMethod, coords -from bike import testdata -from bike.testutils import * -from bike.parsing.load import Cache - -def assertTokensAreSame(t1begin, t1end, tokens): - it = t1begin.clone() - pos = 0 - while it != t1end: - assert it.deref() == tokens[pos] - it.incr() - pos+=1 - assert pos == len(tokens) - - -def helper(src,startcoords, endcoords, newname): - sourcenode = createAST(src) - extractMethod(tmpfile, startcoords, endcoords, newname) - return sourcenode.getSource() - -class TestExtractMethod(BRMTestCase): - - def test_extractsPass(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - pass - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - self.newMethod() - - def newMethod(self): - pass - """) - src = helper(srcBefore, coords(3, 8), coords(3, 12), "newMethod") - self.assertEqual(src,srcAfter) - - def test_extractsPassWhenFunctionAllOnOneLine(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): pass # comment - """) - - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): self.newMethod() # comment - - def newMethod(self): - pass - """) - src = helper(srcBefore, coords(2, 24), coords(2, 28),"newMethod") - self.assertEqual(src,srcAfter) - - def test_extractsPassFromForLoop(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): # comment - for i in foo: - pass - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): # comment - for i in foo: - self.newMethod() - - def newMethod(self): - pass - """) - src = helper(srcBefore, coords(4, 12), coords(4, 16), "newMethod") - self.assertEqual(srcAfter, src) - - def test_newMethodHasArgumentsForUsedTemporarys(self): - - srcBefore=trimLines(""" - class MyClass: - def myMethod(self, c): - a = something() - b = somethingelse() - print a + b + c + d - print \"hello\" - dosomethingelse(a, b) - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self, c): - a = something() - b = somethingelse() - self.newMethod(a, b, c) - dosomethingelse(a, b) - - def newMethod(self, a, b, c): - print a + b + c + d - print \"hello\" - """) - - src = helper(srcBefore, coords(5, 8), coords(6, 21), "newMethod") - self.assertEqual(srcAfter, src) - - def test_newMethodHasSingleArgument(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - a = something() - print a - print \"hello\" - dosomethingelse(a, b) - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - a = something() - self.newMethod(a) - dosomethingelse(a, b) - - def newMethod(self, a): - print a - print \"hello\" - """) - src = helper(srcBefore, coords(4, 8), coords(5, 21), "newMethod") - self.assertEqual(srcAfter, src) - - - def test_doesntHaveDuplicateArguments(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - a = 3 - print a - print a - """) - - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - a = 3 - self.newMethod(a) - - def newMethod(self, a): - print a - print a - """) - src = helper(srcBefore, coords(4, 0), coords(6, 0), "newMethod") - self.assertEqual(srcAfter, src) - - def test_extractsQueryWhenFunctionAllOnOneLine(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self, a): print a # comment - """) - - srcAfter=trimLines(""" - class MyClass: - def myMethod(self, a): self.newMethod(a) # comment - - def newMethod(self, a): - print a - """) - src = helper(srcBefore, coords(2, 27), coords(2, 34), "newMethod") - self.assertEqual(srcAfter, src) - - - def test_worksWhenAssignmentsToTuples(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - a, b, c = 35, 36, 37 - print a + b - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - a, b, c = 35, 36, 37 - self.newMethod(a, b) - - def newMethod(self, a, b): - print a + b - """) - - src = helper(srcBefore, coords(4, 8), coords(4, 19), "newMethod") - self.assertEqual(srcAfter, src) - - def test_worksWhenUserSelectsABlockButDoesntSelectTheHangingDedent(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): # comment - for i in foo: - pass - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): # comment - for i in foo: - self.newMethod() - - def newMethod(self): - pass - """) - - src = helper(srcBefore, coords(4, 8), coords(4, 16), "newMethod") - self.assertEqual(srcAfter, src) - - def test_newMethodHasSingleReturnValue(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - a = 35 # <-- extract me - print a - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - a = self.newMethod() - print a - - def newMethod(self): - a = 35 # <-- extract me - return a - """) - - src = helper(srcBefore, coords(3, 4), - coords(3, 34), "newMethod") - self.assertEqual(srcAfter, src) - - - - def test_newMethodHasMultipleReturnValues(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - a = 35 - b = 352 - print a + b - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - a, b = self.newMethod() - print a + b - - def newMethod(self): - a = 35 - b = 352 - return a, b - """) - src = helper(srcBefore, coords(3, 8), - coords(4, 15), "newMethod") - self.assertEqual(srcAfter, src) - - - - def test_worksWhenMovingCodeJustAfterDedent(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): # comment - for i in foo: - pass - print \"hello\" - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): # comment - for i in foo: - pass - self.newMethod() - - def newMethod(self): - print \"hello\" - """) - - src = helper(srcBefore, coords(5, 8), - coords(5, 21), "newMethod") - self.assertEqual(srcAfter, src) - - - def test_extractsPassWhenSelectionCoordsAreReversed(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - pass - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - self.newMethod() - - def newMethod(self): - pass - """) - src = helper(srcBefore, coords(3, 12), coords(3, 8), "newMethod") - self.assertEqual(srcAfter, src) - - - def test_extractsExpression(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): # comment - a = 32 - b = 2 + a * 1 + 2 - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): # comment - a = 32 - b = 2 + self.newMethod(a) + 2 - - def newMethod(self, a): - return a * 1 - """) - src = helper(srcBefore, coords(4, 16), coords(4, 21), "newMethod") - self.assertEqual(srcAfter, src) - - - def test_extractsExpression2(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): # comment - g = 32 - assert output.thingy(g) == \"bah\" - """) - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): # comment - g = 32 - assert self.newMethod(g) == \"bah\" - - def newMethod(self, g): - return output.thingy(g) - """) - src = helper(srcBefore, coords(4, 15), coords(4, 31), "newMethod") - self.assertEqual(srcAfter, src) - - - -class TestExtractFunction(BRMTestCase): - def runTarget(self, src, begincoords, endcoords, newname): - ast = createAST(src) - extractFunction(ast, begincoords, endcoords, newname) - return ast - - def test_extractsFunction(self): - srcBefore=trimLines(""" - def myFunction(): # comment - a = 3 - c = a + 99 - b = c * 1 - print b - """) - srcAfter=trimLines(""" - def myFunction(): # comment - a = 3 - b = newFunction(a) - print b - - def newFunction(a): - c = a + 99 - b = c * 1 - return b - """) - - src = helper(srcBefore, coords(3, 4), - coords(4, 13), "newFunction") - self.assertEqual(srcAfter, src) - - def test_extractsAssignToAttribute(self): - srcBefore=trimLines(""" - def simulateLoad(path): - item = foo() - item.decl = line - """) - srcAfter=trimLines(""" - def simulateLoad(path): - item = foo() - newFunction(item) - - def newFunction(item): - item.decl = line - """) - - src = helper(srcBefore, coords(3, 0), - coords(4, 0), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_extractsFromFirstBlockOfIfElseStatement(self): - srcBefore=trimLines(""" - def foo(): - if bah: - print \"hello1\" - print \"hello2\" - - elif foo: - pass - """) - srcAfter=trimLines(""" - def foo(): - if bah: - newFunction() - print \"hello2\" - - elif foo: - pass - - def newFunction(): - print \"hello1\" - """) - src = helper(srcBefore, coords(3, 0), - coords(4, 0), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_extractsAugAssign(self): - srcBefore=trimLines(""" - def foo(): - a = 3 - a += 1 - print a - """) - srcAfter=trimLines(""" - def foo(): - a = 3 - a = newFunction(a) - print a - - def newFunction(a): - a += 1 - return a - """) - src = helper(srcBefore, coords(3, 0), - coords(4, 0), "newFunction") - self.assertEqual(srcAfter, src) - - def test_extractsForLoopUsingLoopVariable(self): - srcBefore=trimLines(""" - def foo(): - for i in range(1, 3): - print i - """) - srcAfter=trimLines(""" - def foo(): - for i in range(1, 3): - newFunction(i) - - def newFunction(i): - print i - """) - - src = helper(srcBefore, coords(3, 0), - coords(4, 0), "newFunction") - self.assertEqual(srcAfter, src) - - def test_extractWhileLoopVariableIncrement(self): - srcBefore=trimLines(""" - def foo(): - a = 0 - while a != 3: - a = a+1 - """) - srcAfter=trimLines(""" - def foo(): - a = 0 - while a != 3: - a = newFunction(a) - - def newFunction(a): - a = a+1 - return a - """) - src = helper(srcBefore, coords(4, 0), - coords(5, 0), "newFunction") - self.assertEqual(srcAfter, src) - - def test_extractAssignedVariableUsedInOuterForLoop(self): - srcBefore=trimLines(""" - def foo(): - b = 0 - for a in range(1, 3): - b = b+1 - while b != 2: - print a - b += 1 - """) - srcAfter=trimLines(""" - def foo(): - b = 0 - for a in range(1, 3): - b = b+1 - while b != 2: - b = newFunction(a, b) - - def newFunction(a, b): - print a - b += 1 - return b - """) - - src = helper(srcBefore, coords(6, 0), - coords(8, 0), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_extractsConditionalFromExpression(self): - srcBefore=trimLines(""" - def foo(): - if 123+3: - print aoue - """) - srcAfter=trimLines(""" - def foo(): - if newFunction(): - print aoue - - def newFunction(): - return 123+3 - """) - src = helper(srcBefore, coords(2, 7), - coords(2, 12), "newFunction") - self.assertEqual(srcAfter, src) - - def test_extractCodeAfterCommentInMiddleOfFnDoesntRaiseParseException(self): - srcBefore=trimLines(""" - def theFunction(): - print 1 - # comment - print 2 - """) - srcAfter=trimLines(""" - def theFunction(): - print 1 - # comment - newFunction() - - def newFunction(): - print 2 - """) - src = helper(srcBefore, coords(4, 0), - coords(5, 0), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_canExtractQueryFromNestedIfStatement(self): - srcBefore=trimLines(""" - def theFunction(): - if foo: # comment - if bah: - pass - """) - srcAfter=trimLines(""" - def theFunction(): - if foo: # comment - if newFunction(): - pass - - def newFunction(): - return bah - """) - src = helper(srcBefore, coords(3, 11), - coords(3, 14), "newFunction") - self.assertEqual(srcAfter, src) - - - - def test_doesntMessUpTheNextFunctionOrClass(self): - srcBefore=trimLines(""" - def myFunction(): - a = 3 - print \"hello\"+a # extract me - - class MyClass: - def myMethod(self): - b = 12 # extract me - c = 3 # and me - d = 2 # and me - print b, c - """) - srcAfter=trimLines(""" - def myFunction(): - a = 3 - newFunction(a) - - def newFunction(a): - print \"hello\"+a # extract me - - class MyClass: - def myMethod(self): - b = 12 # extract me - c = 3 # and me - d = 2 # and me - print b, c - """) - - # extract code on one line - src = helper(srcBefore, coords(3, 4), - coords(3, 34), "newFunction") - self.assertEqual(srcAfter, src) - - # extract code on 2 lines (most common user method) - resetRoot() - Cache.instance.reset() - Root() - src = helper(srcBefore, coords(3, 0), - coords(4, 0), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_doesntBallsUpIndentWhenTheresALineWithNoSpacesInIt(self): - srcBefore=trimLines(""" - def theFunction(): - if 1: - pass - - pass - """) - srcAfter=trimLines(""" - def theFunction(): - newFunction() - - def newFunction(): - if 1: - pass - - pass - """) - src = helper(srcBefore, coords(2, 4), - coords(5, 8), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_doesntHaveToBeInsideAFunction(self): - srcBefore=trimLines(r""" - a = 1 - print a + 2 - f(b) - """) - srcAfter=trimLines(r""" - a = 1 - newFunction(a) - - def newFunction(a): - print a + 2 - f(b) - """) - src = helper(srcBefore, coords(2, 0), - coords(3, 4), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_doesntBarfWhenEncountersMethodCalledOnCreatedObj(self): - srcBefore=trimLines(r""" - results = QueryEngine(q).foo() - """) - srcAfter=trimLines(r""" - newFunction() - - def newFunction(): - results = QueryEngine(q).foo() - """) - src = helper(srcBefore, coords(1, 0), - coords(2, 0), "newFunction") - self.assertEqual(srcAfter, src) - - - def test_worksIfNoLinesBeforeExtractedCode(self): - srcBefore=trimLines(r""" - print a + 2 - f(b) - """) - srcAfter=trimLines(r""" - newFunction() - - def newFunction(): - print a + 2 - f(b) - """) - src = helper(srcBefore, coords(1, 0), - coords(2, 4), "newFunction") - self.assertEqual(srcAfter, src) - - -class TestGetRegionAsString(BRMTestCase): - def test_getsHighlightedSingleLinePassStatement(self): - src=trimLines(""" - class MyClass: - def myMethod(self): - pass - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(3, 8), - coords(3, 12), "foobah") - em.getRegionToBuffer() - self.assertEqual(len(em.extractedLines), 1) - self.assertEqual(em.extractedLines[0], "pass\n") - - def test_getsSingleLinePassStatementWhenWholeLineIsHighlighted(self): - src=trimLines(""" - class MyClass: - def myMethod(self): - pass - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(3, 0), - coords(3, 12), "foobah") - em.getRegionToBuffer() - self.assertEqual(len(em.extractedLines), 1) - self.assertEqual(em.extractedLines[0], "pass\n") - - - def test_getsMultiLineRegionWhenJustRegionIsHighlighted(self): - src=trimLines(""" - class MyClass: - def myMethod(self): - print 'hello' - pass - """) - region=trimLines(""" - print 'hello' - pass - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(3, 8), - coords(4, 12), "foobah") - em.getRegionToBuffer() - self.assertEqual(em.extractedLines, region.splitlines(1)) - - def test_getsMultiLineRegionWhenRegionLinesAreHighlighted(self): - src=trimLines(""" - class MyClass: - def myMethod(self): - print 'hello' - pass - - """) - region=trimLines(""" - print 'hello' - pass - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(3, 0), - coords(5, 0), "foobah") - em.getRegionToBuffer() - self.assertEqual(em.extractedLines, region.splitlines(1)) - - def test_getsHighlightedSubstringOfLine(self): - src=trimLines(""" - class MyClass: - def myMethod(self): - if a == 3: - pass - """) - region=trimLines(""" - a == 3 - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(3, 11), - coords(3, 17), "foobah") - em.getRegionToBuffer() - self.assertEqual(em.extractedLines, region.splitlines(1)) - - -class TestGetTabwidthOfParentFunction(BRMTestCase): - def test_getsTabwidthForSimpleMethod(self): - src=trimLines(""" - class MyClass: - def myMethod(self): - pass - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(3, 11), - coords(3, 17), "foobah") - self.assertEqual(em.getTabwidthOfParentFunction(), 4) - - def test_getsTabwidthForFunctionAtRootScope(self): - src=trimLines(""" - def myFn(self): - pass - """) - sourcenode = createAST(src) - em = ExtractMethod(sourcenode, coords(2, 0), - coords(2, 9), "foobah") - self.assertEqual(em.getTabwidthOfParentFunction(), 0) - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_extractVariable.py --- a/vim/sadness/bike/bike/refactor/test_extractVariable.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from bike.testutils import * -from bike.refactor.extractVariable import coords, extractLocalVariable - -class TestExtractLocalVariable(BRMTestCase): - def test_worksOnSimpleCase(self): - srcBefore=trimLines(""" - def foo(): - print 3 + 2 - """) - srcAfter=trimLines(""" - def foo(): - a = 3 + 2 - print a - """) - sourcenode = createAST(srcBefore) - extractLocalVariable(tmpfile,coords(2,10),coords(2,15),'a') - self.assertEqual(sourcenode.getSource(),srcAfter) - - def test_worksIfCoordsTheWrongWayRound(self): - srcBefore=trimLines(""" - def foo(): - print 3 + 2 - """) - srcAfter=trimLines(""" - def foo(): - a = 3 + 2 - print a - """) - sourcenode = createAST(srcBefore) - extractLocalVariable(tmpfile,coords(2,15),coords(2,10),'a') - self.assertEqual(sourcenode.getSource(),srcAfter) - - -if __name__ == "__main__": - unittest.main() - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_inlineVariable.py --- a/vim/sadness/bike/bike/refactor/test_inlineVariable.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from bike.testutils import trimLines,createAST, BRMTestCase -from inlineVariable import inlineLocalVariable_old - -class TestInlineLocalVariable(BRMTestCase): - - def test_worksWhenUserDoesItAgainstReference(self): - srcBefore=r""" - def foo(): - b = 'hello' - print b - """ - srcAfter=r""" - def foo(): - print 'hello' - """ - - self.helper( srcBefore, 3, 10, srcAfter ) - - def test_worksWhenInlinedCodeIsOverTwoLines(self): - srcBefore=r""" - def foo(): - b = 3 + \ - 2 - print b - """ - - srcAfter=r""" - def foo(): - print 3 + \ - 2 - """ - - self.helper(srcBefore, 2, 4, srcAfter) - - ''' Needs Adding Again - def test_addsBracketsWhenInlinedCodeHasPresidenceOverSurroundingCode(self): - srcBefore=trimLines(r""" - def foo(): - b = 3 + 2 - print 3 * b - """) - srcAfter=trimLines(r""" - def foo(): - print 3 * (3 + 2) - """) - assert 0 - ''' - - def test_worksWithMultipleInstancesOfVariableOnLine(self): - srcBefore=r""" - def foo(): - x = 11 - print x, x - """ - - srcAfter=r""" - def foo(): - print 11, 11 - """ - - self.helper(srcBefore, 2, 4, srcAfter) - - def test_worksWithMultipleMultilineCode(self): - srcBefore=r""" - def foo(): - b = 3 + \ - 2 - print b - print b - """ - - srcAfter=r""" - def foo(): - print 3 + \ - 2 - print 3 + \ - 2 - """ - - self.helper(srcBefore, 2, 4, srcAfter) - - ''' Can't do this without some hairy logic to deduce how to inline - the variables. E.g. how do you inline a,b = foo() ? - - def test_handlesTupleAssignment(self): - srcBefore=r""" - def foo(): - x, y = 1, 2 - print x - print y - """ - - srcAfter=r""" - def foo(): - y = 2 - print 1 - print y - """ - - self.helper(srcBefore, 2, 4, srcAfter) - ''' - - - def helper(self, srcBefore, y, x, srcAfter): - sourcenode = createAST(trimLines(srcBefore)) - inlineLocalVariable_old(sourcenode,y,x) - self.assertEqual(sourcenode.getSource(),trimLines(srcAfter)) - -if __name__ == "__main__": - unittest.main() - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_moveToModule.py --- a/vim/sadness/bike/bike/refactor/test_moveToModule.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,241 +0,0 @@ -#!/usr/bin/env python -import setpath -from bike.testutils import * -from bike.transformer.save import save - -from moveToModule import * - -class TestMoveClass(BRMTestCase): - def test_movesTheText(self): - src1=trimLines(""" - def before(): pass - class TheClass: - pass - def after(): pass - """) - src1after=trimLines(""" - def before(): pass - def after(): pass - """) - src2after=trimLines(""" - class TheClass: - pass - """) - - try: - createPackageStructure(src1, "") - moveClassToNewModule(pkgstructureFile1,2, - pkgstructureFile2) - save() - self.assertEqual(src1after,file(pkgstructureFile1).read()) - self.assertEqual(src2after,file(pkgstructureFile2).read()) - finally: - removePackageStructure() - -class TestMoveFunction(BRMTestCase): - def test_importsNameReference(self): - src1=trimLines(""" - a = 'hello' - def theFunction(self): - print a - """) - src2after=trimLines(""" - from a.foo import a - def theFunction(self): - print a - """) - self.helper(src1, src2after) - - - - def test_importsExternalReference(self): - src0=(""" - a = 'hello' - """) - src1=trimLines(""" - from top import a - def theFunction(self): - print a - """) - src2after=trimLines(""" - from top import a - def theFunction(self): - print a - """) - try: - createPackageStructure(src1, "", src0) - moveFunctionToNewModule(pkgstructureFile1,2, - pkgstructureFile2) - save() - self.assertEqual(src2after,file(pkgstructureFile2).read()) - finally: - removePackageStructure() - - def test_doesntImportRefCreatedInFunction(self): - src1=trimLines(""" - def theFunction(self): - a = 'hello' - print a - """) - src2after=trimLines(""" - def theFunction(self): - a = 'hello' - print a - """) - - self.helper(src1, src2after) - - - def test_doesntImportRefCreatedInFunction(self): - src1=trimLines(""" - def theFunction(self): - a = 'hello' - print a - """) - src2after=trimLines(""" - def theFunction(self): - a = 'hello' - print a - """) - - self.helper(src1, src2after) - - - def test_addsImportStatementToOriginalFileIfRequired(self): - src1=trimLines(""" - def theFunction(self): - pass - b = theFunction() - """) - - src1after=trimLines(""" - from a.b.bah import theFunction - b = theFunction() - """) - try: - createPackageStructure(src1,"") - moveFunctionToNewModule(pkgstructureFile1,1, - pkgstructureFile2) - save() - self.assertEqual(src1after,file(pkgstructureFile1).read()) - finally: - removePackageStructure() - - def test_updatesFromImportStatementsInOtherModules(self): - src0=trimLines(""" - from a.foo import theFunction - print theFunction() - """) - src1=trimLines(""" - def theFunction(self): - pass - """) - - src0after=trimLines(""" - from a.b.bah import theFunction - print theFunction() - """) - try: - createPackageStructure(src1,"",src0) - moveFunctionToNewModule(pkgstructureFile1,1, - pkgstructureFile2) - save() - self.assertEqual(src0after,file(pkgstructureFile0).read()) - finally: - removePackageStructure() - - def test_updatesFromImportMultiplesInOtherModules(self): - src0=trimLines(""" - from a.foo import something,theFunction,somethingelse #comment - print theFunction() - """) - src1=trimLines(""" - def theFunction(self): - pass - something = '' - somethingelse = 0 - """) - - src0after=trimLines(""" - from a.foo import something,somethingelse #comment - from a.b.bah import theFunction - print theFunction() - """) - try: - createPackageStructure(src1,"",src0) - moveFunctionToNewModule(pkgstructureFile1,1, - pkgstructureFile2) - save() - self.assertEqual(src0after,file(pkgstructureFile0).read()) - finally: - removePackageStructure() - - def test_updatesFromImportMultiplesInTargetModule(self): - src0=trimLines(""" - from a.foo import something,theFunction,somethingelse #comment - print theFunction() - """) - src1=trimLines(""" - def theFunction(self): - pass - something = '' - somethingelse = 0 - """) - - src0after=trimLines(""" - from a.foo import something,somethingelse #comment - print theFunction() - def theFunction(self): - pass - """) - try: - createPackageStructure(src1,"",src0) - moveFunctionToNewModule(pkgstructureFile1,1, - pkgstructureFile0) - save() - #print file(pkgstructureFile0).read() - self.assertEqual(src0after,file(pkgstructureFile0).read()) - finally: - removePackageStructure() - - - def test_updatesFromImportInTargetModule(self): - src0=trimLines(""" - from a.foo import theFunction - print theFunction() - """) - src1=trimLines(""" - def theFunction(self): - pass - """) - - src0after=trimLines(""" - print theFunction() - def theFunction(self): - pass - """) - try: - createPackageStructure(src1,"",src0) - moveFunctionToNewModule(pkgstructureFile1,1, - pkgstructureFile0) - save() - self.assertEqual(src0after,file(pkgstructureFile0).read()) - finally: - removePackageStructure() - - - - def helper(self, src1, src2after): - try: - createPackageStructure(src1, "") - moveFunctionToNewModule(pkgstructureFile1,2, - pkgstructureFile2) - save() - self.assertEqual(src2after,file(pkgstructureFile2).read()) - finally: - removePackageStructure() - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_rename.py --- a/vim/sadness/bike/bike/refactor/test_rename.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from bike import testdata -from rename import rename -from bike.testutils import * - -class TestRenameTemporary(BRMTestCase): - def test_renamesSimpleReferencesGivenAssignment(self): - src=trimLines(""" - def foo(): - a = 3 - print a - """) - srcAfter=trimLines(""" - def foo(): - b = 3 - print b - """) - src = self.helper(src,"",2,4,"b") - self.assertEqual(srcAfter,src) - - def helper(self, src, classsrc, line, col, newname): - try: - createPackageStructure(src,classsrc) - filename = pkgstructureFile1 - rename(filename,line,col,newname) - # modify me once save is moved - #return readFile(filename) - from bike.transformer.save import outputqueue - return outputqueue[filename] - finally: - removePackageStructure() -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_renameClass.py --- a/vim/sadness/bike/bike/refactor/test_renameClass.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from rename import rename -from bike.transformer.save import save -from bike.testutils import * -import compiler - -class RenameClassTests: - - def testRenamesClassDcl(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(): - pass - """) - srcAfter=trimLines(""" - class NewName: - def theMethod(): - pass - """) - - src = self.rename(srcBefore, 1,6,"NewName") - self.assertEqual(srcAfter,src) - - # i.e. a = TheClass() - def testRenamesClassReference(self): - srcBefore=trimLines(""" - class TheClass: - pass - a = TheClass() - """) - srcAfter=trimLines(""" - class NewName: - pass - a = NewName() - """) - src = self.rename(srcBefore, 1,6,"NewName") - self.assertEqual(srcAfter,src) - - # i.e. a = TheClass.TheClass() - def testRenamesClassReferenceWhenScopeIsSameNameAsClass(self): - srcBefore = trimLines(""" - class TheClass: - class TheClass: - pass - a = TheClass.TheClass() - """) - srcAfter=trimLines(""" - class TheClass: - class NewName: - pass - a = TheClass.NewName() - """) - src = self.rename(srcBefore, 2,10, "NewName") - self.assertEqual(srcAfter,src) - - # i.e. a = TheClass.TheClass() - def testRenamesClassReferenceWhenChildIsSameNameAsClass(self): - srcBefore = trimLines(""" - class TheClass: - class TheClass: - pass - a = TheClass.TheClass() - """) - srcAfter=trimLines(""" - class NewName: - class TheClass: - pass - a = NewName.TheClass() - """) - src = self.rename(srcBefore, 1,6,"NewName") - self.assertEqual(srcAfter,src) - - - # a = TheClass() + TheClass() - def testRenamesClassReferenceWhenTwoRefsInTheSameLine(self): - srcBefore=trimLines(""" - class TheClass: - pass - a = TheClass() + TheClass() - """) - srcAfter=trimLines(""" - class NewName: - pass - a = NewName() + NewName() - """) - src = self.rename(srcBefore,1,6, "NewName") - self.assertEqual(srcAfter,src) - - def testRenamesClassReferenceInInstanceCreation(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): pass - TheClass().theMethod() - """) - srcAfter=trimLines(""" - class NewName: - def theMethod(self): pass - NewName().theMethod() - """) - src = self.rename(srcBefore,1,6,"NewName") - self.assertEqual(srcAfter,src) - - # i.e. if renaming TheClass, shouldnt rename a.b.c.TheClass - def testDoesntRenameBugusClassReferenceOnEndOfGetattrNest(self): - srcBefore=trimLines(""" - class TheClass: - pass - a.b.c.TheClass # Shouldn't be renamed - """) - srcAfter=trimLines(""" - class NewName: - pass - a.b.c.TheClass # Shouldn't be renamed - """) - src = self.rename(srcBefore,1,6,"NewName") - self.assertEqual(srcAfter,src) - - def testRenamesClassRefUsedInExceptionRaise(self): - srcBefore=trimLines(""" - class TheClass: - pass - raise TheClass, \"hello mum\" - """) - srcAfter=trimLines(""" - class NewName: - pass - raise NewName, \"hello mum\" - """) - src = self.rename(srcBefore, 1,6, "NewName") - self.assertEqual(srcAfter,src) - - def testRenamesClassReferenceNameInInheritenceSpec(self): - srcBefore=trimLines(""" - class TheClass: - pass - class DerivedClass(TheClass): - pass - """) - srcAfter=trimLines(""" - class NewName: - pass - class DerivedClass(NewName): - pass - """) - src = self.rename(srcBefore, 1,6, "NewName") - self.assertEqual(srcAfter,src) - - - -class RenameClassTests_importsClass: - - def testRenamesClassReferenceInInstanceCreationWithFQN(self): - srcBefore=trimLines(""" - import b.bah - def foo(): - a = b.bah.TheClass() - """) - srcAfter=trimLines(""" - import b.bah - def foo(): - a = b.bah.NewName() - """) - src = self.renameClass(srcBefore,"NewName") - self.assertEqual(srcAfter,src) - - def testRenamesClassReferencesInInheritenceSpecs(self): - - srcBefore=trimLines(""" - import b - class DerivedClass(b.bah.TheClass): - pass - """) - srcAfter=trimLines(""" - import b - class DerivedClass(b.bah.NewName): - pass - """) - src = self.renameClass(srcBefore,"NewName") - self.assertEqual(srcAfter,src) - - def testRenamesFromImportReferenceWhenInBodyOfClass(self): - srcBefore=trimLines(""" - class AnotherClass: - from b.bah import TheClass - TheClass.baz = 0 - """) - srcAfter=trimLines(""" - class AnotherClass: - from b.bah import NewName - NewName.baz = 0 - """) - src = self.renameClass(srcBefore,"NewName") - self.assertEqual(srcAfter,src) - - - def testRenamesReferenceToClassImportedInSameClassScope(self): - srcBefore=trimLines(""" - class AnotherClass: - from b.bah import TheClass - TheClass.baz = 0 - """) - srcAfter=trimLines(""" - class AnotherClass: - from b.bah import NewName - NewName.baz = 0 - """) - src = self.renameClass(srcBefore,"NewName") - self.assertEqual(srcAfter,src) - - def testRenamesReferenceToClassImportedWithFromImportStar(self): - srcBefore=trimLines(""" - from a.b.bah import * - a = TheClass() - """) - srcAfter=trimLines(""" - from a.b.bah import * - a = NewName() - """) - src = self.renameClass(srcBefore,"NewName") - self.assertEqual(srcAfter,src) - -class TestRenameClass(BRMTestCase, RenameClassTests): - - def rename(self, src, line, col, newname): - createPackageStructure(src,"pass") - rename(pkgstructureFile1,line,col, newname) - save() - return file(pkgstructureFile1).read() - - -class TestRenameClassReferenceWithDirectoryStructure(BRMTestCase, - RenameClassTests_importsClass): - - def renameClass(self, src, newname): - createPackageStructure(src,TheClassTestdata) - rename(pkgstructureFile2,1,6, newname) - save() - return file(pkgstructureFile1).read() - - -TheClassTestdata = trimLines(""" -class TheClass: - def theMethod(self): - pass - def differentMethod(self): - pass - -class DifferentClass: - def theMethod(self): - pass -""") - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_renameFunction.py --- a/vim/sadness/bike/bike/refactor/test_renameFunction.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from rename import rename -from bike import testdata -from bike.testutils import * -from bike.transformer.save import save -import compiler - -class RenameFunctionTests: - def runTarget(self, src, klassfqn, newname): - # see concrete subclasses for implementation - pass - - def testRenamesFunctionDcl(self): - srcBefore=trimLines(""" - def theFunction(): - pass - """) - srcAfter=trimLines(""" - def newName(): - pass - """) - src = self.rename(srcBefore,1,4,"newName") - self.assertEqual(srcAfter,src) - - def testDoesntBarfWhenFunctionIncludesBrackettedExpression(self): - srcBefore=trimLines(""" - def theFunction(): - return ('\\n').strip() - """) - srcAfter=trimLines(""" - def newName(): - return ('\\n').strip() - """) - src = self.rename(srcBefore,1,4, "newName") - self.assertEqual(srcAfter,src) - - - - -class RenameFunctionTests_importsFunction: - - def testRenamesImportedFunctionReference(self): - srcBefore=trimLines(""" - import b.bah - b.bah.theFunction() - """) - srcAfter=trimLines(""" - import b.bah - b.bah.newName() - """) - src = self.renameFunction(srcBefore,"newName") - self.assertEqual(srcAfter,src) - - def testRenamesFunctionReferenceImportedWithFromClause(self): - srcBefore=trimLines(""" - from b.bah import theFunction - theFunction() - """) - srcAfter=trimLines(""" - from b.bah import newName - newName() - """) - src = self.renameFunction(srcBefore,"newName") - self.assertEqual(srcAfter,src) - - def testRenamesFunctionRefInImportClause(self): - srcBefore=trimLines(""" - import b.bah - b.bah.theFunction() - """) - srcAfter=trimLines(""" - import b.bah - b.bah.newName() - """) - src = self.renameFunction(srcBefore,"newName") - self.assertEqual(srcAfter,src) - - - def testRenamesFunctionRefInImportFromClause(self): - srcBefore=trimLines(""" - from b.bah import theFunction - theFunction() - """) - srcAfter=trimLines(""" - from b.bah import newName - newName() - """) - src = self.renameFunction(srcBefore,"newName") - self.assertEqual(srcAfter,src) - - - -class TestRenameFunction(BRMTestCase, RenameFunctionTests): - def rename(self, src, line, col, newname): - writeTmpTestFile(src) - rename(tmpfile,line,col, newname) - save() - return file(tmpfile).read() - - -class TestRenameFunctionReferenceWithDirectoryStructure(BRMTestCase, RenameFunctionTests_importsFunction): - - def renameFunction(self, src, newname): - createPackageStructure(src,FunctionTestdata) - rename(pkgstructureFile2,1,4, newname) - save() - return file(pkgstructureFile1).read() - -FunctionTestdata = trimLines(""" -def theFunction(): - pass -""") - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/test_renameMethod.py --- a/vim/sadness/bike/bike/refactor/test_renameMethod.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,710 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from rename import rename -import compiler -from bike import testdata - -from bike.testutils import* - -from bike.transformer.save import save - -class RenameMethodTests: - - def test_renamesTheMethod(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - pass - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - pass - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_doesntRenameMethodOfSameNameOnOtherClasses(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - pass - class b: - def theMethod(self): - pass - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - pass - class b: - def theMethod(self): - pass - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_doesntRenameOtherMethodsOfSameClass(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - a=b - def aMethod(self): - pass - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - a=b - def aMethod(self): - pass - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodWhenClassNestedInFunction(self): - srcBefore=trimLines(""" - def theFunction(): - class TheClass: - def theMethod(self): - pass - """) - srcAfter=trimLines(""" - def theFunction(): - class TheClass: - def newName(self): - pass - """) - src = self.rename(srcBefore,3,12,"newName") - self.assertEqual(srcAfter,src) - - def test_doesntBarfOnInheritanceHierarchies(self): - srcBefore=trimLines(""" - from b.bah import DifferentClass - class TheClass(foo.bah): - def theMethod(self): - pass - """) - src = self.rename(srcBefore,2,8,"newName") - - def test_renamesMethodWhenMethodCallFromOtherMethodInSameClass(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - pass - def anotherMethod(self): - self.theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - pass - def anotherMethod(self): - self.newName() - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_doesntBarfOnNestedClasses(self): - srcBefore=trimLines(""" - class TheClass: - class AnotherClass: - pass - def theMethod(self): - pass - """) - src = self.rename(srcBefore,4,8,"newName") - - def test_renamesMethodWhenBaseClassesArentInAST(self): - srcBefore=trimLines(""" - class TheClass(notInAst): - def theMethod(self): - pass - """) - srcAfter=trimLines(""" - class TheClass(notInAst): - def newName(self): - pass - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodInRelatedClasses(self): - srcBefore=trimLines(""" - class root: - def theMethod(self): - pass - - class a(root): - def theMethod(self): - pass - - class b(root): - pass - - class TheClass(b): - def theMethod(self): - pass - """) - srcAfter=trimLines(""" - class root: - def newName(self): - pass - - class a(root): - def newName(self): - pass - - class b(root): - pass - - class TheClass(b): - def newName(self): - pass - """) - src = self.rename(srcBefore,13,8,"newName") - self.assertEqual(srcAfter,src) - - - def test_renameMethodDoesntBarfOnNoneAsDefaultArgToMethod(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self, root, flist, stack=None): - pass - """) - src = self.rename(srcBefore,2,8,"newName") - - - -class RenameMethodTests_ImportsClass: - def test_renamesMethodOnDerivedClassInstance(self): - srcBefore = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass(BaseClass): - pass - - class DerivedDerivedClass(DerivedClass): - def theMethod(self): - print 'hello' - """) - srcAfter = trimLines(""" - from b.bah import TheClass as BaseClass - - class DerivedClass(BaseClass): - pass - - class DerivedDerivedClass(DerivedClass): - def newName(self): - print 'hello' - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - -class RenameMethodReferenceTests: - # Generic tests. These tests are designed to be run in the context of a ui - # and in a package hierarchy structure - - def test_doesntBarfWhenConfrontedWithComplexReturnTypes(self): - src = trimLines(""" - import a - class TheClass: - def theMethod(self): - pass - - def bah(): - return a[35] - - b = bah() - b.theMethod() - """) - self.rename(src,3,8,"newName") - - def test_doesntbarfWhenCallMadeOnInstanceReturnedFromFnCall(self): - srcBefore=trimLines(""" - from foo import e - class TheClass: - def theMethod(self): - pass - ast = e().f(src) - """) - self.rename(srcBefore,3,8,"newName") - - def test_doesntStackOverflowOnRecursiveFunctions(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - pass - - def foo(a): - return foo(a) - """) - self.rename(srcBefore,2,8,"newName") - - def test_renamesMethodReferenceOfInstanceCreatedInParentScopeAfterFunction(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - pass - a = TheClass() - def foo(): - a.theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - pass - a = TheClass() - def foo(): - a.newName() - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodReferenceOfInstanceObtainedByCallingFunction(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(): - pass - def foo(): - b = TheClass() - return b - a = foo() - a.theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(): - pass - def foo(): - b = TheClass() - return b - a = foo() - a.newName() - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodReferenceOfInstanceCreatedInAnotherFunction(self): - - srcBefore=trimLines(""" - class TheClass: - def theMethod(): - pass - def bah(): - return TheClass() - def foo(): - a = bah() - a.theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(): - pass - def bah(): - return TheClass() - def foo(): - a = bah() - a.newName() - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodReferenceOfInstanceCreatedInSubsequentFunction(self): - srcBefore = trimLines(""" - class TheClass: - def theMethod(): - pass - class NotTheClass: - def theMethod(): - pass - - def foo(): - a = bah() - a.theMethod() - - def bah(): - return TheClass() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(): - pass - class NotTheClass: - def theMethod(): - pass - - def foo(): - a = bah() - a.newName() - - def bah(): - return TheClass() - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodReferenceOnInstanceThatIsAnAttributeOfSelf(self): - srcBefore = trimLines(""" - class TheClass: - def theMethod(self): - pass - - class AnotherClass: - def __init__(self): - self.a = TheClass() - def anotherFn(self): - self.a.theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - pass - - class AnotherClass: - def __init__(self): - self.a = TheClass() - def anotherFn(self): - self.a.newName() - """) - src = self.rename(srcBefore,2,8,"newName") - self.assertEqual(srcAfter,src) - - def test_doesntBarfOnGetattrThatItCantDeduceTypeOf(self): - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): - pass - a = TheClass - - a.b.bah = 3 - """) - self.rename(srcBefore,2,8,"newName") - - -class RenameMethodReferenceTests_ImportsClass: - - def test_renamesReferenceOfClassImportedAsAnotherName(self): - srcBefore=trimLines(""" - from b.bah import TheClass as MyTheClass - def foo(): - a = MyTheClass() - a.theMethod() - """) - srcAfter=trimLines(""" - from b.bah import TheClass as MyTheClass - def foo(): - a = MyTheClass() - a.newName() - """) - src = self.renameMethod(srcBefore,2,8, "newName") - self.assertEqual(srcAfter,src) - - def test_renamesReferenceWhenObjectCreationAndReferenceInModuleScope(self): - srcBefore=trimLines(""" - from b.bah import TheClass - a = TheClass() - a.theMethod() - """) - srcAfter=trimLines(""" - from b.bah import TheClass - a = TheClass() - a.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - - def test_renamesReferenceWhenObjectCreatedInSameFunctionAsReference(self): - srcBefore=trimLines(""" - import b.bah - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - srcAfter=trimLines(""" - import b.bah - def foo(): - a = b.bah.TheClass() - a.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - def test_doesntrenameDifferentMethodReferenceWhenObjectCreatedInSameScope(self): - srcBefore=trimLines(""" - import b.bah.TheClass - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - src = self.renameMethod(srcBefore, 4,8, "newName") - self.assertEqual(srcBefore,src) - - def test_doesntrenameMethodReferenceWhenDifferentObjectCreatedInSameScope(self): - srcBefore=trimLines(""" - import b.bah.TheClass - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - src = self.renameMethod(srcBefore, 8,8,"newName") - self.assertEqual(srcBefore,src) - - def test_renamesReferenceOfImportedClass(self): - srcBefore=trimLines(""" - import b.bah - - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - srcAfter=trimLines(""" - import b.bah - - def foo(): - a = b.bah.TheClass() - a.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - def test_doesntRenameReferenceOfDifferentImportedClass(self): - srcBefore=trimLines(""" - from b.bah import DifferentClass - - def foo(): - a = b.bah.TheClass() - a.theMethod() - """) - src = self.renameMethod(srcBefore, 8,8, - "newName") - self.assertEqual(srcBefore,src) - - def test_renamesReferenceOfClassImportedWithFromClause(self): - srcBefore=trimLines(""" - from b.bah import TheClass - - def foo(): - a = TheClass() - a.theMethod() - """) - srcAfter=trimLines(""" - from b.bah import TheClass - - def foo(): - a = TheClass() - a.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - def test_doesntrenameReferenceOfClassImportedWithDifferentAsClause(self): - srcBefore = trimLines(""" - from b.bah import TheClass as MyClass - - def foo(): - a = TheClass() - a.theMethod() - """) - - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcBefore,src) - - def test_renamesReferenceOfClassImportedWithFromFooImportStar(self): - srcBefore=trimLines(""" - from b.bah import * - a = TheClass() - a.theMethod() - """) - srcAfter=trimLines(""" - from b.bah import * - a = TheClass() - a.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - def test_renamesMethodReferenceOfInstanceCreatedInParentScope(self): - srcBefore=trimLines(""" - from b.bah import TheClass - a = TheClass() - def foo(): - a.theMethod() - """) - srcAfter=trimLines(""" - from b.bah import TheClass - a = TheClass() - def foo(): - a.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - def test_doesntRenameMethodWhenObjectCreatedInChildScopeToMethodReference(self): - srcBefore = trimLines(""" - from b.bah import TheClass - a = AnotherClass() - def foo(): - a = TheClass() - a.theMethod() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcBefore,src) - - def test_renamesReferenceOnDerivedClassInstance(self): - srcBefore=trimLines(""" - import b - class DerivedClass(b.bah.TheClass): - pass - class DerivedDerivedClass(DerivedClass): - pass - theInstance = DerivedDerivedClass() - theInstance.theMethod() - """) - srcAfter=trimLines(""" - import b - class DerivedClass(b.bah.TheClass): - pass - class DerivedDerivedClass(DerivedClass): - pass - theInstance = DerivedDerivedClass() - theInstance.newName() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - - -# tests that cover stuff not renamed automatically -# (I.e. are renamed after user manually expresses desire to do so) -class RenameMethodAfterPromptTests: - def test_renamesReferenceWhenMethodCallDoneOnInstanceCreation(self): - - srcBefore=trimLines(""" - class TheClass: - def theMethod(self): pass - TheClass().theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): pass - TheClass().newName() - """) - src = self.renameMethod(srcBefore,2,8, "newName") - self.assertEqual(srcAfter,src) - - - def test_renamesReferenceInMiddleOfBiggerCompoundCall(self): - srcBefore = trimLines(""" - class TheClass: - def theMethod(self): return AnotherClass() - TheClass().theMethod().anotherMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): return AnotherClass() - TheClass().newName().anotherMethod() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - -class TestRenameMethodWithSingleModule(BRMTestCase, RenameMethodTests, RenameMethodReferenceTests): - # template method - def rename(self, src, line, col, newname): - try: - createPackageStructure(src, "pass") - rename(pkgstructureFile1,line,col,newname) - save() - return file(pkgstructureFile1).read() - finally: - removePackageStructure() - - -class TestRenameMethodWithDirectoryStructure(RenameMethodTests, RenameMethodReferenceTests, BRMTestCase): - - def rename(self, src, line, col, newname): - try: - createPackageStructure("pass",src) - rename(pkgstructureFile2,line,col,newname) - save() - return file(pkgstructureFile2).read() - finally: - removePackageStructure() - - -class TestRenameMethodReferenceWithDirectoryStructure(BRMTestCase, RenameMethodTests_ImportsClass, RenameMethodReferenceTests_ImportsClass): - - def renameMethod(self, src, line, col, newname): - try: - createPackageStructure(src,MethodTestdata) - rename(pkgstructureFile2,line,col,newname) - save() - return file(pkgstructureFile1).read() - finally: - removePackageStructure() - -class TestRenameMethodStuffCorrectlyAfterPromptReturnsTrue(BRMTestCase, - RenameMethodAfterPromptTests): - - def callback(self, filename, line, colbegin, colend): - return 1 - - - def renameMethod(self, src, line, col, newname): - createPackageStructure(src, MethodTestdata) - rename(pkgstructureFile1,line,col,newname,self.callback) - save() - return file(pkgstructureFile1).read() - - - -class TestDoesntRenameMethodIfPromptReturnsFalse(BRMTestCase): - def callback(self, filename, line, colbegin, colend): - return 0 - - def renameMethod(self, src, line, col, newname): - createPackageStructure(src, MethodTestdata) - rename(pkgstructureFile1,line,col,newname,self.callback) - save() - return file(pkgstructureFile1).read() - - def test_doesntRenameMethodIfPromptReturnsFalse(self): - srcBefore = trimLines(""" - class TheClass: - def theMethod(self): - pass - b = TheClass() - b.theMethod() - a = someFunction() - a.theMethod() - """) - srcAfter=trimLines(""" - class TheClass: - def newName(self): - pass - b = TheClass() - b.newName() - a = someFunction() - a.theMethod() - """) - src = self.renameMethod(srcBefore, 2,8, "newName") - self.assertEqual(srcAfter,src) - - -MethodTestdata = trimLines(""" -class TheClass: - def theMethod(self): - pass - def differentMethod(self): - pass - -class DifferentClass: - def theMethod(self): - pass -""") - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/testall.py --- a/vim/sadness/bike/bike/refactor/testall.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -#!/usr/bin/env python -import setpath -from test_renameMethod import * -from test_renameClass import * -from test_renameFunction import * -from test_rename import * -from test_extractMethod import * -from test_inlineVariable import * -from test_extractVariable import * -from test_moveToModule import * - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/refactor/utils.py --- a/vim/sadness/bike/bike/refactor/utils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -import re - -def getLineSeperator(line): - if line.endswith("\r\n"): - linesep = "\r\n" # windoze - else: - linesep = line[-1] # mac or unix - return linesep - - -def getTabWidthOfLine(line): - match = re.match("\s+",line) - if match is None: - return 0 - else: - return match.end(0) - -def reverseCoordsIfWrongWayRound(startcoords,endcoords): - if(startcoords.line > endcoords.line) or \ - (startcoords.line == endcoords.line and \ - startcoords.column > endcoords.column): - return endcoords,startcoords - else: - return startcoords,endcoords diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/setpath.py --- a/vim/sadness/bike/bike/setpath.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -import sys,os -if not os.path.abspath("..") in sys.path: - from bike import log - print >> log.warning, "Appending to the system path. This should only happen in unit tests" - sys.path.append(os.path.abspath("..")) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/test_bikefacade.py --- a/vim/sadness/bike/bike/test_bikefacade.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,377 +0,0 @@ -#!/usr/bin/env python -import unittest -import setpath -import sys - -from bike import testdata -from bike.testutils import * -import bike -from bike.refactor.test_renameFunction import RenameFunctionTests, RenameFunctionTests_importsFunction, FunctionTestdata -from bike.refactor.test_renameClass import RenameClassTests, RenameClassTests_importsClass, TheClassTestdata -from bike.refactor.test_renameMethod import RenameMethodTests, RenameMethodTests_ImportsClass, RenameMethodReferenceTests, RenameMethodReferenceTests_ImportsClass, RenameMethodAfterPromptTests, TestDoesntRenameMethodIfPromptReturnsFalse,MethodTestdata -from bike.refactor import test_extractMethod -import bikefacade -from bike import UndoStackEmptyException -from bike.query.getTypeOf import getTypeOf - -class TestPathFunctions(BRMTestCase): - def test_setCompletePythonPath_removesDuplicates(self): - origpath = sys.path - try: - sys.path = ["foobah"] - ctx = bike.init() - ctx._setCompletePythonPath(sys.path[-1]) - self.assertEqual(1,ctx._getCurrentSearchPath().count(sys.path[-1])) - finally: - sys.path = origpath - - - def test_setNonLibPathonPath_removesLibDirectories(self): - origpath = sys.path - try: - writeTmpTestFile("pass") - libdir = os.path.join(sys.prefix,"lib","python"+sys.version[:3]) - sys.path = [libdir,os.path.join(libdir,"site-packages")] - ctx = bike.init() - ctx._setNonLibPythonPath(tmproot) - self.assertEqual([tmproot],ctx._getCurrentSearchPath()) - finally: - sys.path = origpath - -class TestRenameMethodAfterPrompt(BRMTestCase,RenameMethodAfterPromptTests): - def callback(self, filename, line, colstart, colend): - return 1 - - def renameMethod(self, src, line, col, newname): - writeTmpTestFile(src) - ctx = bike.init() - ctx.setRenameMethodPromptCallback(self.callback) - ctx.renameByCoordinates(tmpfile,line,col,newname) - ctx.save() - newsrc = readFile(tmpfile) - return newsrc - -class TestDoesntRenameMethodIfPromptReturnsFalse(TestDoesntRenameMethodIfPromptReturnsFalse): - - def callback(self, filename, line, colstart, colend): - return 0 - - def renameMethod(self, src, line, col, newname): - writeTmpTestFile(src) - ctx = bike.init() - ctx.setRenameMethodPromptCallback(self.callback) - ctx.renameByCoordinates(tmpfile,line,col,newname) - ctx.save() - newsrc = readFile(tmpfile) - return newsrc - - -class TestRenameByCoordinates2(RenameMethodTests,RenameMethodReferenceTests, RenameClassTests,RenameFunctionTests,BRMTestCase): - def rename(self, src, line, col, newname): - writeTmpTestFile(src) - ctx = bike.init() - ctx.renameByCoordinates(os.path.abspath(tmpfile),line,col,newname) - ctx.save() - newsrc = readFile(tmpfile) - return newsrc - - -class TestRenameByCoordinatesWithDirectoryStructure( - RenameClassTests_importsClass, - RenameFunctionTests_importsFunction, - RenameMethodTests_ImportsClass, - RenameMethodReferenceTests_ImportsClass, - BRMTestCase): - def renameClass(self, src, newname): - try: - createPackageStructure(src, TheClassTestdata) - ctx = bike.init() - ctx.renameByCoordinates(pkgstructureFile2,1,6,newname) - ctx.save() - newsrc = readFile(pkgstructureFile1) - return newsrc - finally: - removePackageStructure() - - - def renameMethod(self, src, line, col, newname): - try: - createPackageStructure(src, MethodTestdata) - ctx = bike.init() - ctx.renameByCoordinates(pkgstructureFile2,line,col,newname) - ctx.save() - newsrc = readFile(pkgstructureFile1) - return newsrc - finally: - removePackageStructure() - - def renameFunction(self, src, newname): - try: - createPackageStructure(src, FunctionTestdata) - ctx = bike.init() - ctx.renameByCoordinates(pkgstructureFile2,1,4,newname) - ctx.save() - newsrc = readFile(pkgstructureFile1) - return newsrc - finally: - removePackageStructure() - - - -class Test_deducePackageOfFile(BRMTestCase): - def test_returnsEmptyStringIfFileNotInPackage(self): - try: - # this doesnt have __init__.py file, so - # isnt package - os.makedirs("a") - writeFile(os.path.join("a","foo.py"),"pass") - pkg = bikefacade._deducePackageOfFile(os.path.join("a","foo.py")) - assert pkg == "" - finally: - os.remove(os.path.join("a","foo.py")) - os.removedirs(os.path.join("a")) - - def test_returnsNestedPackage(self): - try: - os.makedirs(os.path.join("a","b")) - writeFile(os.path.join("a","__init__.py"),"# ") - writeFile(os.path.join("a","b","__init__.py"),"# ") - writeFile(os.path.join("a","b","foo.py"),"pass") - pkg = bikefacade._deducePackageOfFile(os.path.join("a","b","foo.py")) - assert pkg == "a.b" - finally: - os.remove(os.path.join("a","__init__.py")) - os.remove(os.path.join("a","b","__init__.py")) - os.remove(os.path.join("a","b","foo.py")) - os.removedirs(os.path.join("a","b")) - - -class TestExtractMethod(test_extractMethod.TestExtractMethod): - - def test_extractsPass(self): - srcBefore=trimLines(""" - class MyClass: - def myMethod(self): - pass - """) - - srcAfter=trimLines(""" - class MyClass: - def myMethod(self): - self.newMethod() - - def newMethod(self): - pass - """) - - writeTmpTestFile(srcBefore) - ctx = bike.init() - ctx.extractMethod(os.path.abspath(tmpfile),3,8,3,12,"newMethod") - ctx.save() - self.assertEqual(readTmpTestFile(),srcAfter) - ctx.undo() - ctx.save() - self.assertEqual(readTmpTestFile(),srcBefore) - - -class TestExtractFunction(test_extractMethod.TestExtractFunction): - def test_extractsFunction(self): - srcBefore=trimLines(""" - def myFunction(): # comment - a = 3 - c = a + 99 - b = c * 1 - print b - """) - srcAfter=trimLines(""" - def myFunction(): # comment - a = 3 - b = newFunction(a) - print b - - def newFunction(a): - c = a + 99 - b = c * 1 - return b - """) - writeTmpTestFile(srcBefore) - ctx = bike.init() - ctx.extractMethod(os.path.abspath(tmpfile),3,4,4,13,"newFunction") - ctx.save() - self.assertEqual(readTmpTestFile(),srcAfter) - ctx.undo() - ctx.save() - self.assertEqual(readTmpTestFile(),srcBefore) - - -class TestUndo(BRMTestCase): - - def test_undoesTheTextOfASingleFile(self): - src = trimLines(""" - class a: - def foo(self): - pass - """) - writeTmpTestFile(src) - #ctx = bike.init() - ctx = bike.init() - - ctx.renameByCoordinates(tmpfile,2,8,"c") - ctx.save() - ctx.undo() - ctx.save() - newsrc = readFile(tmpfile) - self.assertEqual(newsrc,src) - - - def test_undoesTwoConsecutiveRefactorings(self): - try: - src = trimLines(""" - class a: - def foo(self): - pass - """) - writeTmpTestFile(src) - ctx = bike.init() - ctx.renameByCoordinates(tmpfile,2,8,"c") - ctx.save() - - newsrc1 = readFile(tmpfile) - - ctx.renameByCoordinates(tmpfile,2,8,"d") - ctx.save() - - - # 1st undo - ctx.undo() - ctx.save() - newsrc = readFile(tmpfile) - self.assertEqual(newsrc, - newsrc1) - - # 2nd undo - ctx.undo() - ctx.save() - newsrc = readFile(tmpfile) - self.assertEqual(newsrc,src) - finally: - pass - #deleteTmpTestFile() - - - def test_undoesTheTextOfAFileTwice(self): - for i in range(3): - src = trimLines(""" - class foo: - def bah(self): - pass - """) - writeTmpTestFile(src) - ctx = bike.init() - ctx.renameByCoordinates(tmpfile,2,8,"c") - ctx.save() - ctx.undo() - ctx.save() - newsrc = readFile(tmpfile) - self.assertEqual(newsrc,src) - raisedexception=0 - try: - ctx.undo() - except UndoStackEmptyException: - pass - else: - assert 0,"should have raised an exception" - - ''' - def test_undoesManualModificationsToFiles(self): - writeTmpTestFile("class foo: pass") - origsrc = readFile(tmpfile) - ctx = bike.init() - - writeTmpTestFile("pass") - import os - ctx.init() - newsrc = readFile(tmpfile) - assert newsrc != origsrc - ctx.undo() - ctx.save() - newsrc = readFile(tmpfile) - assert newsrc == origsrc - ''' - -class TestGetReferencesToClass_Facade(BRMTestCase): - def test_returnsReferences(self): - src = trimLines(""" - class TheClass: - pass - a = TheClass() - """) - writeTmpTestFile(src) - ctx = bike.init() - refs = [refs for refs in ctx.findReferencesByCoordinates(tmpfile,1,6)] - self.assertEqual(refs[0].filename,os.path.abspath(tmpfile)) - self.assertEqual(refs[0].lineno,3) - assert hasattr(refs[0],"confidence") - - -class TestFindDefinitionByCoordinates(BRMTestCase): - def test_findsClassRef(self): - src=trimLines(""" - class TheClass: - pass - a = TheClass() - """) - writeTmpTestFile(src) - ctx = bike.init() - defn = [x for x in ctx.findDefinitionByCoordinates(tmpfile,3,6)] - assert defn[0].filename == os.path.abspath(tmpfile) - assert defn[0].lineno == 1 - assert defn[0].confidence == 100 - -class TestBRM_InlineLocalVariable(BRMTestCase): - def test_works(self): - srcBefore=trimLines(""" - def foo(): - b = 'hello' - print b - """) - srcAfter=trimLines(""" - def foo(): - print 'hello' - """) - - writeTmpTestFile(srcBefore) - ctx = bike.init() - ctx.inlineLocalVariable(tmpfile,3,10) - ctx.save() - self.assertEqual(file(tmpfile).read(),srcAfter) - - -class TestBRM_ExtractLocalVariable(BRMTestCase): - def test_works(self): - srcBefore=trimLines(""" - def foo(): - print 3 + 2 - """) - srcAfter=trimLines(""" - def foo(): - a = 3 + 2 - print a - """) - try: - writeTmpTestFile(srcBefore) - ctx = bike.init() - ctx.extractLocalVariable(tmpfile,2,10,2,15,'a') - ctx.save() - self.assertEqual(file(tmpfile).read(),srcAfter) - finally: - pass - #deleteTmpTestFile() - - - - - - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/test_testutils.py --- a/vim/sadness/bike/bike/test_testutils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import setpath -import unittest -from testutils import* -import testdata -import sys - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/testall.py --- a/vim/sadness/bike/bike/testall.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -import setpath -from test_bikefacade import * - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/testdata.py --- a/vim/sadness/bike/bike/testdata.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -TheClass = """ -class TheClass: - def theMethod(self): - pass - def differentMethod(self): - pass - -class DifferentClass: - def theMethod(self): - pass -""" - - -Function = """ -def theFunction(): - pass -""" diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/testutils.py --- a/vim/sadness/bike/bike/testutils.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -from bike.globals import * -import unittest -import os -import os.path -from mock import Mock -from bike.parsing.fastparserast import getRoot, Root, resetRoot -from parsing.utils import fqn_rcar, fqn_rcdr -import re -from bike import log -filesToDelete = None -dirsToDelete = None - -class BRMTestCase(unittest.TestCase): - def setUp(self): - log.warning = log.SilentLogger() - try: os.makedirs(tmproot) - except: pass - os.chdir(tmproot) - - resetRoot(Root([tmproot])) - getRoot().unittestmode = True - global filesToDelete - global dirsToDelete - filesToDelete = [] - dirsToDelete = [] - from bike.parsing.load import Cache - Cache.instance.reset() - - - - def tearDown(self): - global filesToDelete - global dirsToDelete - - for path in filesToDelete: - try: os.remove(path) - except: pass - filesToDelete = [] - - for path in dirsToDelete: - try: os.removedirs(path) - except: pass - dirsToDelete = [] - - os.chdir("..") - try: os.removedirs(tmproot) - except: pass - - - -tmproot = os.path.abspath("tmproot") -tmpfile = os.path.join(tmproot, "bicyclerepairman_tmp_testfile.py") -tmpmodule = "bicyclerepairman_tmp_testfile" - - -def writeFile(filename, src): - f = open(filename, "w+") - f.write(src) - f.close() - filesToDelete.append(filename) - -def readFile(filename): - f = open(filename) - src = f.read() - f.close() - return src - -def writeTmpTestFile(src): - try: - os.makedirs(tmproot) - except OSError: - pass - writeFile(tmpfile, src) - -def readTmpTestFile(): - return readFile(tmpfile) - -def deleteTmpTestFile(): - os.remove(tmpfile) - os.removedirs(tmproot) - - -pkgstructureRootDir = tmproot -pkgstructureBasedir = os.path.join(pkgstructureRootDir, "a") -pkgstructureChilddir = os.path.join(pkgstructureBasedir, "b") -pkgstructureFile0 = os.path.join(pkgstructureRootDir, "top.py") -pkgstructureFile1 = os.path.join(pkgstructureBasedir, "foo.py") -pkgstructureFile2 = os.path.join(pkgstructureChilddir, "bah.py") - - -def createPackageStructure(src1, src2, src0="pass"): - try: os.makedirs(pkgstructureChilddir) - except: pass - writeFile(os.path.join(pkgstructureBasedir, "__init__.py"), "#") - writeFile(os.path.join(pkgstructureChilddir, "__init__.py"), "#") - writeFile(pkgstructureFile0, src0) - writeFile(pkgstructureFile1, src1) - writeFile(pkgstructureFile2, src2) - -def removePackageStructure(): - os.remove(os.path.join(pkgstructureBasedir, "__init__.py")) - os.remove(os.path.join(pkgstructureChilddir, "__init__.py")) - os.remove(pkgstructureFile0) - os.remove(pkgstructureFile1) - os.remove(pkgstructureFile2) - os.removedirs(pkgstructureChilddir) - - -pkgstructureBasedir2 = os.path.join(pkgstructureRootDir, "c") -pkgstructureFile3 = os.path.join(pkgstructureBasedir2, "bing.py") - -def createSecondPackageStructure(src3): - try: os.makedirs(pkgstructureBasedir2) - except: pass - writeFile(os.path.join(pkgstructureBasedir2, "__init__.py"), "#") - writeFile(pkgstructureFile3, src3) - -def removeSecondPackageStructure(): - os.remove(os.path.join(pkgstructureBasedir2, "__init__.py")) - os.remove(pkgstructureFile3) - os.removedirs(pkgstructureBasedir2) - - - -def createAST(src): - from bike.parsing.load import getSourceNode - writeFile(tmpfile,src) - return getSourceNode(tmpfile) - - -def createSourceNodeAt(src, fqn): - modname = fqn_rcar(fqn) - packagefqn = fqn_rcdr(fqn) - dirpath = os.path.join(*packagefqn.split(".")) - filepath = os.path.join(dirpath,modname+".py") - try: os.makedirs(dirpath) - except: pass - dirsToDelete.append(dirpath) - - # add the __init__.py files - path = "." - for pathelem in packagefqn.split("."): - path = os.path.join(path,pathelem) - initfile = os.path.join(path,"__init__.py") - writeFile(initfile,"#") - filesToDelete.append(initfile) - writeFile(filepath,src) - filesToDelete.append(filepath) - return getRoot() - - -# takes the leading whitespace out of a multi line comment. -# means you can imbed """ -# text like -# this -# """ -# in your code, and it will come out -#"""text like -#this""" -def trimLines(src): - lines = src.splitlines(1)[1:] - tabwidth = re.match("\s*",lines[0]).end(0) - newlines = [] - for line in lines: - if line == "\n" or line == "\r\n": - newlines.append(line) - else: - newlines.append(line[tabwidth:]) - return "".join(newlines) - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/transformer/WordRewriter.py --- a/vim/sadness/bike/bike/transformer/WordRewriter.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -from bike.parsing.load import getSourceNode -from bike.transformer.undo import getUndoStack -from bike.transformer.save import queueFileToSave -import re - -# This class maintains a set of changed lines to the original source -# nodes. This is important because the act of changing a line messes -# up the coordinates on which renames are done. -# Commit writes the changes back to the source nodes -class WordRewriter: - def __init__(self): - self.modifiedsrc = {} - - def rewriteString(self, srcnode, lineno, colno, newname): - filename = srcnode.filename - if not self.modifiedsrc.has_key(filename): - getUndoStack().addSource(filename,srcnode.getSource()) - self.modifiedsrc[filename] = {} - if not self.modifiedsrc[filename].has_key(lineno): - line = srcnode.getLines()[lineno-1] - self.modifiedsrc[filename][lineno] = self._lineToDict(line) - self.modifiedsrc[filename][lineno][colno] = newname - - - # writes all the changes back to the src nodes - def commit(self): - for filename in self.modifiedsrc.keys(): - srcnode = getSourceNode(filename) - for lineno in self.modifiedsrc[filename]: - lines = srcnode.getLines() - lines[lineno-1] = self._dictToLine(self.modifiedsrc[filename][lineno]) - queueFileToSave(filename,"".join(srcnode.getLines())) - - - # this function creates a dictionary with each word referenced by - # its column position in the original line - def _lineToDict(self, line): - words = re.split("(\w+)", line) - h = {};i = 0 - for word in words: - h[i] = word - i+=len(word) - return h - - def _dictToLine(self, d): - cols = d.keys() - cols.sort() - return "".join([d[colno]for colno in cols]) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/transformer/__init__.py --- a/vim/sadness/bike/bike/transformer/__init__.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -""" -Package containing modules which transform the internal -representation of the sourcecode. -""" diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/transformer/save.py --- a/vim/sadness/bike/bike/transformer/save.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -from bike import log - -outputqueue = {} - -def getQueuedFile(filename): - try: - return outputqueue[filename] - except: - pass - #print "HERE!" - - -def resetOutputQueue(): - global outputqueue - outputqueue = {} - -def queueFileToSave(filename,src): - outputqueue[filename] = src - from bike.parsing.load import getSourceNode - getSourceNode(filename).resetWithSource(src) - -def save(): - from bike.transformer.undo import getUndoStack - - global outputqueue - savedFiles = [] - for filename,src in outputqueue.iteritems(): - print >> log.progress, "Writing:",filename - f = file(filename, "w+") - f.write(outputqueue[filename]) - f.close() - savedFiles.append(filename) - outputqueue = {} - #print "stack is "+ str(getUndoStack().stack) - getUndoStack().commitUndoFrame() - return savedFiles diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/transformer/setpath.py --- a/vim/sadness/bike/bike/transformer/setpath.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -import sys,os -if not os.path.abspath("..") in sys.path: - from bike import log - print >> log.warning, "Appending to the system path. This should only happen in unit tests" - sys.path.append(os.path.abspath("..")) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/transformer/testall.py --- a/vim/sadness/bike/bike/transformer/testall.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -#!/usr/bin/env python - -#from test_undo import * - -if __name__ == "__main__": - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/bike/transformer/undo.py --- a/vim/sadness/bike/bike/transformer/undo.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -from bike import log -from bike.transformer.save import queueFileToSave - -_undoStack = None - -def getUndoStack(forceNewStack = 0): - global _undoStack - if _undoStack is None or forceNewStack: - _undoStack = UndoStack() - return _undoStack - -class UndoStackEmptyException: pass - -class UndoStack(object): - def __init__(self): - self.stack = [] - self.stack.append({}) - self.frame = self.stack[-1] - self.setUndoBufferSize(10) - - def setUndoBufferSize(self, undoBufferSize): - self.undoBufferSize = undoBufferSize - - def addSource(self, filename, src): - if filename not in self.frame: - self.frame[filename] = src - - def commitUndoFrame(self): - #restrict size of buffer - while len(self.stack) > self.undoBufferSize: - #print "clipping undo stack" - del self.stack[0] - - if len(self.frame) != 0: - #print "commitUndoFrame" - self.stack.append({}) - self.frame = self.stack[-1] - - def undo(self, **opts): - #print "undo called",self.stack - if len(self.stack) < 2: - raise UndoStackEmptyException() - undoframe = self.stack[-2] - #print "undoframe is",undoframe - for filename,src in undoframe.iteritems(): - print >>log.progress, "Undoing:",filename - queueFileToSave(filename,src) - self.stack = self.stack[:-2] - self.stack.append({}) - self.frame = self.stack[-1] diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/BicycleRepairMan_Idle.py --- a/vim/sadness/bike/ide-integration/BicycleRepairMan_Idle.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,422 +0,0 @@ -# bicycle repair man idle extension -import bike -from bike.transformer.undo import UndoStackEmptyException -import bike.parsing.load -import os -from Tkinter import * -import tkFileDialog -import tkMessageBox -import tkSimpleDialog -import sys -import string -try: - from idlelib.PathBrowser import * - from idlelib.WindowList import ListedToplevel - from idlelib.TreeWidget import TreeNode, TreeItem, ScrolledCanvas - from idlelib import EditorWindow - from idlelib.PyShell import PyShell - from idlelib.OutputWindow import OutputWindow - try: - from idlelib.configHandler import idleConf - except ImportError: - pass - - - -except ImportError: - from PathBrowser import* - from WindowList import ListedToplevel - from TreeWidget import TreeNode, TreeItem, ScrolledCanvas - import EditorWindow - from PyShell import PyShell - from OutputWindow import OutputWindow - try: - from configHandler import idleConf - except ImportError: - pass - -brmctx = None -shellwin = None -loadingFiles = 0 -matchwin = None - -class NotHighlightedException(Exception): - pass - -class BicycleRepairMan_Idle: - menudefs = [ - ('bicycleRepairMan', [ - ('----- Queries -----',''), - ('_Find References','<>'), - ('_Find Definition','<>'), - None, - ('--- Refactoring ---',''), - ('_Rename', '<>'), - ('_Extract Method', '<>'), - None, - ('_Undo', '<>'), - ]) - ] - - keydefs = { - '<>':[], - '<>':[], - '<>':[], - '<>':[], - '<>':[], - } - - - try: - TRACE = idleConf.GetOption('extensions','BicycleRepairMan_Idle', - 'trace',default=1) - except NameError: # hasnt imported idleconf - probably python 22 - TRACE = 1 - - - def __init__(self, editwin): - self.editwin = editwin - - if self.TRACE == 1: - self.progressLogger = ProgressLogger(self.editwin.flist) - - if not isinstance(editwin, PyShell): - # sly'ly add the refactor menu to the window - name, label = ("bicycleRepairMan", "_BicycleRepairMan") - underline, label = EditorWindow.prepstr(label) - mbar = editwin.menubar - editwin.menudict[name] = menu = Menu(mbar, name = name) - mbar.add_cascade(label = label, menu = menu, underline = underline) - - # Initialize Bicyclerepairman and import the code - path = self.editwin.io.filename - if path is not None: - global brmctx - if brmctx is None: - self.initbrm() - else: - global shellwin - shellwin = editwin - - - def initbrm(self): - global brmctx - brmctx = bike.init() - if self.TRACE == 1: - brmctx.setProgressLogger(self.progressLogger) - - - def brm_find_references_event(self,event): - try: - if not self.confirm_all_buffers_saved(): - return - - if self.editwin.text.index("sel.first") == "": - self.errorbox("Not highlighted", "Highlight the name of a Function, Class or Method and try again") - return - - filename = os.path.normpath(self.editwin.io.filename) - line, column = string.split(self.editwin.text.index("sel.first"),'.') - - numMatches = 0 - global matchwin - if matchwin is None: - matchwin = BRMMatchesWindow(self.editwin.flist, self) - - matchwin.clear() - - for ref in brmctx.findReferencesByCoordinates(filename,int(line),int(column)): - print >>matchwin, "File \""+ref.filename+"\", line "+str(ref.lineno)+", "+str(ref.confidence)+"% confidence" - numMatches +=1 - - print >>matchwin, numMatches," matches" - print >>matchwin, "(Hint: right-click to open locations.)" - except: - self._handleUnexpectedException() - - - def brm_find_definition_event(self,event): - try: - if not self.confirm_all_buffers_saved(): - return - filename = os.path.normpath(self.editwin.io.filename) - - if self.editwin.text.index("sel.first") != "": - line, column = string.split(self.editwin.text.index("sel.first"),'.') - else: - line, column = string.split(self.editwin.text.index("insert"), '.') - - - defns = brmctx.findDefinitionByCoordinates(filename,int(line), - int(column)) - - try: - - firstref = defns.next() - - editwin = self.editwin.flist.open(firstref.filename) - editwin.gotoline(firstref.lineno) - except StopIteration: - self.errorbox("Couldn't Find definition","Couldn't Find definition") - pass - else: - numRefs = 1 - global matchwin - if matchwin is None: - matchwin = BRMMatchesWindow(self.editwin.flist, self) - - for ref in defns: - if numRefs == 1: - print >>matchwin, firstref.filename+":"+str(firstref.lineno)+": "+str(firstref.confidence)+"% confidence" - - numRefs += 1 - print >>matchwin,ref.filename+":"+str(ref.lineno)+": "+str(ref.confidence)+"% confidence" - if matchwin is not None: - print >>matchwin, "(Hint: right-click to open locations.)" - - except: - self._handleUnexpectedException() - - - def brm_rename_event(self, event): - try: - self.renameItemByCoordinates() - except: - self._handleUnexpectedException() - - def brm_extract_method_event(self, event): - try: - if not self.confirm_all_buffers_saved(): - return - try: - filename, newname, beginline, begincolumn, endline, endcolumn = self._getExtractionInformation("Method") - except NotHighlightedException: - return - brmctx.extractMethod(filename, int(beginline), int(begincolumn), - int(endline), int(endcolumn), newname) - savedfiles = brmctx.save() - self.refreshWindows(savedfiles, beginline) - except: - self._handleUnexpectedException() - - - def brm_undo_event(self, event): - try: - line, column = string.split(self.editwin.text.index("insert"), '.') - brmctx.undo() - savedfiles = brmctx.save() - self.refreshWindows(savedfiles, line) - except UndoStackEmptyException: - self.errorbox("Undo Stack Empty", "Undo Stack is empty") - except: - self._handleUnexpectedException() - - def _handleUnexpectedException(self): - import traceback - traceback.print_exc() - self.errorbox("Caught Exception", "Caught Exception "+str(sys.exc_info()[0])) - - def _getExtractionInformation(self, extracttype): - if self.editwin.text.index("sel.first") == "": - self.errorbox("Code not highlighted", "Highlight the region of code you want to extract and try again") - raise NotHighlightedException() - filename = os.path.normpath(self.editwin.io.filename) - newname = tkSimpleDialog.askstring("Extract Method ", - "New "+extracttype+" Name:", - parent = self.editwin.text) - beginline, begincolumn = string.split(self.editwin.text.index("sel.first"), '.') - endline, endcolumn = string.split(self.editwin.text.index("sel.last"), '.') - return filename, newname, beginline, begincolumn, endline, endcolumn - - - def renameMethodPromptCallback(self, filename, line, colbegin, colend): - - editwin = self.editwin.flist.open(filename) - originaltop = self.editwin.getwindowlines()[0] - - # select the method call and position the window - editwin.text.tag_remove("sel", "1.0", "end") - editwin.text.tag_add("sel", str(line)+"."+str(colbegin), - str(line)+"."+str(colend)) - - line, column = string.split(editwin.text.index("sel.first"), '.') - editwin.text.yview(str(int(line)-2)+".0") - - - d = NoFocusDialog("Rename?", - "Cannot deduce the type of highlighted object reference.\nRename this declaration?", - parent = editwin.text) - - # put the window back where it was - self.editwin.text.yview(float(originaltop)) - return d.answer - - def renameItemByCoordinates(self): - if not self.confirm_all_buffers_saved(): - return - if self.editwin.text.index("sel.first") == "": - self.errorbox("Name not highlighted", "Double click the name of the declaration you want to rename (to highlight it) and try again") - return - - brmctx.setRenameMethodPromptCallback(self.renameMethodPromptCallback) - line, column = string.split(self.editwin.text.index("sel.first"), '.') - filename = os.path.normpath(self.editwin.io.filename) - newname = tkSimpleDialog.askstring("Rename", - "Rename to:", - parent = self.editwin.text) - if newname is None: # cancel clicked - return - brmctx.renameByCoordinates(filename, int(line), int(column), newname) - savedfiles = brmctx.save() - self.refreshWindows(savedfiles, line) - - - - def refreshWindows(self, savedfiles, line): - # refresh editor windows - oldtop = self.editwin.getwindowlines()[0] - - global loadingFiles - loadingFiles = 1 - for sf in savedfiles: - normsf = os.path.normcase(sf) - if normsf in self.editwin.flist.dict: - editwin = self.editwin.flist.dict[normsf] - editwin.io.loadfile(sf) - loadingFiles = 0 - - self.editwin.text.mark_set("insert", float(line)) - self.editwin.text.yview(float(oldtop)) - - - - def confirm_all_buffers_saved(self): - filelist = self.editwin.flist.dict.keys() - for f in filelist: - #editwin = self.editwin.flist.open(f) - editwin = self.editwin.flist.dict[f] - if self.confirm_buffer_is_saved(editwin) == 0: - return 0 - return 1 - - -    def confirm_buffer_is_saved(self, editwin): -        if not editwin.get_saved(): -            name = (editwin.short_title()or -            editwin.long_title()or -            "Untitled") -            reply = tkMessageBox.askokcancel("Bicycle Repair Man", -                "The buffer for %s is not saved.\n\n"%name+ -                "Save it and continue?", -                master = self.editwin.text) -          &nbs p; self.editwin.text.focus_set() -            if reply: -                editwin.io.save(None) -            else: -                return 0 -        return 1 - - def errorbox(self, title, message): - tkMessageBox.showerror(title, message, master = self.editwin.text) - self.editwin.text.focus_set() - - -class BRMTraceWindow(OutputWindow): - def short_title(self): - return "BicycleRepairMan Trace" - -class ProgressLogger: - def __init__(self,flist): - self.flist = flist - - def write(self,txt): - if not hasattr(self,"io"): - self.io = BRMTraceWindow(self.flist) - try: - self.io.write(txt) - self.io.flush() - except IOError: - pass - - -class NoFocusDialog(tkSimpleDialog._QueryDialog): - def __init__(self, title, prompt, - initialvalue = None, - minvalue = None, maxvalue = None, - parent = None): - self.answer = 0 - - if not parent: - import Tkinter - parent = Tkinter._default_root - - self.prompt = prompt - self.minvalue = minvalue - self.maxvalue = maxvalue - - self.initialvalue = initialvalue - - Toplevel.__init__(self, parent) - - if title: - self.title(title) - - self.parent = parent - - self.result = None - - body = Frame(self) - self.initial_focus = self.body(body) - body.pack(padx = 5, pady = 5) - - self.buttonbox() - - self.grab_set() - - self.protocol("WM_DELETE_WINDOW", self.cancel) - - if self.parent is not None: - self.geometry("+%d+%d"%(parent.winfo_rootx()+50, - parent.winfo_rooty()+50)) - self.wait_window(self) - - - def getresult(self): - self.answer = 1 - - def body(self, master): - w = Label(master, text = self.prompt, justify = LEFT) - w.grid(row = 0, padx = 5, sticky = W) - - def buttonbox(self): - box = Frame(self) - - w = Button(box, text = "Yes", width = 10, command = self.ok, default = ACTIVE) - w.pack(side = LEFT, padx = 5, pady = 5) - w = Button(box, text = "No", width = 10, command = self.cancel) - w.pack(side = LEFT, padx = 5, pady = 5) - - self.bind("", self.ok) - self.bind("", self.cancel) - box.pack() - - - - - -class BRMMatchesWindow(OutputWindow): - def __init__(self,flist,masterwin): - OutputWindow.__init__(self,flist) - self.masterwin = masterwin - - def close(self): - global matchwin - matchwin = None - OutputWindow.close(self) - - def short_title(self): - return "BicycleRepairMan Matches" - - def clear(self): - self.text.delete("1.0","end-1c") - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/ChangeLog --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/ChangeLog Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,417 +0,0 @@ -2002-11-23 François Pinard - - * : Release 0.20. - - * Pymacs/__init__.py: Integrate version.py. - * Pymacs/version.py: Deleted. - * setup.py, Pymacs/pymacs.py: Adjusted. - -2002-11-15 François Pinard - - * pymacs.el (pymacs-python-reference): Handle when function is - defined as a mere variable, or when a function is being advised. - -2002-11-14 François Pinard - - * : Release 0.19. - - * Pymacs/pymacs.py (List.__getitem__): Raise IndexError when - out of bounds. This should allow for iterating over a list. - - * README.html: New, merely a template for Webert. - -2002-11-13 François Pinard - - * pymacs.el (pymacs-call): New. Use it whenever adequate. - -2002-09-26 François Pinard - - * Makefile (publish): Revised. - -2002-08-18 François Pinard - - * : Release 0.18. - -2002-08-09 François Pinard - - * Pymacs/rebox.py (Emacs_Rebox.find_comment): Correctly spell - backward_char, not backward-char. - -2002-08-08 François Pinard - - * Pymacs/rebox.py (pymacs_load_hook): Compute the interactions - map from the bound methods, instead of from the generic ones. - -2002-07-14 François Pinard - - * Pymacs/pymacs.py (Lisp_Interface.__call__): Wrap argument in - progn, so lisp() could accept a sequence of expressions. - -2002-07-01 François Pinard - - * pymacs.el (pymacs-start-services): Disable undo for *Pymacs*. - -2002-06-25 François Pinard - - * : Release 0.17. - - * pymacs.py: Deleted, this was the compatibility module. - * setup: Simplified to handle the Emacs Lisp part only. - Deleted -P, -p and -x, as well as compile_python. - - * Makefile: Adjusted. Removed pythondir and pymacsdir. - * pymacs.el (pymacs-load-path): Merely preset to nil. - - * setup: Changes for easing installation on Win32. - Reported by Syver Enstad. - - * Pymacs/pymacs.py (print_lisp): Produce Emacs strings more - explicitly, avoiding hexadecimal sequences generated by Python - 2.2. Those hexadecimal sequences confused Emacs when immediately - followed by more hexadecimal looking characters. - -2002-01-30 François Pinard - - * pymacs.el (pymacs-load-path): Initialise with pymacsdir. - * pymacs-services: Do not handle a patched pymacsdir anymore. - * setup (complete_install): Set pymacsdir for Lisp, not Python. - Do not accept a -b option anymore, do not install pymacs-services, - as this is now to be done through setup.py. - * Makefile (install): Do not use -b while calling setup. - -2002-01-29 François Pinard - - * : Release 0.16. - - * Pymacs/pymacs.py: New file, previously top-level. - * pymacs.py: Now a mere bootstrap for Pymacs/pymacs.py. - * Pymacs/__init__.py: Define lisp and Let. - * Makefile (pythondir): Documentation amended. - * setup: Distinguish between empty arguments, which ask for - autoconfiguration, and None arguments, which inhibit it. - * pymacs-services: Import pymacs from Pymacs. - - * Pymacs/version.py: New file. Rename pymacs to Pymacs. - * setup, setup.py, Pymacs/pymacs.py (main): Use it. - - * setup: Substitute None for pymacsdir instead of the empty string. - * pymacs-services: Adjusted. - - * Pymacs/pymacs.py (Let): Have all push_* methods to return self. - -2002-01-20 François Pinard - - * pymacs.el, pymacs.el: Replace LISP by Lisp in comments. - Reported by Paul Foley. - -2002-01-10 François Pinard - - * : Release 0.15. - - * pymacs.el (pymacs-start-services): Properly diagnose a timeout, - using the timeout parameter value instead of a fixed string. - -2002-01-07 François Pinard - - * : Release 0.14. - - * pymacs.py: Set various __repr__() to yield Python code, - containing the corresponding expanded LISP expression. - Set various __str__() to yield mutable LISP code. - - * pymacs.py (Let): Point markers to nowhere once done with them. - -2002-01-06 François Pinard - - * : Release 0.13. - - * pymacs.el (pymacs-load): Imply prefix correctly when the module - is part of a package, that is, when its name has at least one dot. - * pymacs.py (pymacs_load_helper): Idem. - - * pymacs.py (Protocol): New name for Server. - - * pymacs.py (pymacs_load_helper): Implement pymacs_load_hook. - - * MANIFEST.in, setup.py, Pymacs/__init__.py: New files. - * Makefile: Adjusted and simplified. - -2002-01-03 François Pinard - - * pymacs.py (pymacs_load_helper): Handle module within package. - Reported by Syver Enstad. - -2001-12-18 François Pinard - - * pymacs.bat: New file. - -2001-11-29 François Pinard - - * : Release 0.12. - - * pymacs.el (pymacs-timeout-at-start, pymacs-timeout-at-reply, - pymacs-timeout-at-line): New variables. Use them. - -2001-10-17 François Pinard - - * pymacs.py (pymacs_load_helper): Check the function attribute - before the interactions dictionary, for people having Python 2.x. - Reported by Carel Fellinger. - - * pymacs.el, pymacs.py, pymacs-services: Add the usual GPL notices. - Reported by Richard Stallman. - -2001-10-16 François Pinard - - * : Release 0.11. - - * pymacs.el (pymacs-defuns): Accept interaction specifications. - (pymacs-defun): Process an interaction specification. - (pymacs-python-reference): Adjust for interactive functions. - * pymacs.py (pymacs_load_helper): Transmit interaction specifications. - Reported by Christian Tanzer and Stefan Reichör. - -2001-10-15 François Pinard - - * pymacs.py (pymacs_load_helper): Accept dashed module names. - Reported by Stefan Reichör. - - * pymacs.el (pymacs-python-reference): Rewrite, as it was broken. - (documentation): Say it is a Python function, even if no docstring. - Reported by Stefan Reichör. - -2001-10-12 François Pinard - - * : Release 0.10. - - * pymacs.el (pymacs-print-for-eval): Handle multi-line strings. - Reported by Dave Sellars. - - * pymacs.el (pymacs-print-for-eval): Remove string text properties. - Reported by Eli Zaretskii. - -2001-10-06 François Pinard - - * pymacs.py (Let.__nonzero__): New. - -2001-09-28 François Pinard - - * : Release 0.9. - -2001-09-26 François Pinard - - * pymacs.py (Let.push): Save the value of the symbol, not the - symbol itself. - -2001-09-25 François Pinard - - * : Release 0.8. - - * pymacs.py (Let): New class. - - * pymacs.el: New variable pymacs-use-hash-tables, set to t when - hash tables are available, or nil otherwise. Use it. This is so - older Emacs would work. - Reported by Dirk Vleugels. - -2001-09-21 François Pinard - - * pymacs.el (pymacs-defun): Ensure the function is registered - at definition, not at call time. Otherwise, it would never be - garbage-collected if it is never called. - -2001-09-20 François Pinard - - * : Release 0.7. - - * pymacs.el (pymacs-print-for-apply): Also accept Python objects - for a function, instead of requiring strings. - (pymacs-defun): Use a Python object, not an explicit string reference. - (pymacs-python): Merge pymacs-save-index. - (pymacs-save-index): Deleted. - -2001-09-18 François Pinard - - * pymacs.el (pymacs-load): Accept a noerror argument. - -2001-09-17 François Pinard - - * setup: New script. - * Makefile: Use it. - - * pymacs.py (Symbol.set): Make things simpler when value is None. - - * pymacs.el (pymacs-print-for-eval): Use Python lists to represent - LISP proper lists and Python tuples to represent LISP vectors, - instead of the other way around. - * pymacs.py (pymacs_load_helper, print_lisp): Similar changes. - Reported by John Wiegley. - -2001-09-16 François Pinard - - * : Release 0.6. - - * pymacs.el (pymacs-start-services, pymacs-print-for-eval, - pymacs-round-trip): Protect match data. - -2001-09-15 François Pinard - - * pymacs.el (documentation): Completed. Now into service. - (pymacs-documentation): Deleted. - (pymacs-python-reference): New. - - * pymacs.el (pymacs-print-for-eval): Use car-safe. - -2001-09-14 François Pinard - - * pymacs.el (pymacs-print-for-eval): replace-regexp-in-string does - not exist in older Emacs versions, so use paraphrases. - Reported by Carey Evans. - - * pymacs.el (pymacs-start-services): Set pymacs-transit-buffer - permanently only at end of the function, in case anything fails. - Reported by Carey Evans. - -2001-09-13 François Pinard - - * : Release 0.5. - - * pymacs.el (documentation, pymacs-documentation): New, experimental. - * pymacs.py (doc_string): New. - (pymacs_load_helper): The result should evaluate to the module. - -2001-09-12 François Pinard - - * pymacs.py (pymacs_load_helper): Use reload instead of __import__ - whenever the module was already loaded. - - * pymacs.py (pymacs_load_helper): Return t when there is nothing - to define, instead of returning a noisy pymacs-defuns noop. - - * Makefile (dist): Update a version-less symbolic link. - - * pymacs.el (pymacs-python, pymacs-defun): New functions. - (pymacs-defuns): Use pymacs-defun. - * pymacs.py (print_lisp): Use the above. - - * pymacs.py (Server): Free all accumulated LISP indices, while - replying for another reason. This should decrease overhead. - (Lisp.__del__): Delay freeing LISP, do not free one index at a time. - * pymacs.el (pymacs-free-lisp): Free many indices at once. - - * pymacs.el (pymacs-start-services, pymacs-round-trip): Recognise - reply even when not at beginning of line. The Python module may - print incomplete lines, unrelated to the communication protocol. - -2001-09-11 François Pinard - - * : Release 0.4. - - * pymacs.py (zombie): New, so to get a clear diagnostic. - (zombie_python): Link objects to the above function. - * pymacs.el (pymacs-terminate-services): Ask for confirmation if - any object in LISP space is still in use on the Python side. - * pymacs-test.el (try-lisp): Do not terminate the helper. - - * pymacs.py (Buffer): New class, yet empty for now. - * pymacs.el (pymacs-print-for-eval): Use it. - Reported by Brian McErlean. - - * pymacs.py (Table): New class. - * pymacs.el (pymacs-print-for-eval): Use it. - Reported by Brian McErlean. - - * pymacs.py (List, Vector): New classes, split out of Lisp class. - * pymacs.el (pymacs-print-for-eval): Use them. - (pymacs-lisp-length, pymacs-lisp-ref, pymacs-list-set): Deleted. - Reported by Brian McErlean. - - * pymacs.py (Server.loop): Allow keyboard interrupts through. - - * pymacs.el: Use Lisp instead of Handle. Rename - pymacs-handle-length to pymacs-lisp-length, pymacs-handle-ref to - pymacs-lisp-ref, pymacs-handle-set o pymacs-lisp-set, - pymacs-allocate-handle to pymacs-allocate-lisp and - pymacs-free-handle to pymacs-free-lisp. - - * pymacs.py: Rename Lisp to Lisp_Interface, and Handle to Lisp. - Adjust for other renamings above. - - * pymacs.el: Rename pymacs-id to pymacs-python. Ajust for below. - * pymacs.py: Rename handles to python, free_handles to - free_python, zombie_handles to zombie_python and allocate_handle - to allocate_python. - - * pymacs.el (pymacs-proper-list-p): New function. Use it - everywhere instead of listp, which is not what I thought it was! - - * pymacs.el (pymacs-serve-until-reply): In case of LISP error, - transmit a list of one argument, instead of the argument itself, - to print-for-apply. This was preventing proper diagnostic. - Correct a similar error for when expansion is requested. - - * pymacs.el (pymacs-print-for-eval): Do not transmit a symbol - by its name, when it comes from another oblist than the main one. - - * pymacs.py (print_lisp): Transmit pymacs-id as a dotted pair. - * pymacs.el (pymacs-print-for-eval): Adjusted. - - * pymacs.el (pymacs-print-for-eval): Use lisp[], not sym[]. - Avoid double escaping of the transmitted string in this case. - Reported by Brian McErlean. - -2001-09-10 François Pinard - - * : Release 0.3. - - * pymacs.py (Server.send): Ensure an end of line after reply. - * pymacs.el (pymacs-round-trip): Do not add one after Python replies. - - * pymacs.el (pymacs-round-trip): Check for vanishing helper process. - (pymacs-serve-until-reply): Get text without catching errors, than - eval. Else, protocol errors get reported back to Python. - * pymacs.py (Server.ProtocolError): New. Better than AssertError. - If it occurs, get out of program, do not keep returning errors. - Reported by Carey Evans. - - * pymacs.el (pymacs-round-trip): If point coincides with marker, - just keep it that way as the buffer grows. - - * pymacs.el (pymacs-start-services): If the hash table already - exists, inform the Python side of IDs that it should not reuse. - Otherwise, old lambdas may randomly refer to new Python objects. - (pymacs-terminate-services): Remember Python IDs, do not reset them. - - * pymacs.py (zombie_handles): New. - - * Makefile: Transmit $(pymacsdir) to pymacs-services. - * pymacs-services: Handle it. - - * pymacs.py (print_lisp): Process an empty tuple properly. - Reported by Carey Evans. - - * pymacs.el (pymacs-start-services): With run-at-time, use `20 20' - instead of `t 20', so XEmacs is happy. - Reported by Carey Evans. - - * pymacs.el (pymacs-start-services, pymacs-terminate-services): - Use `post-gc-hook' if available, instead of using a timer. - Reported by Gerd Möllman. - - * pymacs.py (Symbol.value, Symbol.copy): Add argument self. - (print_lisp): Quote symbols if quoted=1. - -2001-09-09 François Pinard - - * pymacs.el (pymacs-defuns): New function. - * pymacs.py: Use it. This should allow faster imports. - - * Makefile, pymacs.el, pymacs.py: Use `(pymacs-version VERSION)', - not `(started)'. Check for version discrepancies. - - * Makefile: A bit more parameterization. - - * : Release 0.2, including ideas and suggestions from others. - Reported by Brian McErlean, Carel Fellinger, Cedric Adjih, - Marcin Qrczak Kowalczyk, Paul Winkler and Steffen Ries. - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/ChangeLog-rebox --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/ChangeLog-rebox Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -2002-01-29 François Pinard - - * Pymacs/rebox.py: Use an interactions map instead of the - interaction attribute, so it works with earlier Python versions. - - * Pymacs/rebox.py: Import lisp and Let from Pymacs. - -2002-01-13 François Pinard - - * Pymacs/rebox.py (Emacs_Rebox.emacs_engine): Expand flag value, - when it is neither the - symbol nor a number. - -2002-01-08 François Pinard - - * Pymacs/rebox.py (Template.build): Subtract margin from width - just before actually rebuilding the box. - Reported by Paul Provost. - -2002-01-07 François Pinard - - * Pymacs/rebox.py (main): Implement -v option. - - * Pymacs/rebox.py (pymacs_load_hook): Declare set_default_style. - - * Pymacs/rebox.py (Emacs_Rebox.clean_undo_after): Debugged. - - * Pymacs/rebox.py (Template): New class. Reorgnise all code. - * Pymacs/rebox.py (engine): Moved out of Rebox class. - * Pymacs/rebox.py (Rebox, Batch_Rebox): Deleted, as they got empty. - - * Pymacs/rebox.py (Emacs_Rebox.clean_undo_after): Rewrite in LISP. - -2002-01-06 François Pinard - - * rebox: New file. - -2002-01-03 François Pinard - - * Pymacs/rebox.py: New file, translated from Libit/rebox.el. - -2000-09-28 François Pinard - - * rebox.el: Replace statistical heuristics for box style recognition - by more precise checks and explicit priorities between styles. To do - so, add weights to rebox-templates, replace rebox-building-data by - rebox-style-data holding regexps, delete rebox-recognition-data. - - * rebox.el (rebox-regexp-ruler): New function. - (rebox-regexp-quote): Add matching for following white space. - Don't force two characters on each middle line, nor in blank rulers. - Reported by Paul Provost. - -2000-04-28 François Pinard - - * rebox.el (rebox-guess-style): When two styles have equal weight, - retain the highest numbered, as it probably is the richest. - Otherwise, simple C++ comments end up with a single slash. - Reported by Akim Demaille. - -2000-04-19 François Pinard - - * rebox.el: Reorganize from bottom-up into top-down. - (taarna-mode): Deleted. - -2000-04-18 François Pinard - - * rebox.el (rebox-show-style, rebox-help-string-for-language, - rebox-help-string-for-quality, rebox-help-string-for-type): Deleted. - (rebox-rstrip, rebox-regexp-quote, rebox-unbuild): New functions. - (rebox-build): New name for rebox-reconstruct. - -2000-04-15 François Pinard - - * rebox.el (rebox-guess-style): New function. - (rebox-engine): Use it. Simplified by using template information. - -2000-04-14 François Pinard - - * rebox.el (rebox-templates): New variable. - (rebox-register-template): New function. - (rebox-reconstruct): Much simplified by using the above. - -2000-04-12 François Pinard - - * rebox.el: Rework the initial documentation block. - (rebox-reconstruct): Guarantee newline at end for style 241. - Reported by Marc Feeley and Paul Provost. - -2000-02-22 François Pinard - - * rebox.el: Little speed cleanup. Avoid looking-at when easy. - -2000-02-10 François Pinard - - * rebox.el: Adjust comment to suggest add-hook instead of setq. - Reported by Akim Demaille. - -2000-01-30 François Pinard - - * rebox.el: Prefer when, unless and cond over if and progn. - Combine successive setq. - - * rebox.el (rebox-engine): Recognise quality for shell boxes. - Reported by Akim Demaille. - -1999-06-30 François Pinard - - * rebox.el: Add GPL comment. - Reported by Paul Eggert. - -1998-03-28 François Pinard - - * rebox.el (rebox-reconstruct): Refill a closing */ with the rest. - Do not add spaces to a line which is otherwise empty. - -1997-12-01 François Pinard - - * rebox.el (rebox-engine): Simplify two regexps, for XEmacs. - Reported by Ulrich Drepper. - -1997-02-17 François Pinard - - * rebox.el (rebox-reconstruct): Ensure indent-tabs-mode is nil. - -1997-02-14 François Pinard - - * rebox.el: Corrected a bug demonstrated as the beginning line - of a paragraph spuriously jumping right spuriously. The full - match of the beginning of comment was replaced by spaces on the - initial line, while only \1 needed replacement. This shortened - this line, causing later nasty effects. - -1996-07-10 François Pinard - - * rebox.el: Recognise style 241, so margin does not get doubled. - Reported by Marc Feeley. - -1996-07-09 François Pinard - - * rebox.el: Use symbolic constants for language, quality and type. - -1996-06-09 François Pinard - - * rebox.el (rebox-find-and-narrow): Take care of a missing end of - line after a comment being at end of buffer. - Reported by Ulrich Drepper. diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/Makefile --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Makefile Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -# Interface between Emacs LISP and Python - Makefile. -# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , 2001. - -# The `README' file provides a few good hints about installation. - -### Start of customisation. -# -# Somewhere on your Emacs LISP load-path. -lispdir = -# -### End of customisation. - -PYSETUP = python setup.py -DISTRIBUTION := $(shell ./setup -V) - -all: - $(PYSETUP) build - -install: all - @./setup -l '$(lispdir)' - $(PYSETUP) install - -tags: - (find bin -type f; find -name '*.py') | grep -v '~$$' | etags - - -dist: - $(PYSETUP) sdist - mv dist/$(DISTRIBUTION).tar.gz . - rmdir dist - ls -l *.gz - -publish: dist - traiter README.html > index.html - chmod 644 index.html $(DISTRIBUTION).tar.gz - scp -p index.html $(DISTRIBUTION).tar.gz bor:w/pymacs/ - rm index.html $(DISTRIBUTION).tar.gz - ssh bor rm -vf w/pymacs/Pymacs.tar.gz - ssh bor ln -vs $(DISTRIBUTION).tar.gz w/pymacs/Pymacs.tar.gz - ssh bor ls -Llt w/pymacs diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/PKG-INFO --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/PKG-INFO Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -Metadata-Version: 1.0 -Name: Pymacs -Version: 0.20 -Summary: Interface between Emacs LISP and Python. -Home-page: http://www.iro.umontreal.ca/~pinard -Author: François Pinard -Author-email: pinard@iro.umontreal.ca -License: UNKNOWN -Description: UNKNOWN -Platform: UNKNOWN diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/.cvsignore --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/.cvsignore Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -*.pyc diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/__init__.py --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/__init__.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# Copyright © 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , 2002. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -"""\ -Interface between Emacs Lisp and Python - Module initialisation. - -A few symbols are moved in here so they appear to be defined at this level. -""" - -from pymacs import Let, lisp - -# Identification of version. - -package = 'Pymacs' -version = '0.20' diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/pymacs.py --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/pymacs.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,587 +0,0 @@ -#!/usr/bin/env python -# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , 2001. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -"""\ -Interface between Emacs Lisp and Python - Python part. - -Emacs may launch this module as a stand-alone program, in which case it -acts as a server of Python facilities for that Emacs session, reading -requests from standard input and writing replies on standard output. - -This module may also be usefully imported by those other Python modules. -See the Pymacs documentation (in `README') for more information. -""" - -## Note: This code is currently compatible down to Python version 1.5.2. -## It is probably worth keeping it that way for a good while, still. - -import os, string, sys, types - -# Python services for Emacs applications. - -def main(*arguments): - """\ -Execute Python services for Emacs, and Emacs services for Python. -This program is meant to be called from Emacs, using `pymacs.el'. - -The program arguments are additional search paths for Python modules. -""" - from Pymacs import version - arguments = list(arguments) - arguments.reverse() - for argument in arguments: - if os.path.isdir(argument): - sys.path.insert(0, argument) - lisp._protocol.send('(pymacs-version "%s")' % version) - lisp._protocol.loop() - -class Protocol: - - # FIXME: The following should work, but does not: - # - # * pymacs.py (Protocol): Declare exceptions as classes, not strings. - # - #class ProtocolError(Exception): pass - #class ReplyException(Exception): pass - #class ErrorException(Exception): pass - # - # I get: - # (pymacs-eval "lisp('\"abc\"').__class__.__name__") - # "ReplyException" - - ProtocolError = 'ProtocolError' - ReplyException = 'ReplyException' - ErrorException = 'ErrorException' - - def __init__(self): - self.freed = [] - - def loop(self): - # The server loop repeatedly receives a request from Emacs and - # returns a response, which is either the value of the received - # Python expression, or the Python traceback if an error occurs - # while evaluating the expression. - - # The server loop may also be executed, as a recursive invocation, - # in the context of Emacs serving a Python request. In which - # case, we might also receive a notification from Emacs telling - # that the reply has been transmitted, or that an error occurred. - # A reply notification from Emacs interrupts the loop: the result - # of this function is the value returned from Emacs. - while 1: - try: - text = self.receive() - if text[:5] == 'exec ': - exec eval(text[5:], {}, {}) - status = 'reply' - argument = None - else: - status = 'reply' - argument = eval(text) - except Protocol.ReplyException, value: - return value - except Protocol.ErrorException, message: - status = 'error' - argument = message - except Protocol.ProtocolError, message: - sys.stderr.write("Protocol error: %s\n" % message) - sys.exit(1) - except KeyboardInterrupt: - raise - except: - import StringIO, traceback - message = StringIO.StringIO() - traceback.print_exc(file=message) - status = 'error' - argument = message.getvalue() - # Send an expression to EMACS applying FUNCTION over ARGUMENT, - # where FUNCTION is `pymacs-STATUS'. - fragments = [] - write = fragments.append - if self.freed: - write('(progn (pymacs-free-lisp') - for index in self.freed: - write(' %d' % index) - write(') ') - write('(pymacs-%s ' % status) - print_lisp(argument, write, quoted=1) - write(')') - if self.freed: - write(')') - self.freed = [] - self.send(string.join(fragments, '')) - - def receive(self): - # Receive a Python expression from Emacs, return its text unevaluated. - text = sys.stdin.read(3) - if not text or text[0] != '>': - raise Protocol.ProtocolError, "`>' expected." - while text[-1] != '\t': - text = text + sys.stdin.read(1) - return sys.stdin.read(int(text[1:-1])) - - def send(self, text): - # Send TEXT to Emacs, which is an expression to evaluate. - if text[-1] == '\n': - sys.stdout.write('<%d\t%s' % (len(text), text)) - else: - sys.stdout.write('<%d\t%s\n' % (len(text) + 1, text)) - sys.stdout.flush() - -def reply(value): - # This function implements the `reply' pseudo-function. - raise Protocol.ReplyException, value - -def error(message): - # This function implements the `error' pseudo-function. - raise Protocol.ErrorException, "Emacs: %s" % message - -def pymacs_load_helper(file_without_extension, prefix): - # This function imports a Python module, then returns a Lisp expression - # which, when later evaluated, will install trampoline definitions in - # Emacs for accessing the Python module facilities. MODULE may be a - # full path, yet without the `.py' or `.pyc' extension, in which case - # the directory is temporarily added to the Python search path for - # the sole duration of that import. All defined symbols on the Lisp - # side have have PREFIX prepended, and have Python underlines in Python - # turned into dashes. If PREFIX is None, it then defaults to the base - # name of MODULE with underlines turned to dashes, followed by a dash. - directory, module_name = os.path.split(file_without_extension) - module_components = string.split(module_name, '.') - if prefix is None: - prefix = string.replace(module_components[-1], '_', '-') + '-' - try: - object = sys.modules.get(module_name) - if object: - reload(object) - else: - try: - if directory: - sys.path.insert(0, directory) - object = __import__(module_name) - finally: - if directory: - del sys.path[0] - # Whenever MODULE_NAME is of the form [PACKAGE.]...MODULE, - # __import__ returns the outer PACKAGE, not the module. - for component in module_components[1:]: - object = getattr(object, component) - except ImportError: - return None - load_hook = object.__dict__.get('pymacs_load_hook') - if load_hook: - load_hook() - interactions = object.__dict__.get('interactions', {}) - if type(interactions) != types.DictType: - interactions = {} - arguments = [] - for name, value in object.__dict__.items(): - if callable(value) and value is not lisp: - arguments.append(allocate_python(value)) - arguments.append(lisp[prefix + string.replace(name, '_', '-')]) - try: - interaction = value.interaction - except AttributeError: - interaction = interactions.get(value) - if callable(interaction): - arguments.append(allocate_python(interaction)) - else: - arguments.append(interaction) - if arguments: - return [lisp.progn, - [lisp.pymacs_defuns, [lisp.quote, arguments]], - object] - return [lisp.quote, object] - -def doc_string(object): - if hasattr(object, '__doc__'): - return object.__doc__ - -# Garbage collection matters. - -# Many Python types do not have direct Lisp equivalents, and may not be -# directly returned to Lisp for this reason. They are rather allocated in -# a list of handles, below, and a handle index is used for communication -# instead of the Python value. Whenever such a handle is freed from the -# Lisp side, its index is added of a freed list for later reuse. - -python = [] -freed_list = [] - -def allocate_python(value): - assert type(value) != type(''), (type(value), `value`) - # Allocate some handle to hold VALUE, return its index. - if freed_list: - index = freed_list[-1] - del freed_list[-1] - python[index] = value - else: - index = len(python) - python.append(value) - return index - -def free_python(*indices): - # Return many handles to the pool. - for index in indices: - python[index] = None - freed_list.append(index) - -def zombie_python(*indices): - # Ensure that some handles are _not_ in the pool. - for index in indices: - while index >= len(python): - freed_list.append(len(python)) - python.append(None) - python[index] = zombie - freed_list.remove(index) - # Merely to make `*Pymacs*' a bit more readable. - freed_list.sort() - -def zombie(*arguments): - error("Object vanished when helper was killed.") - -# Emacs services for Python applications. - -class Let: - - def __init__(self, **keywords): - self.stack = [] - apply(self.push, (), keywords) - - def __del__(self): - while self.stack: - method = self.stack[-1][0] - if method == 'variables': - self.pop() - elif method == 'excursion': - self.pop_excursion() - elif method == 'match_data': - self.pop_match_data() - elif method == 'restriction': - self.pop_restriction() - elif method == 'selected_window': - self.pop_selected_window() - elif method == 'window_excursion': - self.pop_window_excursion() - - def __nonzero__(self): - # So stylistic `if let:' executes faster. - return 1 - - def push(self, **keywords): - pairs = [] - for name, value in keywords.items(): - pairs.append((name, getattr(lisp, name).value())) - setattr(lisp, name, value) - self.stack.append(('variables', pairs)) - return self - - def pop(self): - method, pairs = self.stack[-1] - assert method == 'variables', self.stack[-1] - del self.stack[-1] - for name, value in pairs: - setattr(lisp, name, value) - - def push_excursion(self): - self.stack.append(('excursion', - (lisp.current_buffer(), - lisp.point_marker(), lisp.mark_marker()))) - return self - - def pop_excursion(self): - method, (buffer, point_marker, mark_marker) = self.stack[-1] - assert method == 'excursion', self.stack[-1] - del self.stack[-1] - lisp.set_buffer(buffer) - lisp.goto_char(point_marker) - lisp.set_mark(mark_marker) - lisp.set_marker(point_marker, None) - lisp.set_marker(mark_marker, None) - - def push_match_data(self): - self.stack.append(('match_data', lisp.match_data())) - return self - - def pop_match_data(self): - method, match_data = self.stack[-1] - assert method == 'match_data', self.stack[-1] - del self.stack[-1] - lisp.set_match_data(match_data) - - def push_restriction(self): - self.stack.append(('restriction', - (lisp.point_min_marker(), lisp.point_max_marker()))) - return self - - def pop_restriction(self): - method, (point_min_marker, point_max_marker) = self.stack[-1] - assert method == 'restriction', self.stack[-1] - del self.stack[-1] - lisp.narrow_to_region(point_min_marker, point_max_marker) - lisp.set_marker(point_min_marker, None) - lisp.set_marker(point_max_marker, None) - - def push_selected_window(self): - self.stack.append(('selected_window', lisp.selected_window())) - return self - - def pop_selected_window(self): - method, selected_window = self.stack[-1] - assert method == 'selected_window', self.stack[-1] - del self.stack[-1] - lisp.select_window(selected_window) - - def push_window_excursion(self): - self.stack.append(('window_excursion', - lisp.current_window_configuration())) - return self - - def pop_window_excursion(self): - method, current_window_configuration = self.stack[-1] - assert method == 'window_excursion', self.stack[-1] - del self.stack[-1] - lisp.set_window_configuration(current_window_configuration) - -class Symbol: - - def __init__(self, text): - self.text = text - - def __repr__(self): - return 'lisp[%s]' % repr(self.text) - - def __str__(self): - return '\'' + self.text - - def value(self): - return lisp(self.text) - - def copy(self): - return lisp('(pymacs-expand %s)' % self.text) - - def set(self, value): - if value is None: - lisp('(setq %s nil)' % self.text) - else: - fragments = [] - write = fragments.append - write('(progn (setq %s ' % self.text) - print_lisp(value, write, quoted=1) - write(') nil)') - lisp(string.join(fragments, '')) - - def __call__(self, *arguments): - fragments = [] - write = fragments.append - write('(%s' % self.text) - for argument in arguments: - write(' ') - print_lisp(argument, write, quoted=1) - write(')') - return lisp(string.join(fragments, '')) - -class Lisp: - - def __init__(self, index): - self.index = index - - def __del__(self): - lisp._protocol.freed.append(self.index) - - def __repr__(self): - return ('lisp(%s)' % repr(lisp('(prin1-to-string %s)' % self))) - - def __str__(self): - return '(aref pymacs-lisp %d)' % self.index - - def value(self): - return self - - def copy(self): - return lisp('(pymacs-expand %s)' % self) - -class Buffer(Lisp): - pass - - #def write(text): - # # So you could do things like - # # print >>lisp.current_buffer(), "Hello World" - # lisp.insert(text, self) - - #def point(self): - # return lisp.point(self) - -class List(Lisp): - - def __call__(self, *arguments): - fragments = [] - write = fragments.append - write('(%s' % self) - for argument in arguments: - write(' ') - print_lisp(argument, write, quoted=1) - write(')') - return lisp(string.join(fragments, '')) - - def __len__(self): - return lisp('(length %s)' % self) - - def __getitem__(self, key): - value = lisp('(nth %d %s)' % (key, self)) - if value is None and key >= len(self): - raise IndexError, key - return value - - def __setitem__(self, key, value): - fragments = [] - write = fragments.append - write('(setcar (nthcdr %d %s) ' % (key, self)) - print_lisp(value, write, quoted=1) - write(')') - lisp(string.join(fragments, '')) - -class Table(Lisp): - - def __getitem__(self, key): - fragments = [] - write = fragments.append - write('(gethash ') - print_lisp(key, write, quoted=1) - write(' %s)' % self) - return lisp(string.join(fragments, '')) - - def __setitem__(self, key, value): - fragments = [] - write = fragments.append - write('(puthash ') - print_lisp(key, write, quoted=1) - write(' ') - print_lisp(value, write, quoted=1) - write(' %s)' % self) - lisp(string.join(fragments, '')) - -class Vector(Lisp): - - def __len__(self): - return lisp('(length %s)' % self) - - def __getitem__(self, key): - return lisp('(aref %s %d)' % (self, key)) - - def __setitem__(self, key, value): - fragments = [] - write = fragments.append - write('(aset %s %d ' % (self, key)) - print_lisp(value, write, quoted=1) - write(')') - lisp(string.join(fragments, '')) - -class Lisp_Interface: - - def __init__(self): - self.__dict__['_cache'] = {'nil': None} - self.__dict__['_protocol'] = Protocol() - - def __call__(self, text): - self._protocol.send('(progn %s)' % text) - return self._protocol.loop() - - def __getattr__(self, name): - if name[0] == '_': - raise AttributeError, name - return self[string.replace(name, '_', '-')] - - def __setattr__(self, name, value): - if name[0] == '_': - raise AttributeError, name - self[string.replace(name, '_', '-')] = value - - def __getitem__(self, name): - try: - return self._cache[name] - except KeyError: - symbol = self._cache[name] = Symbol(name) - return symbol - - def __setitem__(self, name, value): - try: - symbol = self._cache[name] - except KeyError: - symbol = self._cache[name] = Symbol(name) - symbol.set(value) - -lisp = Lisp_Interface() - -print_lisp_quoted_specials = {'"': '\\"', '\\': '\\\\', '\b': '\\b', - '\f': '\\f', '\n': '\\n', '\t': '\\t'} - -def print_lisp(value, write, quoted=0): - if value is None: - write('nil') - elif type(value) == types.IntType: - write(repr(value)) - elif type(value) == types.FloatType: - write(repr(value)) - elif type(value) == types.StringType: - write('"') - for character in value: - special = print_lisp_quoted_specials.get(character) - if special is not None: - write(special) - elif 32 <= ord(character) < 127: - write(character) - else: - write('\\%.3o' % ord(character)) - write('"') - elif type(value) == types.ListType: - if quoted: - write("'") - if len(value) == 0: - write('nil') - elif len(value) == 2 and value[0] == lisp.quote: - write("'") - print_lisp(value[1], write) - else: - write('(') - print_lisp(value[0], write) - for sub_value in value[1:]: - write(' ') - print_lisp(sub_value, write) - write(')') - elif type(value) == types.TupleType: - write('[') - if len(value) > 0: - print_lisp(value[0], write) - for sub_value in value[1:]: - write(' ') - print_lisp(sub_value, write) - write(']') - elif isinstance(value, Lisp): - write(str(value)) - elif isinstance(value, Symbol): - if quoted: - write("'") - write(value.text) - elif callable(value): - write('(pymacs-defun %d)' % allocate_python(value)) - else: - write('(pymacs-python %d)' % allocate_python(value)) - -if __name__ == '__main__': - apply(main, sys.argv[1:]) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/rebox.py --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/Pymacs/rebox.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1235 +0,0 @@ -#!/usr/bin/env python -# Copyright © 1991-1998, 2000, 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , April 1991. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -"""\ -Handling of boxed comments in various box styles. - -Introduction ------------- - -For comments held within boxes, it is painful to fill paragraphs, while -stretching or shrinking the surrounding box "by hand", as needed. This piece -of Python code eases my life on this. It may be used interactively from -within Emacs through the Pymacs interface, or in batch as a script which -filters a single region to be reformatted. I find only fair, while giving -all sources for a package using such boxed comments, to also give the -means I use for nicely modifying comments. So here they are! - -Box styles ----------- - -Each supported box style has a number associated with it. This number is -arbitrary, yet by _convention_, it holds three non-zero digits such the the -hundreds digit roughly represents the programming language, the tens digit -roughly represents a box quality (or weight) and the units digit roughly -a box type (or figure). An unboxed comment is merely one of box styles. -Language, quality and types are collectively referred to as style attributes. - -When rebuilding a boxed comment, attributes are selected independently -of each other. They may be specified by the digits of the value given -as Emacs commands argument prefix, or as the `-s' argument to the `rebox' -script when called from the shell. If there is no such prefix, or if the -corresponding digit is zero, the attribute is taken from the value of the -default style instead. If the corresponding digit of the default style -is also zero, than the attribute is recognised and taken from the actual -boxed comment, as it existed before prior to the command. The value 1, -which is the simplest attribute, is ultimately taken if the parsing fails. - -A programming language is associated with comment delimiters. Values are -100 for none or unknown, 200 for `/*' and `*/' as in plain C, 300 for `//' -as in C++, 400 for `#' as in most scripting languages, 500 for `;' as in -LISP or assembler and 600 for `%' as in TeX or PostScript. - -Box quality differs according to language. For unknown languages (100) or -for the C language (200), values are 10 for simple, 20 for rounded, and -30 or 40 for starred. Simple quality boxes (10) use comment delimiters -to left and right of each comment line, and also for the top or bottom -line when applicable. Rounded quality boxes (20) try to suggest rounded -corners in boxes. Starred quality boxes (40) mostly use a left margin of -asterisks or X'es, and use them also in box surroundings. For all others -languages, box quality indicates the thickness in characters of the left -and right sides of the box: values are 10, 20, 30 or 40 for 1, 2, 3 or 4 -characters wide. With C++, quality 10 is not useful, it is not allowed. - -Box type values are 1 for fully opened boxes for which boxing is done -only for the left and right but not for top or bottom, 2 for half -single lined boxes for which boxing is done on all sides except top, -3 for fully single lined boxes for which boxing is done on all sides, -4 for half double lined boxes which is like type 2 but more bold, -or 5 for fully double lined boxes which is like type 3 but more bold. - -The special style 221 is for C comments between a single opening `/*' -and a single closing `*/'. The special style 111 deletes a box. - -Batch usage ------------ - -Usage is `rebox [OPTION]... [FILE]'. By default, FILE is reformatted to -standard output by refilling the comment up to column 79, while preserving -existing boxed comment style. If FILE is not given, standard input is read. -Options may be: - - -n Do not refill the comment inside its box, and ignore -w. - -s STYLE Replace box style according to STYLE, as explained above. - -t Replace initial sequence of spaces by TABs on each line. - -v Echo both the old and the new box styles on standard error. - -w WIDTH Try to avoid going over WIDTH columns per line. - -So, a single boxed comment is reformatted by invocation. `vi' users, for -example, would need to delimit the boxed comment first, before executing -the `!}rebox' command (is this correct? my `vi' recollection is far away). - -Batch usage is also slow, as internal structures have to be reinitialised -at every call. Producing a box in a single style is fast, but recognising -the previous style requires setting up for all possible styles. - -Emacs usage ------------ - -For most Emacs language editing modes, refilling does not make sense -outside comments, one may redefine the `M-q' command and link it to this -Pymacs module. For example, I use this in my `.emacs' file: - - (add-hook 'c-mode-hook 'fp-c-mode-routine) - (defun fp-c-mode-routine () - (local-set-key "\M-q" 'rebox-comment)) - (autoload 'rebox-comment "rebox" nil t) - (autoload 'rebox-region "rebox" nil t) - -with a "rebox.el" file having this single line: - - (pymacs-load "Pymacs.rebox") - -Install Pymacs from `http://www.iro.umontreal.ca/~pinard/pymacs.tar.gz'. - -The Emacs function `rebox-comment' automatically discovers the extent of -the boxed comment near the cursor, possibly refills the text, then adjusts -the box style. When this command is executed, the cursor should be within -a comment, or else it should be between two comments, in which case the -command applies to the next comment. The function `rebox-region' does -the same, except that it takes the current region as a boxed comment. -Both commands obey numeric prefixes to add or remove a box, force a -particular box style, or to prevent refilling of text. Without such -prefixes, the commands may deduce the current box style from the comment -itself so the style is preserved. - -The default style initial value is nil or 0. It may be preset to another -value through calling `rebox-set-default-style' from Emacs LISP, or changed -to anything else though using a negative value for a prefix, in which case -the default style is set to the absolute value of the prefix. - -A `C-u' prefix avoids refilling the text, but forces using the default box -style. `C-u -' lets the user interact to select one attribute at a time. - -Adding new styles ------------------ - -Let's suppose you want to add your own boxed comment style, say: - - //--------------------------------------------+ - // This is the style mandated in our company. - //--------------------------------------------+ - -You might modify `rebox.py' but then, you will have to edit it whenever you -get a new release of `pybox.py'. Emacs users might modify their `.emacs' -file or their `rebox.el' bootstrap, if they use one. In either cases, -after the `(pymacs-load "Pymacs.rebox")' line, merely add: - - (rebox-Template NNN MMM ["//-----+" - "// box " - "//-----+"]) - -If you use the `rebox' script rather than Emacs, the simplest is to make -your own. This is easy, as it is very small. For example, the above -style could be implemented by using this script instead of `rebox': - - #!/usr/bin/env python - import sys - from Pymacs import rebox - rebox.Template(226, 325, ('//-----+', - '// box ', - '//-----+')) - apply(rebox.main, tuple(sys.argv[1:])) - -In all cases, NNN is the style three-digit number, with no zero digit. -Pick any free style number, you are safe with 911 and up. MMM is the -recognition priority, only used to disambiguate the style of a given boxed -comments, when it matches many styles at once. Try something like 400. -Raise or lower that number as needed if you observe false matches. - -On average, the template uses three lines of equal length. Do not worry if -this implies a few trailing spaces, they will be cleaned up automatically -at box generation time. The first line or the third line may be omitted -to create vertically opened boxes. But the middle line may not be omitted, -it ought to include the word `box', which will get replaced by your actual -comment. If the first line is shorter than the middle one, it gets merged -at the start of the comment. If the last line is shorter than the middle -one, it gets merged at the end of the comment and is refilled with it. - -History -------- - -I first observed rounded corners, as in style 223 boxes, in code from -Warren Tucker, a previous maintainer of the `shar' package, circa 1980. - -Except for very special files, I carefully avoided boxed comments for -real work, as I found them much too hard to maintain. My friend Paul -Provost was working at Taarna, a computer graphics place, which had boxes -as part of their coding standards. He asked that we try something to get -him out of his misery, and this how `rebox.el' was originally written. -I did not plan to use it for myself, but Paul was so enthusiastic that I -timidly started to use boxes in my things, very little at first, but more -and more as time passed, still in doubt that it was a good move. Later, -many friends spontaneously started to use this tool for real, some being very -serious workers. This convinced me that boxes are acceptable, after all. - -I do not use boxes much with Python code. It is so legible that boxing -is not that useful. Vertical white space is less necessary, too. I even -avoid white lines within functions. Comments appear prominent enough when -using highlighting editors like Emacs or nice printer tools like `enscript'. - -After Emacs could be extended with Python, in 2001, I translated `rebox.el' -into `rebox.py', and added the facility to use it as a batch script. -""" - -## Note: This code is currently compatible down to Python version 1.5.2. -## It is probably worth keeping it that way for a good while, still. - -## Note: a double hash comment introduces a group of functions or methods. - -import re, string, sys - -def main(*arguments): - refill = 1 - style = None - tabify = 0 - verbose = 0 - width = 79 - import getopt - options, arguments = getopt.getopt(arguments, 'ns:tvw:', ['help']) - for option, value in options: - if option == '--help': - sys.stdout.write(__doc__) - sys.exit(0) - elif option == '-n': - refill = 0 - elif option == '-s': - style = int(value) - elif option == '-t': - tabify = 1 - elif option == '-v': - verbose = 1 - elif option == '-w': - width = int(value) - if len(arguments) == 0: - text = sys.stdin.read() - elif len(arguments) == 1: - text = open(arguments[0]).read() - else: - sys.stderr.write("Invalid usage, try `rebox --help' for help.\n") - sys.exit(1) - old_style, new_style, text, position = engine( - text, style=style, width=width, refill=refill, tabify=tabify) - if text is None: - sys.stderr.write("* Cannot rebox to style %d.\n" % new_style) - sys.exit(1) - sys.stdout.write(text) - if verbose: - if old_style == new_style: - sys.stderr.write("Reboxed with style %d.\n" % old_style) - else: - sys.stderr.write("Reboxed from style %d to %d.\n" - % (old_style, new_style)) - -def pymacs_load_hook(): - global interactions, lisp, Let, region, comment, set_default_style - from Pymacs import lisp, Let - emacs_rebox = Emacs_Rebox() - # Declare functions for Emacs to import. - interactions = {} - region = emacs_rebox.region - interactions[region] = 'P' - comment = emacs_rebox.comment - interactions[comment] = 'P' - set_default_style = emacs_rebox.set_default_style - -class Emacs_Rebox: - - def __init__(self): - self.default_style = None - - def set_default_style(self, style): - """\ -Set the default style to STYLE. -""" - self.default_style = style - - def region(self, flag): - """\ -Rebox the boxed comment in the current region, obeying FLAG. -""" - self.emacs_engine(flag, self.find_region) - - def comment(self, flag): - """\ -Rebox the surrounding boxed comment, obeying FLAG. -""" - self.emacs_engine(flag, self.find_comment) - - def emacs_engine(self, flag, find_limits): - """\ -Rebox text while obeying FLAG. Call FIND_LIMITS to discover the extent -of the boxed comment. -""" - # `C-u -' means that box style is to be decided interactively. - if flag == lisp['-']: - flag = self.ask_for_style() - # If FLAG is zero or negative, only change default box style. - if type(flag) is type(0) and flag <= 0: - self.default_style = -flag - lisp.message("Default style set to %d" % -flag) - return - # Decide box style and refilling. - if flag is None: - style = self.default_style - refill = 1 - elif type(flag) == type(0): - if self.default_style is None: - style = flag - else: - style = merge_styles(self.default_style, flag) - refill = 1 - else: - flag = flag.copy() - if type(flag) == type([]): - style = self.default_style - refill = 0 - else: - lisp.error("Unexpected flag value %s" % flag) - # Prepare for reboxing. - lisp.message("Reboxing...") - checkpoint = lisp.buffer_undo_list.value() - start, end = find_limits() - text = lisp.buffer_substring(start, end) - width = lisp.fill_column.value() - tabify = lisp.indent_tabs_mode.value() is not None - point = lisp.point() - if start <= point < end: - position = point - start - else: - position = None - # Rebox the text and replace it in Emacs buffer. - old_style, new_style, text, position = engine( - text, style=style, width=width, - refill=refill, tabify=tabify, position=position) - if text is None: - lisp.error("Cannot rebox to style %d" % new_style) - lisp.delete_region(start, end) - lisp.insert(text) - if position is not None: - lisp.goto_char(start + position) - # Collapse all operations into a single one, for Undo. - self.clean_undo_after(checkpoint) - # We are finished, tell the user. - if old_style == new_style: - lisp.message("Reboxed with style %d" % old_style) - else: - lisp.message("Reboxed from style %d to %d" - % (old_style, new_style)) - - def ask_for_style(self): - """\ -Request the style interactively, using the minibuffer. -""" - language = quality = type = None - while language is None: - lisp.message("\ -Box language is 100-none, 200-/*, 300-//, 400-#, 500-;, 600-%%") - key = lisp.read_char() - if key >= ord('0') and key <= ord('6'): - language = key - ord('0') - while quality is None: - lisp.message("\ -Box quality/width is 10-simple/1, 20-rounded/2, 30-starred/3 or 40-starred/4") - key = lisp.read_char() - if key >= ord('0') and key <= ord('4'): - quality = key - ord('0') - while type is None: - lisp.message("\ -Box type is 1-opened, 2-half-single, 3-single, 4-half-double or 5-double") - key = lisp.read_char() - if key >= ord('0') and key <= ord('5'): - type = key - ord('0') - return 100*language + 10*quality + type - - def find_region(self): - """\ -Return the limits of the region. -""" - return lisp.point(), lisp.mark(lisp.t) - - def find_comment(self): - """\ -Find and return the limits of the block of comments following or enclosing -the cursor, or return an error if the cursor is not within such a block -of comments. Extend it as far as possible in both directions. -""" - let = Let() - let.push_excursion() - # Find the start of the current or immediately following comment. - lisp.beginning_of_line() - lisp.skip_chars_forward(' \t\n') - lisp.beginning_of_line() - if not language_matcher[0](self.remainder_of_line()): - temp = lisp.point() - if not lisp.re_search_forward('\\*/', None, lisp.t): - lisp.error("outside any comment block") - lisp.re_search_backward('/\\*') - if lisp.point() > temp: - lisp.error("outside any comment block") - temp = lisp.point() - lisp.beginning_of_line() - lisp.skip_chars_forward(' \t') - if lisp.point() != temp: - lisp.error("text before start of comment") - lisp.beginning_of_line() - start = lisp.point() - language = guess_language(self.remainder_of_line()) - # Find the end of this comment. - if language == 2: - lisp.search_forward('*/') - if not lisp.looking_at('[ \t]*$'): - lisp.error("text after end of comment") - lisp.end_of_line() - if lisp.eobp(): - lisp.insert('\n') - else: - lisp.forward_char(1) - end = lisp.point() - # Try to extend the comment block backwards. - lisp.goto_char(start) - while not lisp.bobp(): - if language == 2: - lisp.skip_chars_backward(' \t\n') - if not lisp.looking_at('[ \t]*\n[ \t]*/\\*'): - break - if lisp.point() < 2: - break - lisp.backward_char(2) - if not lisp.looking_at('\\*/'): - break - lisp.re_search_backward('/\\*') - temp = lisp.point() - lisp.beginning_of_line() - lisp.skip_chars_forward(' \t') - if lisp.point() != temp: - break - lisp.beginning_of_line() - else: - lisp.previous_line(1) - if not language_matcher[language](self.remainder_of_line()): - break - start = lisp.point() - # Try to extend the comment block forward. - lisp.goto_char(end) - while language_matcher[language](self.remainder_of_line()): - if language == 2: - lisp.re_search_forward('[ \t]*/\\*') - lisp.re_search_forward('\\*/') - if lisp.looking_at('[ \t]*$'): - lisp.beginning_of_line() - lisp.forward_line(1) - end = lisp.point() - else: - lisp.forward_line(1) - end = lisp.point() - return start, end - - def remainder_of_line(self): - """\ -Return all characters between point and end of line in Emacs buffer. -""" - return lisp('''\ -(buffer-substring (point) (save-excursion (skip-chars-forward "^\n") (point))) -''') - - def clean_undo_after_old(self, checkpoint): - """\ -Remove all intermediate boundaries from the Undo list since CHECKPOINT. -""" - # Declare some LISP functions. - car = lisp.car - cdr = lisp.cdr - eq = lisp.eq - setcdr = lisp.setcdr - # Remove any `nil' delimiter recently added to the Undo list. - cursor = lisp.buffer_undo_list.value() - if not eq(cursor, checkpoint): - tail = cdr(cursor) - while not eq(tail, checkpoint): - if car(tail): - cursor = tail - tail = cdr(cursor) - else: - tail = cdr(tail) - setcdr(cursor, tail) - - def clean_undo_after(self, checkpoint): - """\ -Remove all intermediate boundaries from the Undo list since CHECKPOINT. -""" - lisp(""" -(let ((undo-list %s)) - (if (not (eq buffer-undo-list undo-list)) - (let ((cursor buffer-undo-list)) - (while (not (eq (cdr cursor) undo-list)) - (if (car (cdr cursor)) - (setq cursor (cdr cursor)) - (setcdr cursor (cdr (cdr cursor))))))) - nil) -""" - % (checkpoint or 'nil')) - -def engine(text, style=None, width=79, refill=1, tabify=0, position=None): - """\ -Add, delete or adjust a boxed comment held in TEXT, according to STYLE. -STYLE values are explained at beginning of this file. Any zero attribute -in STYLE indicates that the corresponding attribute should be recovered -from the currently existing box. Produced lines will not go over WIDTH -columns if possible, if refilling gets done. But if REFILL is false, WIDTH -is ignored. If TABIFY is true, the beginning of produced lines will have -spaces replace by TABs. POSITION is either None, or a character position -within TEXT. Returns four values: the old box style, the new box style, -the reformatted text, and either None or the adjusted value of POSITION in -the new text. The reformatted text is returned as None if the requested -style does not exist. -""" - last_line_complete = text and text[-1] == '\n' - if last_line_complete: - text = text[:-1] - lines = string.split(string.expandtabs(text), '\n') - # Decide about refilling and the box style to use. - new_style = 111 - old_template = guess_template(lines) - new_style = merge_styles(new_style, old_template.style) - if style is not None: - new_style = merge_styles(new_style, style) - new_template = template_registry.get(new_style) - # Interrupt processing if STYLE does not exist. - if not new_template: - return old_template.style, new_style, None, None - # Remove all previous comment marks, and left margin. - if position is not None: - marker = Marker() - marker.save_position(text, position, old_template.characters()) - lines, margin = old_template.unbuild(lines) - # Ensure only one white line between paragraphs. - counter = 1 - while counter < len(lines) - 1: - if lines[counter] == '' and lines[counter-1] == '': - del lines[counter] - else: - counter = counter + 1 - # Rebuild the boxed comment. - lines = new_template.build(lines, width, refill, margin) - # Retabify to the left only. - if tabify: - for counter in range(len(lines)): - tabs = len(re.match(' *', lines[counter]).group()) / 8 - lines[counter] = '\t' * tabs + lines[counter][8*tabs:] - # Restore the point position. - text = string.join(lines, '\n') - if last_line_complete: - text = text + '\n' - if position is not None: - position = marker.get_position(text, new_template.characters()) - return old_template.style, new_style, text, position - -def guess_language(line): - """\ -Guess the language in use for LINE. -""" - for language in range(len(language_matcher) - 1, 1, -1): - if language_matcher[language](line): - return language - return 1 - -def guess_template(lines): - """\ -Find the heaviest box template matching LINES. -""" - best_template = None - for template in template_registry.values(): - if best_template is None or template > best_template: - if template.match(lines): - best_template = template - return best_template - -def left_margin_size(lines): - """\ -Return the width of the left margin for all LINES. Ignore white lines. -""" - margin = None - for line in lines: - counter = len(re.match(' *', line).group()) - if counter != len(line): - if margin is None or counter < margin: - margin = counter - if margin is None: - margin = 0 - return margin - -def merge_styles(original, update): - """\ -Return style attributes as per ORIGINAL, in which attributes have been -overridden by non-zero corresponding style attributes from UPDATE. -""" - style = [original / 100, original / 10 % 10, original % 10] - merge = update / 100, update / 10 % 10, update % 10 - for counter in range(3): - if merge[counter]: - style[counter] = merge[counter] - return 100*style[0] + 10*style[1] + style[2] - -def refill_lines(lines, width): - """\ -Refill LINES, trying to not produce lines having more than WIDTH columns. -""" - # Try using GNU `fmt'. - import tempfile, os - name = tempfile.mktemp() - open(name, 'w').write(string.join(lines, '\n') + '\n') - process = os.popen('fmt -cuw %d %s' % (width, name)) - text = process.read() - os.remove(name) - if process.close() is None: - return map(string.expandtabs, string.split(text, '\n')[:-1]) - # If `fmt' failed, do refilling more naively, wihtout using the - # Knuth algorithm, nor protecting full stops at end of sentences. - lines.append(None) - new_lines = [] - new_line = '' - start = 0 - for end in range(len(lines)): - if not lines[end]: - margin = left_margin_size(lines[start:end]) - for line in lines[start:end]: - counter = len(re.match(' *', line).group()) - if counter > margin: - if new_line: - new_lines.append(' ' * margin + new_line) - new_line = '' - indent = counter - margin - else: - indent = 0 - for word in string.split(line): - if new_line: - if len(new_line) + 1 + len(word) > width: - new_lines.append(' ' * margin + new_line) - new_line = word - else: - new_line = new_line + ' ' + word - else: - new_line = ' ' * indent + word - indent = 0 - if new_line: - new_lines.append(' ' * margin + new_line) - new_line = '' - if lines[end] is not None: - new_lines.append('') - start = end + 1 - return new_lines - -class Marker: - - ## Heuristic to simulate a marker while reformatting boxes. - - def save_position(self, text, position, ignorable): - """\ -Given a TEXT and a POSITION in that text, save the adjusted position -by faking that all IGNORABLE characters before POSITION were removed. -""" - ignore = {} - for character in ' \t\r\n' + ignorable: - ignore[character] = None - counter = 0 - for character in text[:position]: - if ignore.has_key(character): - counter = counter + 1 - self.position = position - counter - - def get_position(self, text, ignorable, latest=0): - """\ -Given a TEXT, return the value that would yield the currently saved position, -if it was saved by `save_position' with IGNORABLE. Unless the position lies -within a series of ignorable characters, LATEST has no effect in practice. -If LATEST is true, return the biggest possible value instead of the smallest. -""" - ignore = {} - for character in ' \t\r\n' + ignorable: - ignore[character] = None - counter = 0 - position = 0 - if latest: - for character in text: - if ignore.has_key(character): - counter = counter + 1 - else: - if position == self.position: - break - position = position + 1 - elif self.position > 0: - for character in text: - if ignore.has_key(character): - counter = counter + 1 - else: - position = position + 1 - if position == self.position: - break - return position + counter - -## Template processing. - -class Template: - - def __init__(self, style, weight, lines): - """\ -Digest and register a single template. The template is numbered STYLE, -has a parsing WEIGHT, and is described by one to three LINES. -STYLE should be used only once through all `declare_template' calls. - -One of the lines should contain the substring `box' to represent the comment -to be boxed, and if three lines are given, `box' should appear in the middle -one. Lines containing only spaces are implied as necessary before and after -the the `box' line, so we have three lines. - -Normally, all three template lines should be of the same length. If the first -line is shorter, it represents a start comment string to be bundled within the -first line of the comment text. If the third line is shorter, it represents -an end comment string to be bundled at the end of the comment text, and -refilled with it. -""" - assert not template_registry.has_key(style), \ - "Style %d defined more than once" % style - self.style = style - self.weight = weight - # Make it exactly three lines, with `box' in the middle. - start = string.find(lines[0], 'box') - if start >= 0: - line1 = None - line2 = lines[0] - if len(lines) > 1: - line3 = lines[1] - else: - line3 = None - else: - start = string.find(lines[1], 'box') - if start >= 0: - line1 = lines[0] - line2 = lines[1] - if len(lines) > 2: - line3 = lines[2] - else: - line3 = None - else: - assert 0, "Erroneous template for %d style" % style - end = start + len('box') - # Define a few booleans. - self.merge_nw = line1 is not None and len(line1) < len(line2) - self.merge_se = line3 is not None and len(line3) < len(line2) - # Define strings at various cardinal directions. - if line1 is None: - self.nw = self.nn = self.ne = None - elif self.merge_nw: - self.nw = line1 - self.nn = self.ne = None - else: - if start > 0: - self.nw = line1[:start] - else: - self.nw = None - if line1[start] != ' ': - self.nn = line1[start] - else: - self.nn = None - if end < len(line1): - self.ne = string.rstrip(line1[end:]) - else: - self.ne = None - if start > 0: - self.ww = line2[:start] - else: - self.ww = None - if end < len(line2): - self.ee = line2[end:] - else: - self.ee = None - if line3 is None: - self.sw = self.ss = self.se = None - elif self.merge_se: - self.sw = self.ss = None - self.se = string.rstrip(line3) - else: - if start > 0: - self.sw = line3[:start] - else: - self.sw = None - if line3[start] != ' ': - self.ss = line3[start] - else: - self.ss = None - if end < len(line3): - self.se = string.rstrip(line3[end:]) - else: - self.se = None - # Define parsing regexps. - if self.merge_nw: - self.regexp1 = re.compile(' *' + regexp_quote(self.nw) + '.*$') - elif self.nw and not self.nn and not self.ne: - self.regexp1 = re.compile(' *' + regexp_quote(self.nw) + '$') - elif self.nw or self.nn or self.ne: - self.regexp1 = re.compile( - ' *' + regexp_quote(self.nw) + regexp_ruler(self.nn) - + regexp_quote(self.ne) + '$') - else: - self.regexp1 = None - if self.ww or self.ee: - self.regexp2 = re.compile( - ' *' + regexp_quote(self.ww) + '.*' - + regexp_quote(self.ee) + '$') - else: - self.regexp2 = None - if self.merge_se: - self.regexp3 = re.compile('.*' + regexp_quote(self.se) + '$') - elif self.sw and not self.ss and not self.se: - self.regexp3 = re.compile(' *' + regexp_quote(self.sw) + '$') - elif self.sw or self.ss or self.se: - self.regexp3 = re.compile( - ' *' + regexp_quote(self.sw) + regexp_ruler(self.ss) - + regexp_quote(self.se) + '$') - else: - self.regexp3 = None - # Save results. - template_registry[style] = self - - def __cmp__(self, other): - return cmp(self.weight, other.weight) - - def characters(self): - """\ -Return a string of characters which may be used to draw the box. -""" - characters = '' - for text in (self.nw, self.nn, self.ne, - self.ww, self.ee, - self.sw, self.ss, self.se): - if text: - for character in text: - if character not in characters: - characters = characters + character - return characters - - def match(self, lines): - """\ -Returns true if LINES exactly match this template. -""" - start = 0 - end = len(lines) - if self.regexp1 is not None: - if start == end or not self.regexp1.match(lines[start]): - return 0 - start = start + 1 - if self.regexp3 is not None: - if end == 0 or not self.regexp3.match(lines[end-1]): - return 0 - end = end - 1 - if self.regexp2 is not None: - for line in lines[start:end]: - if not self.regexp2.match(line): - return 0 - return 1 - - def unbuild(self, lines): - """\ -Remove all comment marks from LINES, as hinted by this template. Returns the -cleaned up set of lines, and the size of the left margin. -""" - margin = left_margin_size(lines) - # Remove box style marks. - start = 0 - end = len(lines) - if self.regexp1 is not None: - lines[start] = unbuild_clean(lines[start], self.regexp1) - start = start + 1 - if self.regexp3 is not None: - lines[end-1] = unbuild_clean(lines[end-1], self.regexp3) - end = end - 1 - if self.regexp2 is not None: - for counter in range(start, end): - lines[counter] = unbuild_clean(lines[counter], self.regexp2) - # Remove the left side of the box after it turned into spaces. - delta = left_margin_size(lines) - margin - for counter in range(len(lines)): - lines[counter] = lines[counter][delta:] - # Remove leading and trailing white lines. - start = 0 - end = len(lines) - while start < end and lines[start] == '': - start = start + 1 - while end > start and lines[end-1] == '': - end = end - 1 - return lines[start:end], margin - - def build(self, lines, width, refill, margin): - """\ -Put LINES back into a boxed comment according to this template, after -having refilled them if REFILL. The box should start at column MARGIN, -and the total size of each line should ideally not go over WIDTH. -""" - # Merge a short end delimiter now, so it gets refilled with text. - if self.merge_se: - if lines: - lines[-1] = lines[-1] + ' ' + self.se - else: - lines = [self.se] - # Reduce WIDTH according to left and right inserts, then refill. - if self.ww: - width = width - len(self.ww) - if self.ee: - width = width - len(self.ee) - if refill: - lines = refill_lines(lines, width) - # Reduce WIDTH further according to the current right margin, - # and excluding the left margin. - maximum = 0 - for line in lines: - if line: - if line[-1] in '.!?': - length = len(line) + 1 - else: - length = len(line) - if length > maximum: - maximum = length - width = maximum - margin - # Construct the top line. - if self.merge_nw: - lines[0] = ' ' * margin + self.nw + lines[0][margin:] - start = 1 - elif self.nw or self.nn or self.ne: - if self.nn: - line = self.nn * width - else: - line = ' ' * width - if self.nw: - line = self.nw + line - if self.ne: - line = line + self.ne - lines.insert(0, string.rstrip(' ' * margin + line)) - start = 1 - else: - start = 0 - # Construct all middle lines. - for counter in range(start, len(lines)): - line = lines[counter][margin:] - line = line + ' ' * (width - len(line)) - if self.ww: - line = self.ww + line - if self.ee: - line = line + self.ee - lines[counter] = string.rstrip(' ' * margin + line) - # Construct the bottom line. - if self.sw or self.ss or self.se and not self.merge_se: - if self.ss: - line = self.ss * width - else: - line = ' ' * width - if self.sw: - line = self.sw + line - if self.se and not self.merge_se: - line = line + self.se - lines.append(string.rstrip(' ' * margin + line)) - return lines - -def regexp_quote(text): - """\ -Return a regexp matching TEXT without its surrounding space, maybe -followed by spaces. If STRING is nil, return the empty regexp. -Unless spaces, the text is nested within a regexp parenthetical group. -""" - if text is None: - return '' - if text == ' ' * len(text): - return ' *' - return '(' + re.escape(string.strip(text)) + ') *' - -def regexp_ruler(character): - """\ -Return a regexp matching two or more repetitions of CHARACTER, maybe -followed by spaces. Is CHARACTER is nil, return the empty regexp. -Unless spaces, the ruler is nested within a regexp parenthetical group. -""" - if character is None: - return '' - if character == ' ': - return ' +' - return '(' + re.escape(character + character) + '+) *' - -def unbuild_clean(line, regexp): - """\ -Return LINE with all parenthetical groups in REGEXP erased and replaced by an -equivalent number of spaces, except for trailing spaces, which get removed. -""" - match = re.match(regexp, line) - groups = match.groups() - for counter in range(len(groups)): - if groups[counter] is not None: - start, end = match.span(1 + counter) - line = line[:start] + ' ' * (end - start) + line[end:] - return string.rstrip(line) - -## Template data. - -# Matcher functions for a comment start, indexed by numeric LANGUAGE. -language_matcher = [] -for pattern in (r' *(/\*|//+|#+|;+|%+)', - r'', # 1 - r' */\*', # 2 - r' *//+', # 3 - r' *#+', # 4 - r' *;+', # 5 - r' *%+'): # 6 - language_matcher.append(re.compile(pattern).match) - -# Template objects, indexed by numeric style. -template_registry = {} - -def make_generic(style, weight, lines): - """\ -Add various language digit to STYLE and generate one template per language, -all using the same WEIGHT. Replace `?' in LINES accordingly. -""" - for language, character in ((300, '/'), # C++ style comments - (400, '#'), # scripting languages - (500, ';'), # LISP and assembler - (600, '%')): # TeX and PostScript - new_style = language + style - if 310 < new_style <= 319: - # Disallow quality 10 with C++. - continue - new_lines = [] - for line in lines: - new_lines.append(string.replace(line, '?', character)) - Template(new_style, weight, new_lines) - -# Generic programming language templates. - -make_generic(11, 115, ('? box',)) - -make_generic(12, 215, ('? box ?', - '? --- ?')) - -make_generic(13, 315, ('? --- ?', - '? box ?', - '? --- ?')) - -make_generic(14, 415, ('? box ?', - '???????')) - -make_generic(15, 515, ('???????', - '? box ?', - '???????')) - -make_generic(21, 125, ('?? box',)) - -make_generic(22, 225, ('?? box ??', - '?? --- ??')) - -make_generic(23, 325, ('?? --- ??', - '?? box ??', - '?? --- ??')) - -make_generic(24, 425, ('?? box ??', - '?????????')) - -make_generic(25, 525, ('?????????', - '?? box ??', - '?????????')) - -make_generic(31, 135, ('??? box',)) - -make_generic(32, 235, ('??? box ???', - '??? --- ???')) - -make_generic(33, 335, ('??? --- ???', - '??? box ???', - '??? --- ???')) - -make_generic(34, 435, ('??? box ???', - '???????????')) - -make_generic(35, 535, ('???????????', - '??? box ???', - '???????????')) - -make_generic(41, 145, ('???? box',)) - -make_generic(42, 245, ('???? box ????', - '???? --- ????')) - -make_generic(43, 345, ('???? --- ????', - '???? box ????', - '???? --- ????')) - -make_generic(44, 445, ('???? box ????', - '?????????????')) - -make_generic(45, 545, ('?????????????', - '???? box ????', - '?????????????')) - -# Textual (non programming) templates. - -Template(111, 113, ('box',)) - -Template(112, 213, ('| box |', - '+-----+')) - -Template(113, 313, ('+-----+', - '| box |', - '+-----+')) - -Template(114, 413, ('| box |', - '*=====*')) - -Template(115, 513, ('*=====*', - '| box |', - '*=====*')) - -Template(121, 123, ('| box |',)) - -Template(122, 223, ('| box |', - '`-----\'')) - -Template(123, 323, ('.-----.', - '| box |', - '`-----\'')) - -Template(124, 423, ('| box |', - '\\=====/')) - -Template(125, 523, ('/=====\\', - '| box |', - '\\=====/')) - -Template(141, 143, ('| box ',)) - -Template(142, 243, ('* box *', - '*******')) - -Template(143, 343, ('*******', - '* box *', - '*******')) - -Template(144, 443, ('X box X', - 'XXXXXXX')) - -Template(145, 543, ('XXXXXXX', - 'X box X', - 'XXXXXXX')) -# C language templates. - -Template(211, 118, ('/* box */',)) - -Template(212, 218, ('/* box */', - '/* --- */')) - -Template(213, 318, ('/* --- */', - '/* box */', - '/* --- */')) - -Template(214, 418, ('/* box */', - '/* === */')) - -Template(215, 518, ('/* === */', - '/* box */', - '/* === */')) - -Template(221, 128, ('/* ', - ' box', - '*/')) - -Template(222, 228, ('/* .', - '| box |', - '`----*/')) - -Template(223, 328, ('/*----.', - '| box |', - '`----*/')) - -Template(224, 428, ('/* \\', - '| box |', - '\\====*/')) - -Template(225, 528, ('/*====\\', - '| box |', - '\\====*/')) - -Template(231, 138, ('/* ', - ' | box', - ' */ ')) - -Template(232, 238, ('/* ', - ' | box | ', - ' *-----*/')) - -Template(233, 338, ('/*-----* ', - ' | box | ', - ' *-----*/')) - -Template(234, 438, ('/* box */', - '/*-----*/')) - -Template(235, 538, ('/*-----*/', - '/* box */', - '/*-----*/')) - -Template(241, 148, ('/* ', - ' * box', - ' */ ')) - -Template(242, 248, ('/* * ', - ' * box * ', - ' *******/')) - -Template(243, 348, ('/******* ', - ' * box * ', - ' *******/')) - -Template(244, 448, ('/* box */', - '/*******/')) - -Template(245, 548, ('/*******/', - '/* box */', - '/*******/')) - -Template(251, 158, ('/* ', - ' * box', - ' */ ')) - -if __name__ == '__main__': - apply(main, sys.argv[1:]) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/README --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/README Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1030 +0,0 @@ -* README for `Pymacs' allout -*- outline -*- - - `http://www.iro.umontreal.ca/~pinard/pymacs/' contains a copy of this - `README' file in HTML form. The canonical Pymacs distribution is - available as `http://www.iro.umontreal.ca/~pinard/pymacs/Pymacs.tar.gz'. - Report problems and suggestions to `mailto:pinard@iro.umontreal.ca'. - -.. Presentation. - -. : What is Pymacs? - - Pymacs is a powerful tool which, once started from Emacs, allows both-way - communication between Emacs Lisp and Python. Yet, Pymacs aims Python as - an extension language for Emacs rather than the other way around; this - assymetry is reflected in some design choices. Within Emacs Lisp code, - one may load and use Python modules. Python functions may themselves use - Emacs services, and handle Emacs Lisp objects kept in Emacs Lisp space. - - The goals are to write "naturally" in both languages, debug with ease, - fall back gracefully on errors, and allow full cross-recursivity. - - It is very easy to install Pymacs, as neither Emacs nor Python need to - be compiled nor relinked. Emacs merely starts Python as a subprocess, - and Pymacs implements a communication protocol between both processes. - -. : Warning to Pymacs users. - - I expect average Pymacs users to have a deeper knowledge of Python - than Emacs Lisp. Some examples at the end of this file are meant - for Python users having a limited experience with the Emacs API. - Currently, there are only contains two examples, one is too small, - the other is too big :-). As there is no dedicated mailing list nor - discussion group for Pymacs, let's use `python-list@python.org' for - asking questions or discussing Pymacs related matters. - - This is beta status software: specifications are slightly frozen, yet - changes may still happen that would require small adaptations in your - code. Report problems to François Pinard at `pinard@iro.umontreal.ca'. - For discussing specifications or making suggestions, please also copy - the `python-list@python.org' mailing list, to help brain-storming! :-) - -. : History and references. - - I once starved for a Python-extensible editor, and pondered the idea of - dropping Emacs for other avenues, but found nothing much convincing. - Moreover, looking at all LISP extensions I wrote for myself, and - considering all those superb tools written by others and that became - part of my computer life, it would have been a huge undertaking for - me to reprogram these all in Python. So, when I began to see that - something like Pymacs was possible, I felt strongly motivated! :-) - - Pymacs revisits previous Cedric Adjih's works about running Python as a - process separate from Emacs. See `http://www.crepuscule.com/pyemacs/', - or write Cedric at `adjih-pam@crepuscule.com'. Cedric presented - `pyemacs' to me as a proof of concept. As I simplified that concept - a bit, I dropped the `e' in `pyemacs' :-). Cedric also told me that - there exist some older patches for linking Python right into XEmacs. - - Brian McErlean independently and simultaneously wrote a tool similar - to this one, we decided to join our projects. Amusing coincidence, he - even chose `pymacs' as a name. Brian paid good attention to complex - details that escaped my courage, so his help and collaboration have - been beneficial. You may reach Brian at `brianmce@crosswinds.net'. - - One other reference of interest is Doug Bagley shoot out project, - which compares the relative speed of many popular languages. - See `http://www.bagley.org/~doug/shootout/' for more information. - -.. Installation. - -. : Install the Pymacs proper. - - Currently, there are two installation scripts, and both should be run. - If you prefer, you may use `make install lispdir=LISPDIR', where - LISPDIR is some directory along the list kept in your Emacs `load-path'. - - The first installation script installs the Python package, including the - Pymacs examples, using the Python standard Distutils tool. Merely `cd' - into the Pymacs distribution, then execute `python setup.py install'. - To get an option reminder, do `python setup.py install --help'. Check - the Distutils documentation if you need more information about this. - - The second installation script installs the Emacs Lisp part only. - (It used to do everything, but is now doomed to disappear completely.) - Merely `cd' into the Pymacs distribution, then run `python setup -ie'. - This will invite you to interactively confirm the Lisp installation - directory. Without `-ie', the Lisp part of Pymacs will be installed - in some automatically guessed place. Use `-n' to known about the guess - without proceeding to the actual installation. `./setup -E xemacs ...' - may be useful to XEmacs lovers. See `./setup -H' for all options. - - About Win32 systems, Syver Enstad says: "For Pymacs to operate correctly, - one should create a batch file with `pymacs-services.bat' as a name, - which runs the `pymacs-services' script. The `.bat' file could be - placed along with `pymacs-services', wherever that maybe.". - - To check that `pymacs.el' is properly installed, start Emacs and give - it the command `M-x load-library RET pymacs': you should not receive - any error. To check that `pymacs.py' is properly installed, start - an interactive Python session and type `from Pymacs import lisp': - you should not receive any error. To check that `pymacs-services' - is properly installed, type `pymacs-services ' expected.". - - Currently, there is only one installed Pymacs example, which comes - in two parts: a batch script `rebox' and a `Pymacs.rebox' module. - To check that both are properly installed, type `rebox '). - - To bind the F1 key to the `helper' function in some `module': - - lisp.global_set_key((lisp.f1,), lisp.module_helper) - - (item,) is a Python tuple yielding an Emacs Lisp vector. `lisp.f1' - translates to the Emacs Lisp symbol `f1'. So, Python `(lisp.f1,)' is - Emacs Lisp `[f1]'. Keys like `[M-f2]' might require some more ingenuity, - one may write either (lisp['M-f2'],) or (lisp.M_f2,) on the Python side. - -.. Debugging. - -. : The `*Pymacs*' buffer. - - Emacs and Python are two separate processes (well, each may use more - than one process). Pymacs implements a simple communication protocol - between both, and does whatever needed so the programmers do not have - to worry about details. The main debugging tool is the communication - buffer between Emacs and Python, which is named `*Pymacs*'. To make - good use of it, first set `pymacs-trace-transit' to `t', so all - exchanges are accumulated in that buffer. As it is sometimes helpful - to understand the communication protocol, it is briefly explained here, - using an artificially complex example to do so. Consider: - - ----------------------------------------------------------------------> - (pymacs-eval "lisp('(pymacs-eval \"`2L**111`\")')") - "2596148429267413814265248164610048L" - ----------------------------------------------------------------------< - - Here, Emacs asks Python to ask Emacs to ask Python for a simple bignum - computation. Note that Emacs does not natively know how to handle big - integers, nor has an internal representation for them. This is why I - use backticks, so Python returns a string representation of the result, - instead of the result itself. Here is a trace for this example. The `<' - character flags a message going from Python to Emacs and is followed - by an expression written in Emacs Lisp. The '>' character flags a - message going from Emacs to Python and is followed by a expression - written in Python. The number gives the length of the message. - - ----------------------------------------------------------------------> - <22 (pymacs-version "0.3") - >49 eval("lisp('(pymacs-eval \"`2L**111`\")')") - <25 (pymacs-eval "`2L**111`") - >18 eval("`2L**111`") - <47 (pymacs-reply "2596148429267413814265248164610048L") - >45 reply("2596148429267413814265248164610048L") - <47 (pymacs-reply "2596148429267413814265248164610048L") - ----------------------------------------------------------------------< - - Python evaluation is done in the context of the `Pymacs.pymacs' module, - so for example a mere `reply' really means `Pymacs.pymacs.reply'. On the - Emacs Lisp side, there is no concept of module namespaces, so we use - the `pymacs-' prefix as an attempt to stay clean. Users should ideally - refrain from naming their Emacs Lisp objects with a `pymacs-' prefix. - - `reply' and `pymacs-reply' are special functions meant to indicate that - an expected result is finally transmitted. `error' and `pymacs-error' - are special functions that introduce a string which explains an exception - which recently occurred. `pymacs-expand' is a special function - implementing the `copy()' methods of Emacs Lisp handles or symbols. - In all other cases, the expression is a request for the other side, - that request stacks until a corresponding reply is received. - - Part of the protocol manages memory, and this management generates - some extra-noise in the `*Pymacs*' buffer. Whenever Emacs passes a - structure to Python, an extra pointer is generated on the Emacs side to - inhibit garbage collection by Emacs. Python garbage collector detects - when the received structure is no longer needed on the Python side, - at which time the next communication will tell Emacs to remove the - extra pointer. It works symmetrically as well, that is, whenever Python - passes a structure to Emacs, an extra Python reference is generated to - inhibit garbage collection on the Python side. Emacs garbage collector - detects when the received structure is no longer needed on the Emacs - side, after which Python will be told to remove the extra reference. - For efficiency, those allocation-related messages are delayed, merged and - batched together within the next communication having another purpose. - -. : Emacs usual debugging. - - If cross-calls between Emacs Lisp and Python nest deeply, an error will - raise successive exceptions alternatively on both sides as requests - unstack, and the diagnostic gets transmitted back and forth, slightly - growing as we go. So, errors will eventually be reported by Emacs. - I made no kind of effort to transmit the Emacs Lisp backtrace on the - Python side, as I do not see a purpose for it: all debugging is done - within Emacs windows anyway. - - On recent Emacses, the Python backtrace gets displayed in the - mini-buffer, and the Emacs Lisp backtrace is simultaneously shown in the - `*Backtrace*' window. One useful thing is to allow to mini-buffer to - grow big, so it has more chance to fully contain the Python backtrace, - the last lines of which are often especially useful. Here, I use: - - (setq resize-mini-windows t - max-mini-window-height .85) - - in my `.emacs' file, so the mini-buffer may use 85% of the screen, - and quickly shrinks when fewer lines are needed. The mini-buffer - contents disappear at the next keystroke, but you can recover the - Python backtrace by looking at the end of the `*Messages*' buffer. - In which case the `ffap' package in Emacs may be yet another friend! - From the `*Messages*' buffer, once `ffap' activated, merely put the - cursor on the file name of a Python module from the backtrace, and - `C-x C-f RET' will quickly open that source for you. - -. : Auto-reloading on save. - - I found useful to automatically `pymacs-load' some Python files whenever - they get saved from Emacs. Here is how I do it. The code below assumes - that Python files meant for Pymacs are kept in `~/share/emacs/python'. - - (defun fp-maybe-pymacs-reload () - (let ((pymacsdir (expand-file-name "~/share/emacs/python/"))) - (when (and (string-equal (file-name-directory buffer-file-name) - pymacsdir) - (string-match "\\.py\\'" buffer-file-name)) - (pymacs-load (substring buffer-file-name 0 -3))))) - (add-hook 'after-save-hook 'fp-maybe-pymacs-reload) - -.. Exemples. - -. : Paul Winkler's. - -. , The problem. - - Let's say I have a a module, call it `manglers.py', containing this - simple python function: - - def break_on_whitespace(some_string): - words = some_string.split() - return '\n'.join(words) - - The goal is telling Emacs about this function so that I can call it on - a region of text and replace the region with the result of the call. - And bind this action to a key, of course, let's say `[f7]'. - - The Emacs buffer ought to be handled in some way. If this is not on the - Emacs Lisp side, it has to be on the Python side, but we cannot escape - handling the buffer. So, there is an equilibrium in the work to do for - the user, that could be displaced towards Emacs Lisp or towards Python. - -. , Python side. - - Here is a first draft for the Python side of the problem: - - from Pymacs import lisp - - def break_on_whitespace(): - start = lisp.point() - end = lisp.mark(lisp.t) - if start > end: - start, end = end, start - text = lisp.buffer_substring(start, end) - words = text.split() - replacement = '\n'.join(words) - lisp.delete_region(start, end) - lisp.insert(replacement) - - interactions = {break_on_whitespace: ''} - - For various stylistic reasons, this could be rewritten into: - - from Pymacs import lisp - interactions = {} - - def break_on_whitespace(): - start, end = lisp.point(), lisp.mark(lisp.t) - words = lisp.buffer_substring(start, end).split() - lisp.delete_region(start, end) - lisp.insert('\n'.join(words)) - - interactions[break_on_whitespace] = '' - - The above relies, in particular, on the fact that for those Emacs - Lisp functions used here, `start' and `end' may be given in any order. - -. , Emacs side. - - On the Emacs side, one would do: - - (pymacs-load "manglers") - (global-set-key [f7] 'manglers-break-on-whitespace) - -. : The `rebox' tool. - -. , The problem. - - For comments held within boxes, it is painful to fill paragraphs, while - stretching or shrinking the surrounding box "by hand", as needed. - This piece of Python code eases my life on this. It may be used - interactively from within Emacs through the Pymacs interface, or in - batch as a script which filters a single region to be reformatted. - - In batch, the reboxing is driven by command options and arguments - and expects a complete, self-contained boxed comment from a file. - Emacs function `rebox-region' also presumes that the region encloses - a single boxed comment. Emacs `rebox-comment' is different, as it - has to chase itself the extent of the surrounding boxed comment. - -. , Python side. - - The Python code is too big to be inserted in this documentation: see - file `Pymacs/rebox.py' in the Pymacs distribution. You will observe - in the code that Pymacs specific features are used exclusively from - within the `pymacs_load_hook' function and the `Emacs_Rebox' class. - In batch mode, `Pymacs' is not even imported. Here, we mean to - discuss some of the design choices in the context of Pymacs. - - In batch mode, as well as with `rebox-region', the text to handle is - turned over to Python, and fully processed in Python, with practically - no Pymacs interaction while the work gets done. On the other hand, - `rebox-comment' is rather Pymacs intensive: the comment boundaries - are chased right from the Emacs buffer, as directed by the function - `Emacs_Rebox.find_comment'. Once the boundaries are found, the - remainder of the work is essentially done on the Python side. - - Once the boxed comment has been reformatted in Python, the old comment - is removed in a single delete operation, the new comment is inserted in - a second operation, this occurs in `Emacs_Rebox.process_emacs_region'. - But by doing so, if point was within the boxed comment before the - reformatting, its precise position is lost. To well preserve point, - Python might have driven all reformatting details directly in the - Emacs buffer. We really preferred doing it all on the Python side: - as we gain legibility by expressing the algorithms in pure Python, - the same Python code may be used in batch or interactively, and we - avoid the slowdown that would result from heavy use of Emacs services. - - To avoid completely loosing point, I kludged a `Marker' class, - which goal is to estimate the new value of point from the old. - Reformatting may change the amount of white space, and either delete - or insert an arbitrary number characters meant to draw the box. - The idea is to initially count the number of characters between the - beginning of the region and point, while ignoring any problematic - character. Once the comment has been reboxed, point is advanced from - the beginning of the region until we get the same count of characters, - skipping all problematic characters. This `Marker' class works fully - on the Python side, it does not involve Pymacs at all, but it does - solve a problem that resulted from my choice of keeping the data on - the Python side instead of handling it directly in the Emacs buffer. - - We want a comment reformatting to appear as a single operation, in - the context of Emacs Undo. The method `Emacs_Rebox.clean_undo_after' - handles the general case for this. Not that we do so much in practice: - a reformatting implies one `delete-region' and one `insert', and maybe - some other little adjustements at `Emacs_Rebox.find_comment' time. - Even if this method scans and mofifies an Emacs Lisp list directly in - the Emacs memory, the code doing this stays neat and legible. However, - I found out that the undo list may grow quickly when the Emacs buffer - use markers, with the consequence of making this routine so Pymacs - intensive that most of the CPU is spent there. I rewrote that - routine in Emacs Lisp so it executes in a single Pymacs interaction. - - Function `Emacs_Rebox.remainder_of_line' could have been written in - Python, but it was probably not worth going away from this one-liner in - Emacs Lisp. Also, given this routine is often called by `find_comment', - a few Pymacs protocol interactions are spared this way. This function - is useful when there is a need to apply a regexp already compiled on - the Python side, it is probably better fetching the line from Emacs - and do the pattern match on the Python side, than transmitting the - source of the regexp to Emacs for it to compile and apply it. - - For refilling, I could have either used the refill algorithm built - within in Emacs, programmed a new one in Python, or relied on Ross - Paterson's `fmt', distributed by GNU and available on most Linuxes. - In fact, `refill_lines' prefers the latter. My own Emacs setup is - such that the built-in refill algorithm is _already_ overridden by GNU - `fmt', and it really does a much better job. Experience taught me - that calling an external program is fast enough to be very bearable, - even interactively. If Python called Emacs to do the refilling, Emacs - would itself call GNU `fmt' in my case, I preferred that Python calls - GNU `fmt' directly. I could have reprogrammed GNU `fmt' in Python. - Despite interesting, this is an uneasy project: `fmt' implements - the Knuth refilling algorithm, which depends on dynamic programming - techniques; Ross fine tuned them, and took care of many details. - If GNU `fmt' fails, for not being available, say, `refill_lines' - falls back on a dumb refilling algorithm, which is better than none. - -. , Emacs side. - - The Emacs recipe appears under the `Emacs usage' section, near the - beginning of `Pymacs/rebox.py', so I do not repeat it here. - -.. - François Pinard, - pinard@iro.umontreal.ca diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/README.html --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/README.html Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ - - - - %(title)s - -%(text)s - - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/THANKS --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/THANKS Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -Pymacs has been written by François Pinard after an idea from Cedric Adjih, -and much influenced by Brian McErlean. Here is the list of contributors. - -Brian McErlean b.mcerlean@kainos.com -Carel Fellinger cfelling@iae.nl -Carey Evans careye@spamcop.net -Cedric Adjih adjih-pam@crepuscule.com - http://www.crepuscule.com/pyemacs/ -Christian Tanzer tanzer@swing.co.at -Dave Sellars dsellars@windriver.com -Dirk Vleugels dvl@2scale.net -Eli Zaretskii eliz@is.elta.co.il -François Pinard pinard@iro.umontreal.ca - http://www.iro.umontreal.ca/~pinard -Gerd Möllmann gerd@gnu.org -John Wiegley johnw@gnu.org -Marcin Qrczak Kowalczyk qrczak@knm.org.pl -Paul Foley mycroft@actrix.gen.nz - http://users.actrix.co.nz/mycroft/ -Paul Winkler slinkp23@yahoo.com -Richard Stallman rms@gnu.org -Stefan Reichör xsteve@riic.at -Steffen Ries steffen.ries@sympatico.ca -Syver Enstad syver.enstad@asker.online.no diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/THANKS-rebox --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/THANKS-rebox Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -`rebox' has been written by François Pinard. Here is the list of -contributors. Also see `ChangeLog-rebox' for a more details. - -Akim Demaille demaille@inf.enst.fr -Marc Feeley feeley@iro.umontreal.ca -Paul Eggert eggert@twinsun.com -Paul Provost provost@virtualprototypes.ca -Ulrich Drepper drepper@gnu.org diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/TODO --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/TODO Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -* TODO for `Pymacs' allout -*- outline -*- - -.. Internal cleanup. - -. : `(pymacs-eval "dir()")' shows too many things. - -.. Type conversions. - -. : Convert LISP hash tables into Python dicts and vice-versa. - -.. Iterator protocol. - -. : Allow iterating over vectors. - -.. Rebox. - -. : Debug the Undo list cleanup! - -. : Try the fall back refiller. - -. : Unicode boxes (suggested by Bruno). -. , U+231C..U+231F -. , U+25xx - -.. Debugging facilities. - -. : *Pymacs* -. , Indent. -. , Interpret numbers. -. , Highlight. - -. : Test suite. (Brian has one.) - -. : Python shell link to helper. diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs-services --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs-services Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , 2001. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -"""\ -Interface between Emacs LISP and Python - Python process starter. - -This small bootstrap is so Pymacs modules can be kept in compiled form. -""" - -import sys -from Pymacs import pymacs -apply(pymacs.main, sys.argv[1:]) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs-services.bat --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs-services.bat Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -@python "%~dpn0" %* diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs.el --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/pymacs.el Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,631 +0,0 @@ -;;; Interface between Emacs Lisp and Python - Lisp part. -;;; Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc. -;;; François Pinard , 2001. - -;;; This program is free software; you can redistribute it and/or modify -;;; it under the terms of the GNU General Public License as published by -;;; the Free Software Foundation; either version 2, or (at your option) -;;; any later version. -;;; -;;; This program is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;;; GNU General Public License for more details. -;;; -;;; You should have received a copy of the GNU General Public License -;;; along with this program; if not, write to the Free Software Foundation, -;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -;;; See the Pymacs documentation (in `README') for more information. - -;;; Published functions. - -(defvar pymacs-load-path nil - "List of additional directories to search for Python modules. -The directories listed will be searched first, in the order given.") - -(defvar pymacs-trace-transit nil - "Keep the communication buffer growing, for debugging. -When this variable is nil, the `*Pymacs*' communication buffer gets erased -before each communication round-trip. Setting it to `t' guarantees that -the full communication is saved, which is useful for debugging.") - -(defvar pymacs-forget-mutability nil - "Transmit copies to Python instead of Lisp handles, as much as possible. -When this variable is nil, most mutable objects are transmitted as handles. -This variable is meant to be temporarily rebound to force copies.") - -(defvar pymacs-mutable-strings nil - "Prefer transmitting Lisp strings to Python as handles. -When this variable is nil, strings are transmitted as copies, and the -Python side thus has no way for modifying the original Lisp strings. -This variable is ignored whenever `forget-mutability' is set.") - -(defvar pymacs-timeout-at-start 30 - "Maximum reasonable time, in seconds, for starting `pymacs-services'. -A machine should be pretty loaded before one needs to increment this.") - -(defvar pymacs-timeout-at-reply 5 - "Expected maximum time, in seconds, to get the first line of a reply. -The status of `pymacs-services' is checked at every such timeout.") - -(defvar pymacs-timeout-at-line 2 - "Expected maximum time, in seconds, to get another line of a reply. -The status of `pymacs-services' is checked at every such timeout.") - -(defun pymacs-load (module &optional prefix noerror) - "Import the Python module named MODULE into Emacs. -Each function in the Python module is made available as an Emacs function. -The Lisp name of each function is the concatenation of PREFIX with -the Python name, in which underlines are replaced by dashes. If PREFIX is -not given, it defaults to MODULE followed by a dash. -If NOERROR is not nil, do not raise error when the module is not found." - (interactive - (let* ((module (read-string "Python module? ")) - (default (concat (car (last (split-string module "\\."))) "-")) - (prefix (read-string (format "Prefix? [%s] " default) - nil nil default))) - (list module prefix))) - (message "Pymacs loading %s..." module) - (let ((lisp-code (pymacs-call "pymacs_load_helper" module prefix))) - (cond (lisp-code (let ((result (eval lisp-code))) - (message "Pymacs loading %s...done" module) - result)) - (noerror (message "Pymacs loading %s...failed" module) nil) - (t (error "Pymacs loading %s...failed" module))))) - -(defun pymacs-eval (text) - "Compile TEXT as a Python expression, and return its value." - (interactive "sPython expression? ") - (let ((value (pymacs-call "eval" text))) - (when (interactive-p) - (message "%S" value)) - value)) - -(defun pymacs-exec (text) - "Compile and execute TEXT as a sequence of Python statements. -This functionality is experimental, and does not appear to be useful." - (interactive "sPython statements? ") - (let ((value (pymacs-serve-until-reply - `(progn (princ "exec ") (prin1 ,text))))) - (when (interactive-p) - (message "%S" value)) - value)) - -(defun pymacs-call (function &rest arguments) - "Return the result of calling a Python function FUNCTION over ARGUMENTS. -FUNCTION is a string denoting the Python function, ARGUMENTS are separate -Lisp expressions, one per argument. Immutable Lisp constants are converted -to Python equivalents, other structures are converted into Lisp handles." - (pymacs-apply function arguments)) - -(defun pymacs-apply (function arguments) - "Return the result of calling a Python function FUNCTION over ARGUMENTS. -FUNCTION is a string denoting the Python function, ARGUMENTS is a list of -Lisp expressions. Immutable Lisp constants are converted to Python -equivalents, other structures are converted into Lisp handles." - (pymacs-serve-until-reply `(pymacs-print-for-apply ',function ',arguments))) - -;;; Integration details. - -;; Python functions and modules should ideally look like Lisp functions and -;; modules. This page tries to increase the integration seamlessness. - -(defadvice documentation (around pymacs-ad-documentation activate) - ;; Integration of doc-strings. - (let* ((reference (pymacs-python-reference function)) - (python-doc (when reference - (pymacs-eval (format "doc_string(%s)" reference))))) - (if (or reference python-doc) - (setq ad-return-value - (concat - "It interfaces to a Python function.\n\n" - (when python-doc - (if raw python-doc (substitute-command-keys python-doc))))) - ad-do-it))) - -(defun pymacs-python-reference (object) - ;; Return the text reference of a Python object if possible, else nil. - (when (functionp object) - (let* ((definition (indirect-function object)) - (body (and (pymacs-proper-list-p definition) - (> (length definition) 2) - (eq (car definition) 'lambda) - (cddr definition)))) - (when (and body (listp (car body)) (eq (caar body) 'interactive)) - ;; Skip the interactive specification of a function. - (setq body (cdr body))) - (when (and body - ;; Advised functions start with a string. - (not (stringp (car body))) - ;; Python trampolines hold exactly one expression. - (= (length body) 1)) - (let ((expression (car body))) - ;; EXPRESSION might now hold something like: - ;; (pymacs-apply (quote (pymacs-python . N)) ARGUMENT-LIST) - (when (and (pymacs-proper-list-p expression) - (= (length expression) 3) - (eq (car expression) 'pymacs-apply) - (eq (car (cadr expression)) 'quote)) - (setq object (cadr (cadr expression)))))))) - (when (eq (car-safe object) 'pymacs-python) - (format "python[%d]" (cdr object)))) - -;; The following functions are experimental -- they are not satisfactory yet. - -(defun pymacs-file-handler (operation &rest arguments) - ;; Integration of load-file, autoload, etc. - ;; Emacs might want the contents of some `MODULE.el' which does not exist, - ;; while there is a `MODULE.py' or `MODULE.pyc' file in the same directory. - ;; The goal is to generate a virtual contents for this `MODULE.el' file, as - ;; a set of Lisp trampoline functions to the Python module functions. - ;; Python modules can then be loaded or autoloaded as if they were Lisp. - ;(message "** %S %S" operation arguments) - (cond ((and (eq operation 'file-readable-p) - (let ((module (substring (car arguments) 0 -3))) - (or (pymacs-file-force operation arguments) - (file-readable-p (concat module ".py")) - (file-readable-p (concat module ".pyc")))))) - ((and (eq operation 'load) - (not (pymacs-file-force - 'file-readable-p (list (car arguments)))) - (file-readable-p (car arguments))) - (let ((lisp-code (pymacs-call "pymacs_load_helper" - (substring (car arguments) 0 -3) - nil))) - (unless lisp-code - (error "Python import error")) - (eval lisp-code))) - ((and (eq operation 'insert-file-contents) - (not (pymacs-file-force - 'file-readable-p (list (car arguments)))) - (file-readable-p (car arguments))) - (let ((lisp-code (pymacs-call "pymacs_load_helper" - (substring (car arguments) 0 -3) - nil))) - (unless lisp-code - (error "Python import error")) - (insert (prin1-to-string lisp-code)))) - (t (pymacs-file-force operation arguments)))) - -(defun pymacs-file-force (operation arguments) - ;; Bypass the file handler. - (let ((inhibit-file-name-handlers - (cons 'pymacs-file-handler - (and (eq inhibit-file-name-operation operation) - inhibit-file-name-handlers))) - (inhibit-file-name-operation operation)) - (apply operation arguments))) - -;(add-to-list 'file-name-handler-alist '("\\.el\\'" . pymacs-file-handler)) - -;;; Gargabe collection of Python IDs. - -;; Python objects which have no Lisp representation are allocated on the -;; Python side as `python[INDEX]', and INDEX is transmitted to Emacs, with -;; the value to use on the Lisp side for it. Whenever Lisp does not need a -;; Python object anymore, it should be freed on the Python side. The -;; following variables and functions are meant to fill this duty. - -(defvar pymacs-use-hash-tables nil - "Automatically set to t if hash tables are available.") - -(defvar pymacs-used-ids nil - "List of received IDs, currently allocated on the Python side.") - -(defvar pymacs-weak-hash nil - "Weak hash table, meant to find out which IDs are still needed.") - -(defvar pymacs-gc-wanted nil - "Flag if it is time to clean up unused IDs on the Python side.") - -(defvar pymacs-gc-running nil - "Flag telling that a Pymacs garbage collection is in progress.") - -(defvar pymacs-gc-timer nil - "Timer to trigger Pymacs garbage collection at regular time intervals. -The timer is used only if `post-gc-hook' is not available.") - -(defun pymacs-schedule-gc () - (unless pymacs-gc-running - (setq pymacs-gc-wanted t))) - -(defun pymacs-garbage-collect () - ;; Clean up unused IDs on the Python side. - (when pymacs-use-hash-tables - (let ((pymacs-gc-running t) - (pymacs-forget-mutability t) - (ids pymacs-used-ids) - used-ids unused-ids) - (while ids - (let ((id (car ids))) - (setq ids (cdr ids)) - (if (gethash id pymacs-weak-hash) - (setq used-ids (cons id used-ids)) - (setq unused-ids (cons id unused-ids))))) - ;;(message "** pymacs-garbage-collect %d %d" - ;; (length used-ids) (length unused-ids)) - (setq pymacs-used-ids used-ids - pymacs-gc-wanted nil) - (when unused-ids - (pymacs-apply "free_python" unused-ids))))) - -(defun pymacs-defuns (arguments) - ;; Take one argument, a list holding a number of items divisible by 3. The - ;; first argument is an INDEX, the second is a NAME, the third is the - ;; INTERACTION specification, and so forth. Register Python INDEX with a - ;; function with that NAME and INTERACTION on the Lisp side. The strange - ;; calling convention is to minimise quoting at call time. - (while (>= (length arguments) 3) - (let ((index (nth 0 arguments)) - (name (nth 1 arguments)) - (interaction (nth 2 arguments))) - (fset name (pymacs-defun index interaction)) - (setq arguments (nthcdr 3 arguments))))) - -(defun pymacs-defun (index interaction) - ;; Register INDEX on the Lisp side with a Python object that is a function, - ;; and return a lambda form calling that function. If the INTERACTION - ;; specification is nil, the function is not interactive. Otherwise, the - ;; function is interactive, INTERACTION is then either a string, or the - ;; index of an argument-less Python function returning the argument list. - (let ((object (pymacs-python index))) - (cond ((null interaction) - `(lambda (&rest arguments) - (pymacs-apply ',object arguments))) - ((stringp interaction) - `(lambda (&rest arguments) - (interactive ,interaction) - (pymacs-apply ',object arguments))) - (t `(lambda (&rest arguments) - (interactive (pymacs-call ',(pymacs-python interaction))) - (pymacs-apply ',object arguments)))))) - -(defun pymacs-python (index) - ;; Register on the Lisp side a Python object having INDEX, and return it. - ;; The result is meant to be recognised specially by `print-for-eval', and - ;; in the function position by `print-for-apply'. - (let ((object (cons 'pymacs-python index))) - (when pymacs-use-hash-tables - (puthash index object pymacs-weak-hash) - (setq pymacs-used-ids (cons index pymacs-used-ids))) - object)) - -;;; Generating Python code. - -;; Many Lisp expressions cannot fully be represented in Python, at least -;; because the object is mutable on the Lisp side. Such objects are allocated -;; somewhere into a vector of handles, and the handle index is used for -;; communication instead of the expression itself. - -(defvar pymacs-lisp nil - "Vector of handles to hold transmitted expressions.") - -(defvar pymacs-freed-list nil - "List of unallocated indices in Lisp.") - -;; When the Python CG is done with a Lisp object, a communication occurs so to -;; free the object on the Lisp side as well. - -(defun pymacs-allocate-lisp (expression) - ;; This function allocates some handle for an EXPRESSION, and return its - ;; index. - (unless pymacs-freed-list - (let* ((previous pymacs-lisp) - (old-size (length previous)) - (new-size (if (zerop old-size) 100 (+ old-size (/ old-size 2)))) - (counter new-size)) - (setq pymacs-lisp (make-vector new-size nil)) - (while (> counter 0) - (setq counter (1- counter)) - (if (< counter old-size) - (aset pymacs-lisp counter (aref previous counter)) - (setq pymacs-freed-list (cons counter pymacs-freed-list)))))) - (let ((index (car pymacs-freed-list))) - (setq pymacs-freed-list (cdr pymacs-freed-list)) - (aset pymacs-lisp index expression) - index)) - -(defun pymacs-free-lisp (&rest indices) - ;; This function is triggered from Python side for Lisp handles which lost - ;; their last reference. These references should be cut on the Lisp side as - ;; well, or else, the objects will never be garbage-collected. - (while indices - (let ((index (car indices))) - (aset pymacs-lisp index nil) - (setq pymacs-freed-list (cons index pymacs-freed-list) - indices (cdr indices))))) - -(defun pymacs-print-for-apply-expanded (function arguments) - ;; This function acts like `print-for-apply', but produce arguments which - ;; are expanded copies whenever possible, instead of handles. Proper lists - ;; are turned into Python lists, vectors are turned into Python tuples. - (let ((pymacs-forget-mutability t)) - (pymacs-print-for-apply function arguments))) - -(defun pymacs-print-for-apply (function arguments) - ;; This function prints a Python expression calling FUNCTION, which is a - ;; string naming a Python function, or a Python reference, over all its - ;; ARGUMENTS, which are Lisp expressions. - (let ((separator "") - argument) - (if (eq (car-safe function) 'pymacs-python) - (princ (format "python[%d]" (cdr function))) - (princ function)) - (princ "(") - (while arguments - (setq argument (car arguments) - arguments (cdr arguments)) - (princ separator) - (setq separator ", ") - (pymacs-print-for-eval argument)) - (princ ")"))) - -(defun pymacs-print-for-eval (expression) - ;; This function prints a Python expression out of a Lisp EXPRESSION. - (let (done) - (cond ((not expression) - (princ "None") - (setq done t)) - ((numberp expression) - (princ expression) - (setq done t)) - ((stringp expression) - (when (or pymacs-forget-mutability - (not pymacs-mutable-strings)) - (let ((text (copy-sequence expression))) - (set-text-properties 0 (length text) nil text) - (princ (mapconcat 'identity - (split-string (prin1-to-string text) "\n") - "\\n"))) - (setq done t))) - ((symbolp expression) - (let ((name (symbol-name expression))) - ;; The symbol can only be transmitted when in the main oblist. - (when (eq expression (intern-soft name)) - (cond - ((save-match-data - (string-match "^[A-Za-z][-A-Za-z0-9]*$" name)) - (princ "lisp.") - (princ (mapconcat 'identity (split-string name "-") "_"))) - (t (princ "lisp[") - (prin1 name) - (princ "]"))) - (setq done t)))) - ((vectorp expression) - (when pymacs-forget-mutability - (let ((limit (length expression)) - (counter 0)) - (princ "(") - (while (< counter limit) - (unless (zerop counter) - (princ ", ")) - (pymacs-print-for-eval (aref expression counter))) - (when (= limit 1) - (princ ",")) - (princ ")") - (setq done t)))) - ((eq (car-safe expression) 'pymacs-python) - (princ "python[") - (princ (cdr expression)) - (princ "]")) - ((pymacs-proper-list-p expression) - (when pymacs-forget-mutability - (princ "[") - (pymacs-print-for-eval (car expression)) - (while (setq expression (cdr expression)) - (princ ", ") - (pymacs-print-for-eval (car expression))) - (princ "]") - (setq done t)))) - (unless done - (let ((class (cond ((vectorp expression) "Vector") - ((and pymacs-use-hash-tables - (hash-table-p expression)) - "Table") - ((bufferp expression) "Buffer") - ((pymacs-proper-list-p expression) "List") - (t "Lisp")))) - (princ class) - (princ "(") - (princ (pymacs-allocate-lisp expression)) - (princ ")"))))) - -;;; Communication protocol. - -(defvar pymacs-transit-buffer nil - "Communication buffer between Emacs and Python.") - -;; The principle behind the communication protocol is that it is easier to -;; generate than parse, and that each language already has its own parser. -;; So, the Emacs side generates Python text for the Python side to interpret, -;; while the Python side generates Lisp text for the Lisp side to interpret. -;; About nothing but expressions are transmitted, which are evaluated on -;; arrival. The pseudo `reply' function is meant to signal the final result -;; of a series of exchanges following a request, while the pseudo `error' -;; function is meant to explain why an exchange could not have been completed. - -;; The protocol itself is rather simple, and contains human readable text -;; only. A message starts at the beginning of a line in the communication -;; buffer, either with `>' for the Lisp to Python direction, or `<' for the -;; Python to Lisp direction. This is followed by a decimal number giving the -;; length of the message text, a TAB character, and the message text itself. -;; Message direction alternates systematically between messages, it never -;; occurs that two successive messages are sent in the same direction. The -;; first message is received from the Python side, it is `(version VERSION)'. - -(defun pymacs-start-services () - ;; This function gets called automatically, as needed. - (let ((buffer (get-buffer-create "*Pymacs*"))) - (with-current-buffer buffer - (buffer-disable-undo) - (save-match-data - ;; Launch the Python helper. - (let ((process (apply 'start-process "pymacs" buffer "pymacs-services" - (mapcar 'expand-file-name pymacs-load-path)))) - (process-kill-without-query process) - ;; Receive the synchronising reply. - (while (progn - (goto-char (point-min)) - (not (re-search-forward "<\\([0-9]+\\)\t" nil t))) - (unless (accept-process-output process pymacs-timeout-at-start) - (error "Pymacs helper did not start within %d seconds." - pymacs-timeout-at-start))) - (let ((marker (process-mark process)) - (limit-position (+ (match-end 0) - (string-to-number (match-string 1))))) - (while (< (marker-position marker) limit-position) - (unless (accept-process-output process pymacs-timeout-at-start) - (error "Pymacs helper probably was interrupted at start."))))) - ;; Check that synchronisation occurred. - (goto-char (match-end 0)) - (let ((reply (read (current-buffer)))) - (if (and (pymacs-proper-list-p reply) - (= (length reply) 2) - (eq (car reply) 'pymacs-version)) - (unless (string-equal (cadr reply) "@VERSION@") - (error "Pymacs Lisp version is @VERSION@, Python is %s." - (cadr reply))) - (error "Pymacs got an invalid initial reply."))))) - (setq pymacs-use-hash-tables (and (fboundp 'make-hash-table) - (fboundp 'gethash) - (fboundp 'puthash))) - (when pymacs-use-hash-tables - (if pymacs-weak-hash - ;; A previous Pymacs session occurred in *this* Emacs session. Some - ;; IDs may hang around, which do not correspond to anything on the - ;; Python side. Python should not recycle such IDs for new objects. - (when pymacs-used-ids - (let ((pymacs-transit-buffer buffer) - (pymacs-forget-mutability t)) - (pymacs-apply "zombie_python" pymacs-used-ids))) - (setq pymacs-weak-hash (make-hash-table :weakness 'value))) - (if (boundp 'post-gc-hook) - (add-hook 'post-gc-hook 'pymacs-schedule-gc) - (setq pymacs-gc-timer (run-at-time 20 20 'pymacs-schedule-gc)))) - ;; If nothing failed, only then declare the Pymacs has started! - (setq pymacs-transit-buffer buffer))) - -(defun pymacs-terminate-services () - ;; This function is mainly provided for documentation purposes. - (interactive) - (garbage-collect) - (pymacs-garbage-collect) - (when (or (not pymacs-used-ids) - (yes-or-no-p "\ -Killing the helper might create zombie objects. Kill? ")) - (cond ((boundp 'post-gc-hook) - (remove-hook 'post-gc-hook 'pymacs-schedule-gc)) - ((timerp pymacs-gc-timer) - (cancel-timer pymacs-gc-timer))) - (when pymacs-transit-buffer - (kill-buffer pymacs-transit-buffer)) - (setq pymacs-gc-running nil - pymacs-gc-timer nil - pymacs-transit-buffer nil - pymacs-lisp nil - pymacs-freed-list nil))) - -(defun pymacs-serve-until-reply (inserter) - ;; This function evals INSERTER to print a Python request. It sends it to - ;; the Python helper, and serves all sub-requests coming from the - ;; Python side, until either a reply or an error is finally received. - (unless (and pymacs-transit-buffer - (buffer-name pymacs-transit-buffer) - (get-buffer-process pymacs-transit-buffer)) - (pymacs-start-services)) - (when pymacs-gc-wanted - (pymacs-garbage-collect)) - (let (done value) - (while (not done) - (let* ((text (pymacs-round-trip inserter)) - (reply (condition-case info - (eval text) - (error (cons 'pymacs-oops (prin1-to-string info)))))) - (cond ((not (consp reply)) - (setq inserter - `(pymacs-print-for-apply 'reply '(,reply)))) - ((eq 'pymacs-reply (car reply)) - (setq done t value (cdr reply))) - ((eq 'pymacs-error (car reply)) - (error "Python: %s" (cdr reply))) - ((eq 'pymacs-oops (car reply)) - (setq inserter - `(pymacs-print-for-apply 'error '(,(cdr reply))))) - ((eq 'pymacs-expand (car reply)) - (setq inserter - `(pymacs-print-for-apply-expanded 'reply - '(,(cdr reply))))) - (t (setq inserter - `(pymacs-print-for-apply 'reply '(,reply))))))) - value)) - -(defun pymacs-reply (expression) - ;; This pseudo-function returns `(pymacs-reply . EXPRESSION)'. - ;; `serve-until-reply' later recognises this form. - (cons 'pymacs-reply expression)) - -(defun pymacs-error (expression) - ;; This pseudo-function returns `(pymacs-error . EXPRESSION)'. - ;; `serve-until-reply' later recognises this form. - (cons 'pymacs-error expression)) - -(defun pymacs-expand (expression) - ;; This pseudo-function returns `(pymacs-expand . EXPRESSION)'. - ;; `serve-until-reply' later recognises this form. - (cons 'pymacs-expand expression)) - -(defun pymacs-round-trip (inserter) - ;; This function evals INSERTER to print a Python request. It sends it to - ;; the Python helper, awaits for any kind of reply, and returns it. - (with-current-buffer pymacs-transit-buffer - (unless pymacs-trace-transit - (erase-buffer)) - (let* ((process (get-buffer-process pymacs-transit-buffer)) - (status (process-status process)) - (marker (process-mark process)) - (moving (= (point) marker)) - send-position reply-position reply) - (save-excursion - (save-match-data - ;; Encode request. - (setq send-position (marker-position marker)) - (let ((standard-output marker)) - (eval inserter)) - (goto-char marker) - (unless (= (preceding-char) ?\n) - (princ "\n" marker)) - ;; Send request text. - (goto-char send-position) - (insert (format ">%d\t" (- marker send-position))) - (setq reply-position (marker-position marker)) - (process-send-region process send-position marker) - ;; Receive reply text. - (while (and (eq status 'run) - (progn - (goto-char reply-position) - (not (re-search-forward "<\\([0-9]+\\)\t" nil t)))) - (unless (accept-process-output process pymacs-timeout-at-reply) - (setq status (process-status process)))) - (when (eq status 'run) - (let ((limit-position (+ (match-end 0) - (string-to-number (match-string 1))))) - (while (and (eq status 'run) - (< (marker-position marker) limit-position)) - (unless (accept-process-output process pymacs-timeout-at-line) - (setq status (process-status process)))))) - ;; Decode reply. - (if (not (eq status 'run)) - (error "Pymacs helper status is `%S'." status) - (goto-char (match-end 0)) - (setq reply (read (current-buffer)))))) - (when (and moving (not pymacs-trace-transit)) - (goto-char marker)) - reply))) - -(defun pymacs-proper-list-p (expression) - ;; Tell if a list is proper, id est, that it is `nil, or ends with `nil'. - (cond ((not expression)) - ((consp expression) (not (cdr (last expression)))))) - -(provide 'pymacs) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/rebox --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/rebox Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -#!/usr/bin/env python -# Copyright © 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , 2002. - -"""\ -Handling of boxed comments in various box styles. -""" - -import sys -from Pymacs import rebox -apply(rebox.main, tuple(sys.argv[1:])) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/setup-emacs.py --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/setup-emacs.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,235 +0,0 @@ -#!/usr/bin/env python -# Copyright © 2001, 2002 Progiciels Bourbeau-Pinard inc. -# François Pinard , 2001. - -"""\ -Installer tool for Pymacs `pymacs.el'. - -Usage: setup [OPTION] - - -H Display this help, then exit. - -V Display package name and version, then exit. - - -i Interactively check selected options with user. - -n Dry run: merely display selected options. - -g GROUP Install with write permissions for that user GROUP. - -e Load `.emacs' before checking Emacs `load-path'. - - -l LISPDIR Install `pymacs.el' in LISPDIR. - -E EMACS Use that executable for EMACS, if not `emacs'. -""" - -import os, string, sys - -sys.path.insert(0, '.') -from Pymacs import package, version -del sys.path[0] - -AUTOCONF = () # neither a string nor None - -class run: - interactive = 0 - dry = 0 - group = None - dot_emacs = 0 - lispdir = AUTOCONF - emacs = 'emacs' - -def main(*arguments): - import getopt - options, arguments = getopt.getopt(arguments, 'E:HVeg:il:n') - for option, value in options: - if option == '-E' and value: - run.emacs = value - elif option == '-H': - sys.stdout.write(__doc__) - sys.exit(0) - elif option == '-V': - sys.stdout.write('%s-%s' % (package, version)) - sys.exit(0) - elif option == '-e': - run.dot_emacs = 1 - elif option == '-g' and value: - run.group = value - elif option == '-i': - run.interactive = 1 - elif option == '-l' and value: - if value in ('none', 'None'): - run.lispdir = None - else: - run.lispdir = [value] - auto_configure() - if run.interactive: - check_with_user() - check_choices() - if not run.dry: - complete_install() - -def auto_configure(): - if run.lispdir is AUTOCONF: - run.lispdir = [] - import tempfile - script = tempfile.mktemp() - if sys.platform == 'win32': - # Win32 names starting with tilde and Emacs are unhappy together. - path, file = os.path.split(script) - script = os.path.join(path, 'a' + file) - try: - open(script, 'w').write('(message "%S" load-path)') - load_config = '' - if run.dot_emacs: - config = os.path.join(os.environ['HOME'], '.emacs') - for name in config, config + '.el', config + '.elc': - if os.path.isfile(name): - # Quote! Spaces are common in Win32 file names. - load_config = ' -l "%s"' % name - break - # Quote! Spaces are common in Win32 file names. - text = os.popen('%s -batch%s -l "%s" 2>&1' - % (run.emacs, load_config, script)).read() - finally: - os.remove(script) - position = string.find(text, '("') - if position >= 0: - text = text[position:] - if text[-1] == '\n': - text = text[:-1] - assert text[0] == '(' and text[-1] == ')', text - for path in string.split(text[1:-1]): - assert path[0] == '"' and path[-1] == '"', path - path = path[1:-1] - if os.access(path, 7): - run.lispdir.append(path) - -def check_with_user(): - sys.stderr.write("""\ -Install tool for %s version %s. -""" - % (package, version)) - run.lispdir = user_select('lispdir', run.lispdir, """\ -This is where `pymacs.el', the Emacs side code of Pymacs, should go: -somewhere on your Emacs `load-path'. -""") - -def user_select(name, values, message): - write = sys.stderr.write - readline = sys.stdin.readline - if values is None: - write("""\ - -Enter a value for `%s', or merely type `Enter' if you do not want any. -""" - % name) - write(message) - while 1: - write('%s? ' % name) - text = string.strip(readline()) - if not text: - return None - if os.access(os.path.expanduser(text), 7): - return [text] - write("""\ - -This directory does not exist, or is not writable. Please reenter it. -""") - if len(values) == 1: - return values - if values == []: - write("""\ - -Pymacs is not likely to install properly, as the installer may not currently -write in any directory for `%s'. Running as `root' might help you. -Or else, you will most probably have to revise a bit your work setup. -""" - % name) - write(message) - return values - write("""\ - -There are many possibilities for `%s', please select one of them by -typing its number followed by `Enter'. A mere `Enter' selects the first. -""" - % name) - write(message) - write('\n') - for counter in range(len(values)): - write('%d. %s\n' % (counter + 1, values[counter])) - while 1: - write('[1-%d]? ' % len(values)) - text = string.strip(readline()) - if not text: - return [values[0]] - try: - counter = int(text) - except ValueError: - pass - else: - if 1 <= counter <= len(values): - return [values[counter-1]] - write("""\ -This is not a valid choice. Please retry. -""") - -def check_choices(): - write = sys.stderr.write - error = 0 - if run.lispdir is not None: - if run.lispdir and os.access(os.path.expanduser(run.lispdir[0]), 7): - run.lispdir = run.lispdir[0] - else: - write("\ -Use `-l LISPDIR' to select where `pymacs.el' should go.\n") - error = 1 - if error: - write("ERROR: Installation aborted!\n" - " Try `%s -i'.\n" % sys.argv[0]) - sys.exit(1) - write( - '\n' - "Directory selection for installing Pymacs:\n" - " lispdir = %(lispdir)s\n" - '\n' - % run.__dict__) - -def complete_install(): - run.substitute = {'PACKAGE': package, 'VERSION': version} - if run.lispdir: - goal = os.path.join(run.lispdir, 'pymacs.el') - install('pymacs.el', goal, 0644) - compile_lisp(goal) - -def install(source, destination, permissions): - sys.stderr.write('Installing %s\n' % destination) - write = open(destination, 'w').write - produce_at = 0 - #print '*', run.substitute - for fragment in string.split(open(source).read(), '@'): - #print '**', produce_at, `fragment` - if produce_at: - replacement = run.substitute.get(fragment) - #print '***', replacement - if replacement is None: - write('@') - write(fragment) - else: - write(replacement) - produce_at = 0 - else: - write(fragment) - produce_at = 1 - write = None - set_attributes(destination, permissions) - -def compile_lisp(name): - sys.stderr.write('Compiling %s\n' % name) - os.system('%s -batch -f batch-byte-compile %s' % (run.emacs, name)) - set_attributes(name + 'c', 0644) - -def set_attributes(name, permissions): - if run.group: - os.chown(name, run.group) - permissions = permissions | 0020 - os.chmod(name, permissions) - -if __name__ == '__main__': - apply(main, sys.argv[1:]) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/Pymacs-0.20/setup.py --- a/vim/sadness/bike/ide-integration/Pymacs-0.20/setup.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -#!/usr/bin/env python - -import sys -sys.path.insert(0, '.') -from Pymacs import package, version -del sys.path[0] - -from distutils.core import setup - -setup(name=package, - version=version, - description='Interface between Emacs LISP and Python.', - author='François Pinard', - author_email='pinard@iro.umontreal.ca', - url='http://www.iro.umontreal.ca/~pinard', - scripts=['pymacs-services', 'pymacs-services.bat', 'rebox'], - packages=['Pymacs']) diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/bike.vim --- a/vim/sadness/bike/ide-integration/bike.vim Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,430 +0,0 @@ -" Bicycle Repair Man integration for Vim -" Version 0.3 -" Copyright (c) 2003 Marius Gedminas -" -" Needs Vim 6.x with python interpreter (Python 2.2 or newer) -" Installation instructions: just drop it into $HOME/.vim/plugin and you -" should see the Bicycle Repair Menu appear in GVim (or you can check if -" any of the BikeXxx commands are defined in console mode Vim). If bike.vim -" fails to load and you want to see the reason, try -" let g:bike_exceptions = 1 -" source ~/.vim/plugin/bike.vim -" -" Configuration options you can add to your .vimrc: -" let g:bike_exceptions = 1 " show tracebacks on exceptions -" let g:bike_progress = 1 " show import progress -" -" Commands defined: -" -" BikeShowScope -" Show current scope. Sample of usage: -" autocmd CursorHold *.py BikeShowScope -" -" BikeShowType -" Show selected expression type. The range is ignored, '<,'> is always -" used. Use this in visual block mode. -" -" BikeFindRefs -" Finds all references of the function/method/class defined in current -" line. -" -" BikeFindDef -" Finds the definition of the function/method/class under cursor. -" -" BikeRename -" Renames the function/method/class defined in current line. Updates -" all references in all files known (i.e. imported) to Bicycle Repair -" Man. -" -" BikeExtract -" Extracts a part of the function/method into a new function/method. -" The range is ignored, '<,'> is always used. Use this in visual mode. -" -" BikeUndo -" Globally undoes the previous refactoring. -" -" Issues: -" - Saves all modified buffers to disk without asking the user -- not nice -" - Does not reimport files that were modified outside of Vim -" - Uses mktemp() -- I think that produces deprecation warnings in Python 2.3 -" - BikeShowType, BikeExtract ignores the specified range, that's confusing. -" At least BikeExtract ought to work... -" - BikeShowType/BikeExtract or their GUI counterparts work when not in -" visual mode by using the previous values of '<,'>. Might be confusing. -" - Would be nice if :BikeImport asked to enter package -" - Would be nice if :BikeRename myNewName worked -" - The code is not very robust (grep for XXX) - -" -" Default settings for global configuration variables {{{1 -" - -" Set to 1 to see full tracebacks -if !exists("g:bike_exceptions") - let g:bike_exceptions = 0 -endif - -" Set to 1 to see import progress -if !exists("g:bike_progress") - let g:bike_progress = 0 -endif - -" -" Initialization {{{1 -" - -" First check that Vim is sufficiently recent, that we have python interpreted -" support, and that Bicycle Repair Man is available. -" -" If something is wrong, fail silently, as error messages every time vim -" starts are very annoying. But if the user wants to see why bike.vim failed -" to load, she can let g:bike_exceptions = 1 -if version < 600 - if g:bike_exceptions - echo 'Bicycle Repair Man needs Vim 6.0' - endif - finish -endif - -if !has("python") - if g:bike_exceptions - echo 'Bicycle Repair Man needs Vim with Python interpreter support (2.2 or newer)' - endif - finish -endif - -let s:has_bike=1 -python << END -import vim -import sys -try: - if sys.version_info < (2, 2): - raise ImportError, 'Bicycle Repair Man needs Python 2.2 or newer' - import bike - bikectx = bike.init() - bikectx.isLoaded # make sure bike package is recent enough -except ImportError: - vim.command("let s:has_bike=0") - if vim.eval('g:bike_exceptions') not in (None, '', '0'): - raise -END -if !s:has_bike - finish -endif - -" Use sane cpoptions -let s:cpo_save = &cpo -set cpo&vim - -" -" Menu {{{1 -" -silent! aunmenu Bicycle\ Repair\ Man - -" Shortcuts available: ab-----h-jk--nopq----vw--z -amenu Bicycle\ &Repair\ Man.-SEP1- -\ : -amenu Bicycle\ &Repair\ Man.&Find\ References -\ :call BikeFindRefs() -amenu Bicycle\ &Repair\ Man.Find\ &Definition -\ :call BikeFindDef() -amenu Bicycle\ &Repair\ Man.Resu<s.&List:cl -\ :cl -amenu Bicycle\ &Repair\ Man.Resu<s.&Current:cc -\ :cc -amenu Bicycle\ &Repair\ Man.Resu<s.&Next:cn -\ :cn -amenu Bicycle\ &Repair\ Man.Resu<s.&Previous:cp -\ :cp -amenu Bicycle\ &Repair\ Man.Resu<s.&First:cfirst -\ :cfirst -amenu Bicycle\ &Repair\ Man.Resu<s.Las&t:clast -\ :clast -amenu Bicycle\ &Repair\ Man.Resu<s.&Older\ List:colder -\ :colder -amenu Bicycle\ &Repair\ Man.Resu<s.N&ewer\ List:cnewer -\ :cnewer -amenu Bicycle\ &Repair\ Man.Resu<s.&Window.&Update:cw -\ :cw -amenu Bicycle\ &Repair\ Man.Resu<s.&Window.&Open:copen -\ :copen -amenu Bicycle\ &Repair\ Man.Resu<s.&Window.&Close:cclose -\ :cclose -amenu Bicycle\ &Repair\ Man.-SEP2- -\ : -amenu Bicycle\ &Repair\ Man.&Rename -\ :call BikeRename() -amenu Bicycle\ &Repair\ Man.E&xtract\ Method -\ :call BikeExtract('method') -amenu Bicycle\ &Repair\ Man.&Extract\ Function -\ :call BikeExtract('function') -amenu Bicycle\ &Repair\ Man.&Undo -\ :call BikeUndo() -amenu Bicycle\ &Repair\ Man.-SEP3- -\ : -amenu Bicycle\ &Repair\ Man.Settin&gs.Import\ &Progress.&Enable -\ :let g:bike_progress = 1 -amenu Bicycle\ &Repair\ Man.Settin&gs.Import\ &Progress.&Disable -\ :let g:bike_progress = 0 -amenu Bicycle\ &Repair\ Man.Settin&gs.Full\ &Exceptions.&Enable -\ :let g:bike_exceptions = 1 -amenu Bicycle\ &Repair\ Man.Settin&gs.Full\ &Exceptions.&Disable -\ :let g:bike_exceptions = 0 - -" Note: The three rename commands are basically identical. The two extract -" commands are also identical behind the scenes. - -" -" Commands {{{1 -" - -command! BikeShowScope call BikeShowScope() -command! -range BikeShowType call BikeShowType() -command! BikeFindRefs call BikeFindRefs() -command! BikeFindDef call BikeFindDef() - -command! BikeRename call BikeRename() -command! -range BikeExtract call BikeExtract('function') -command! BikeUndo call BikeUndo() - -" -" Implementation {{{1 -" - -" Query functions {{{2 - -function! s:BikeShowScope() -" Shows the scope under cursor - python << END -fn = vim.current.buffer.name -row, col = vim.current.window.cursor -try: - print bikectx.getFullyQualifiedNameOfScope(fn, row) -except: - show_exc() -END -endf - -function! s:BikeShowType() -" Shows the inferred type of the selected expression - if col("'<") == 0 " mark not set - echo "Select a region first!" - return - endif - if line("'<") != line("'>") " multiline selection - echo "Multi-line regions not supported" - " XXX deficiency of bikefacade interface, expressions can easily span - " several lines in Python - return - endif - python << END -fn = vim.current.buffer.name -row1, col1 = vim.current.buffer.mark('<') -row2, col2 = vim.current.buffer.mark('>') -try: - print bikectx.getTypeOfExpression(fn, row1, col1, col2) -except: - show_exc() -END -endf - -function! s:BikeFindRefs() -" Find all references to the item defined on current line - wall - python << END -fn = vim.current.buffer.name -row, col = vim.current.window.cursor -try: - refs = bikectx.findReferencesByCoordinates(fn, row, col) - quickfixdefs(refs) -except: - show_exc() -END -endf - -function! s:BikeFindDef() -" Find all definitions of the item under cursor. Ideally there should be only -" one. - wall - python << END -fn = vim.current.buffer.name -row, col = vim.current.window.cursor -try: - defs = bikectx.findDefinitionByCoordinates(fn, row, col) - quickfixdefs(defs) -except: - show_exc() -END -endf - -" Refactoring commands {{{2 - -function! s:BikeRename() -" Rename a function/method/class. - - let newname = inputdialog('Rename to: ') - wall - python << END -fn = vim.current.buffer.name -row, col = vim.current.window.cursor -newname = vim.eval("newname") -if newname: - try: - bikectx.setRenameMethodPromptCallback(renameMethodPromptCallback) - bikectx.renameByCoordinates(fn, row, col, newname) - except: - show_exc() - saveChanges() -else: - print "Aborted" -END -endf - -function! s:BikeExtract(what) -" Extract a piece of code into a separate function/method. The argument -" a:what can be 'method' or 'function'. - if col("'<") == 0 " mark not set - echo "Select a region first!" - return - endif - let newname = inputdialog('New function name: ') - wall - python << END -fn = vim.current.buffer.name -row1, col1 = vim.current.buffer.mark('<') -row2, col2 = vim.current.buffer.mark('>') -newname = vim.eval("newname") -if newname: - try: - bikectx.extractMethod(fn, row1, col1, row2, col2, newname) - except: - show_exc() - saveChanges() -else: - print "Aborted" -END -endf - -function! s:BikeUndo() -" Undoes the last refactoring - wall -python << END -try: - bikectx.undo() - saveChanges() -except bike.UndoStackEmptyException, e: - print "Nothing to undo" -END -endf - -" -" Helper functions {{{1 -" - -" Python helpers - -python << END - -import tempfile -import os -import linecache - -modified = {} # a dictionary whose keys are the names of files modifed - # in Vim since the last import - -def show_exc(): - """Print exception according to bike settings.""" - if vim.eval('g:bike_exceptions') not in (None, '', '0'): - import traceback - traceback.print_exc() - else: - type, value = sys.exc_info()[:2] - if value is not None: - print "%s: %s" % (type, value) - else: - print type - -def writedefs(defs, filename): - """Write a list of file locations to a file.""" - ef = None - curdir = os.getcwd() - if not curdir.endswith(os.sep): - curdir = curdir + os.sep - for d in defs: - if not ef: - ef = open(filename, "w") - fn = d.filename - if fn.startswith(curdir): - fn = fn[len(curdir):] - line = linecache.getline(fn, d.lineno).strip() - res ="%s:%d: %3d%%: %s" % (fn, d.lineno, d.confidence, line) - print res - print >> ef, res - if ef: - ef.close() - return ef is not None - -def quickfixdefs(defs): - """Import a list of file locations into vim error list.""" - fn = tempfile.mktemp() # XXX unsafe - if writedefs(defs, fn): - vim.command('let old_errorfile = &errorfile') - vim.command('let old_errorformat = &errorformat') - vim.command(r'set errorformat=\%f:\%l:\ \%m') - vim.command("cfile %s" % fn) - vim.command('let &errorformat = old_errorformat') - vim.command('let &errorfile = old_errorfile') - os.unlink(fn) - else: - print "Not found" - -def renameMethodPromptCallback(filename, line, col1, col2): - """Verify that the call in a given file position should be renamed.""" - vim.command('e +%d %s' % (line, filename)) - vim.command('normal %d|' % col1) - vim.command('match Search /\%%%dl\%%>%dc\%%<%dc' % (line, col1, col2+1)) - vim.command('redraw') - ans = vim.eval('confirm("Cannot deduce instance type. Rename this call?",' - ' "&Yes\n&No", 1, "Question")') - vim.command('match none') - if ans == '1': - return 1 - else: - return 0 - - -def saveChanges(): - """Save refactoring changes to the file system and reload the modified - files in Vim.""" - # bikectx.save() returns a list of modified file names. We should make - # sure that all those files are reloaded iff they were open in vim. - files = map(os.path.abspath, bikectx.save()) - - opened_files = {} - for b in vim.buffers: - if b.name is not None: - opened_files[os.path.abspath(b.name)] = b.name - - for f in files: - try: - # XXX might fail when file name contains funny characters - vim.command("sp %s | q" % opened_files[f]) - except KeyError: - pass - - # Just in case: - vim.command("checktime") - vim.command("e") - -END - -" Make sure modified files are reimported into BRM -autocmd BufWrite * python modified[os.path.abspath(vim.current.buffer.name)] = 1 - -" -" Cleanup {{{1 -" - -" Restore cpoptions -let &cpo = s:cpo_save -unlet s:cpo_save diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/bikeemacs.py --- a/vim/sadness/bike/ide-integration/bikeemacs.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,333 +0,0 @@ -# Bicycle Repair Man integration with (X)Emacs -# By Phil Dawes (2002) -# Uses the fabulous Pymacs package by François Pinard - -from Pymacs import lisp, Let -import bike -reload(bike) -from bike import bikefacade -import StringIO, traceback -import sys - -class EmacsLogger: - def __init__(self): - self.msg = "" - - def write(self,output): - self.msg +=output - if output.endswith("\n"): - lisp.message(self.msg) - self.msg = "" - -class NullLogger: - def write(self,output): - pass - -logger = EmacsLogger() - - -class ExceptionCatcherWrapper: - - def __init__(self,myobj): - self.myobj = myobj - - def __getattr__(self,name): - return ExceptionInterceptor(self.myobj,name) - - -class ExceptionInterceptor: - def __init__(self,targetobj,name): - self.targetobj = targetobj - self.name = name - - def __call__(self, *params, **kwparams ): - try: - return self.makeCall(params) - except: - traceback.print_exc() - lisp.error(str(sys.exc_info()[1])) - - def makeCall(self,params): - argsstr="(self.targetobj" - for i in range(len(params)): - argsstr += ",params["+`i`+"]" - argsstr+=")" - return eval("self.targetobj.__class__."+self.name+argsstr) - - -class BRMEmacs(object): - - def __init__(self,brmctx): - self.ctx = brmctx - - lisp.require(lisp["python-mode"]) - lisp(""" - (defvar brm-menu nil "Menu for Bicycle Repair Man") - (easy-menu-define - brm-menu py-mode-map "Bicycle Repair Man" - '("BicycleRepairMan" - "Queries" - ["Find-References" brm-find-references] - ["Find-Definition" brm-find-definition] - "---" - "Refactoring" - ["Rename" brm-rename t] - ["Extract-Method" brm-extract-method t] - ["Extract-Local-Variable" brm-extract-local-variable t] - ["Inline-Local-Variable" brm-inline-local-variable t] - ["Undo Last Refactoring" brm-undo t] - - )) - (add-hook 'python-mode-hook (lambda () (easy-menu-add brm-menu))) - """) - # ["Move-Class-To-New-Module" brm-move-class t] - # ["Move-Function-To-New-Module" brm-move-class t] - - self.ctx.setProgressLogger(logger) - - - def rename(self,newname): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - line,col = _getCoords() - brmctx.setRenameMethodPromptCallback(promptCallback) - try: - self.ctx.renameByCoordinates(filename,line,col,newname) - savedFiles = brmctx.save() - _revertSavedFiles(savedFiles) - lisp.set_marker(lisp.mark_marker(),None) - except bikefacade.CouldntLocateASTNodeFromCoordinatesException: - print >>logger,"Couldn't find AST Node. Are you renaming the declaration?" - - def kill(self): - self.ctx = None - self.ctx = bike.init() - self.ctx.setProgressLogger(logger) - - def undo(self): - brmctx.undo() - savedFiles = brmctx.save() - _revertSavedFiles(savedFiles) - - def find_references(self): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - line,col = _getCoords() - refs = brmctx.findReferencesByCoordinates(filename,line,col) - _switchToConsole() - numRefs = 0 - for ref in refs: - _insertRefLineIntoConsole(ref) - numRefs +=1 - lisp.insert("Done - %d refs found\n"%numRefs) - - - def find_definition(self): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - line,col = _getCoords() - defns = brmctx.findDefinitionByCoordinates(filename,line,col) - - try: - firstdefn = defns.next() - lisp.find_file_other_window(firstdefn.filename) - lisp.goto_line(firstdefn.lineno) - lisp.forward_char(firstdefn.colno) - except StopIteration: - pass - else: - numRefs = 1 - for defn in defns: - if numRefs == 1: - _switchToConsole() - _insertRefLineIntoConsole(firstdefn) - _insertRefLineIntoConsole(defn) - numRefs += 1 - - - def inline_local_variable(self): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - line,col = _getCoords() - brmctx.inlineLocalVariable(filename,line,col) - lisp.set_marker(lisp.mark_marker(),None) - _revertSavedFiles(brmctx.save()) - - def extract_local_variable(self,name): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - - bline,bcol = _getPointCoords() - lisp.exchange_point_and_mark() - eline,ecol = _getPointCoords() - lisp.exchange_point_and_mark() - - brmctx.extractLocalVariable(filename,bline,bcol,eline,ecol,name) - lisp.set_marker(lisp.mark_marker(),None) - _revertSavedFiles(brmctx.save()) - - def extract_method(self,name): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - - bline,bcol = _getPointCoords() - lisp.exchange_point_and_mark() - eline,ecol = _getPointCoords() - lisp.exchange_point_and_mark() - - brmctx.extract(filename,bline,bcol,eline,ecol,name) - lisp.set_marker(lisp.mark_marker(),None) - _revertSavedFiles(brmctx.save()) - - - def move_class(self,newfilename): - lisp.save_some_buffers() - filename = lisp.buffer_file_name() - line,col = _getCoords() - brmctx.moveClassToNewModule(filename,line,newfilename) - _revertSavedFiles(brmctx.save()) - - - -brmctx = bike.init() - -brmemacs = None - -is_xemacs = (lisp.emacs_version().find("GNU") == -1) -currently_saving=0 - -# fix pop_excursion to work with xemacs -class Let(Let): - def pop_excursion(self): - method, (buffer, point_marker, mark_marker) = self.stack[-1] - assert method == 'excursion', self.stack[-1] - del self.stack[-1] - lisp.set_buffer(buffer) - lisp.goto_char(point_marker) - lisp.set_mark(mark_marker) - lisp.set_marker(point_marker, None) - if mark_marker is not None: # needed for xemacs - lisp.set_marker(mark_marker, None) - - - -def init(): - global brmemacs - brmemacs = ExceptionCatcherWrapper(BRMEmacs(brmctx)) - - -def kill(): - """ - Removes the bicyclerepairman context (freeing the state), - and reinitialises it. - """ - brmemacs.kill() -kill.interaction="" - - -def promptCallback(filename,line,colbegin,colend): - let = Let().push_excursion() # gets popped when let goes out of scope - buffer = lisp.current_buffer() - if let: - ans = 0 - lisp.find_file(filename) - lisp.goto_line(line) - lisp.move_to_column(colbegin) - lisp.set_mark(lisp.point() + (colend - colbegin)) - if is_xemacs: - lisp.activate_region() - ans = lisp.y_or_n_p("Couldn't deduce object type - rename this method reference? ") - del let - lisp.switch_to_buffer(buffer) - return ans - -def rename(newname): - return brmemacs.rename(newname) -rename.interaction="sNew name: " - - -def undo(): - return brmemacs.undo() -undo.interaction="" - - -def _revertSavedFiles(savedFiles): - global currently_saving - currently_saving = 1 - for file in savedFiles: - buf = lisp.find_buffer_visiting(file) - if buf: - lisp.set_buffer(buf) - lisp.revert_buffer(None,1) - currently_saving = 0 - -def find_references(): - brmemacs.find_references() -find_references.interaction="" - -def _getCoords(): - line = lisp.count_lines(1,lisp.point()) - col = lisp.current_column() - if col == 0: - line += 1 # get round 'if col == 0, then line is 1 out' problem - - if mark_exists() and lisp.point() > lisp.mark(): - lisp.exchange_point_and_mark() - col = lisp.current_column() - lisp.exchange_point_and_mark() - return line,col - -def mark_exists(): - if is_xemacs: - return lisp.mark() - else: - return lisp("mark-active") and lisp.mark() - - - -def _switchToConsole(): - consolebuf = lisp.get_buffer_create("BicycleRepairManConsole") - lisp.switch_to_buffer_other_window(consolebuf) - lisp.compilation_mode("BicycleRepairMan") - lisp.erase_buffer() - lisp.insert("Bicycle Repair Man\n") - lisp.insert("(Hint: Press Return a Link)\n") - -def find_definition(): - brmemacs.find_definition() -find_definition.interaction="" - -def _insertRefLineIntoConsole(ref): - lisp.insert(ref.filename+":"+str(ref.lineno)+": "+str(ref.confidence)+"% confidence\n") - _redisplayFrame() - -def _redisplayFrame(): - lisp.sit_for(0) - -def inline_local_variable(): - brmemacs.inline_local_variable() -inline_local_variable.interaction="" - -def extract_local_variable(name): - brmemacs.extract_local_variable(name) -extract_local_variable.interaction="sVariable name: " - - -def extract_method(name): - brmemacs.extract_method(name) -extract_method.interaction="sName of function: " - - -def move_class(newfilename): - return brmemacs.move_class(newfilename) -move_class.interaction="fTarget file: " - - - -def _getPointCoords(): - bline = lisp.count_lines(1,lisp.point()) - bcol = lisp.current_column() - if bcol == 0: # get round line is one less if col is 0 problem - bline += 1 - return bline,bcol - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/test/README --- a/vim/sadness/bike/ide-integration/test/README Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -Test Steps for testing idle integration ---------------------------------------- - -N.B. this test script is not expected to test all of bicyclerepairman -- the pyunit tests do that. It is merely there to test the integration -with idle (which doesnt get tested by pyunit). - - -------------- Rename * ----------------------------------------- - -- Load scrap.py - -- Rename Class to MyRenamedClass - (Check it renames the class) - -- Undo the rename - -- Create scrap3.py, containing the following: - ---------------------------- -import scrap - -a = scrap.MyClass() -a.myMethod() --------------------------- - -- Go back to scrap.py and rename the method to MyRenamedMethod - (Check that it prompts for rename in scrap2.py - rename the - first, but not the second) - (Check that it renames all the methods in scrap2.py and scrap3.py - except for the one you said no to) - -- Undo the rename - (Check that it undid all the renamings in all the files) - -------------- Find References ---------------------------------- - - -- Goto scrap.py, select 'find references'. Check that it tells you to -highlight a class/function/method. - -- Highlight 'myMethod' and try again Check that it displays a list of -references to this method. - - -------------- Find Definition ---------------------------------- - -- Goto scrap2.py, click 'myMethod' on d.myMethod(), then select 'find -definition'. Check that it displays both the myMethod in MyClass and -in AnotherClass. - - -- Goto scrap2.py, click 'myMethod' on e.myMethod(), then select 'find -definition'. Check that it takes you to the definition, and doesn't -display a list of myMethod() references. - - -------------- Extract Method / Function ------------------------ - -- Load extractMethod.py into idle - -- select 'Extract Method' without first selecting a region - (Check that it tells you to select the region) - -- Use extractMethod to extract the marked line from the function - -- Use extractMethod to extract the lines of code from the method - -- Undo the extract Method - -- Undo the extract Function - -- Undo again - confirm that a dialog box pops up telling you the stack -is empty. - - -------------- Extract / Inline local variable ------------------ - -- Load extractMethod.py into the ide - -- In the function 'inlineVariableTest', extract the marked code into a -variable - -- Inline the variable back into the code - ----------------------------------------------------------------- - -- exit from the ide, and delete scrap3.py from the directory - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/test/extractmethod.py --- a/vim/sadness/bike/ide-integration/test/extractmethod.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -def myFunction(): - a = 3 - print "hello"+a # extract me - -class MyClass: - def myMethod(self): - b = 12 # extract me - c = 3 # and me - d = 2 # and me - print b, c - - -def inlineVariableTest(): - a = b + 3 - 5 - # --^^^^^ - Extract this into variable - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/test/scrap.py --- a/vim/sadness/bike/ide-integration/test/scrap.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -class MyClass: - def myMethod(self, foo): - pass - -a = MyClass() - -a.myMethod() - - -class AnotherClass: - def myMethod(self,foo): - pass - -def testFunction(): - print "hello" - - -print "hello" - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/ide-integration/test/scrap2.py --- a/vim/sadness/bike/ide-integration/test/scrap2.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -from scrap import MyClass, testFunction - -b = MyClass() - -b.myMethod() - - -c = abcde() - -c.myMethod() - - -d = defgh() - -d.myMethod() - - -e = MyClass() - -e.myMethod() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/setup.py --- a/vim/sadness/bike/setup.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -import sys -import os,glob -from distutils.core import setup - -# check version -if sys.version_info[0] < 2 or sys.version_info[0] == 2 and sys.version_info[1] < 2: - print "Python versions below 2.2 not supported" - sys.exit(0) - - -setup(name="bicyclerepair", - version="0.9", - description="Bicycle Repair Man, the Python refactoring tool", - maintainer="Phil Dawes", - maintainer_email="pdawes@users.sourceforge.net", - url="http://bicyclerepair.sourceforge.net", - packages=['','bike','bike.refactor','bike.parsing','bike.query','bike.transformer'], - package_dir = {'bike':'bike','':'ide-integration'} - ) - diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/bike/testall.py --- a/vim/sadness/bike/testall.py Thu Feb 10 17:11:26 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/usr/bin/env python - -import sys,os - -# check version -if sys.version_info[0] < 2 or sys.version_info[0] == 2 and sys.version_info[1] < 2: - print "Python versions below 2.2 not supported" - sys.exit(0) - -if not os.path.abspath(".") in sys.path: - sys.path.append(os.path.abspath(".")) - - -from bike import logging - -from bike.test_testutils import * -from bike.parsing.testall import * -from bike.query.testall import * -from bike.refactor.testall import * -from bike.testall import * - -if __name__ == "__main__": - from bike import logging - logging.init() - log = logging.getLogger("bike") - log.setLevel(logging.WARN) - unittest.main() diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 vim/sadness/sadness.vim --- a/vim/sadness/sadness.vim Thu Feb 10 17:11:26 2011 -0500 +++ b/vim/sadness/sadness.vim Thu Feb 17 15:23:03 2011 -0500 @@ -1,7 +1,4 @@ let $rope_pypath = $HOME."/.vim/sadness/ropevim/pylibs" -let $bike_pypath = $HOME."/.vim/sadness/bike" -let $PYTHONPATH = $rope_pypath.":".$bike_pypath.":".$PYTHONPATH +let $PYTHONPATH = $rope_pypath.":".$PYTHONPATH source $HOME/.vim/sadness/ropevim/src/ropevim/ropevim.vim - -source $HOME/.vim/sadness/bike/ide-integration/bike.vim diff -r 9bd6d1ef0a9f -r 4bd40ce732d7 zsh/misc.zsh --- a/zsh/misc.zsh Thu Feb 10 17:11:26 2011 -0500 +++ b/zsh/misc.zsh Thu Feb 17 15:23:03 2011 -0500 @@ -63,3 +63,13 @@ # hgd alias h='~/src/hgd/hd' + +# What the hell did I do the other day? +function whatthehelldididoon() { + for repo in `find . -name '.hg'` + do + echo $repo + h .. -R $repo/.. -d "$1" -u 'Steve Losh' + done +} +