#@+leo-ver=4-thin
#@+node:ktenney.20041211072654.1:@thin at_view.py
#@<< docstring >>
#@+node:ekr.20041231104454:<< docstring >>
'''A plugin that supports ``@clip``, ``@view`` and ``@strip`` nodes.
- Selecting a headline containing ``@clip`` appends the contents of the clipboard to
the end of the body pane.
- Double clicking the icon box of a node whose headline contains ``@view <path-to-file>``
places the contents of the file in the body pane.
- Double clicking the icon box of a node whose headline contains ``@strip <path-to-file>``
places the contents of the file in the body pane, with all sentinels removed.
This plugin also accumulates the effect of all ``@path`` nodes.
'''
#@nonl
#@-node:ekr.20041231104454:<< docstring >>
#@nl
#@@language python
#@@tabwidth -4
#@@pagewidth 80
__version__ = "0.7"
#@<< version history >>
#@+node:ktenney.20041211072654.3:<< version history >>
#@+at
#
# 0.1 KT 2004/12/07 begin converting @button to plugin
#
# 0.2 EKR style changes:
# - Uses g.trace to simplify all traces.
# - Removed comments originating from style guide.
# - Defined __version__ only in root node.
# 0.3 EKR:
# - Used g.importExtension to import path and win32clipboard.
# - Added extensive comments to module's doc string.
# - Added comments to class View node.
# - Commented out several traces.
# - Handle @verbatim sentinels in strip()
# - Fix bug in strip: set path = currentPath.abspath()
# 0.4 EKR:
# - Handle case where self.c has been destroyed in idle handler.
# 0.5 EKR:
# - Corrected and expanded doc string.
# 0.6 EKR:
# - Added better error message if can't load extensions.
# 0.7 EKR:
# - Simplified code, fixed bugs and improved error messages.
#@-at
#@nonl
#@-node:ktenney.20041211072654.3:<< version history >>
#@nl
#@<< imports >>
#@+node:ktenney.20041211072654.4:<< imports >>
import leo.core.leoGlobals as g
import leo.core.leoPlugins as leoPlugins
path = g.importExtension('path', pluginName=__name__,verbose=True)
win32clipboard = g.importExtension('win32clipboard',pluginName=__name__,verbose=True)
#@nonl
#@-node:ktenney.20041211072654.4:<< imports >>
#@nl
#@+others
#@+node:ktenney.20041211072654.6:onCreate
def onCreate(tag, keywords):
c = keywords.get("c")
if not c: return
myView = View(c)
# Register the handlers...
leoPlugins.registerHandler("icondclick2", myView.icondclick2)
leoPlugins.registerHandler("idle", myView.idle)
g.plugin_signon(__name__)
#@nonl
#@-node:ktenney.20041211072654.6:onCreate
#@+node:ktenney.20041211072654.7:class View
class View:
'''A class to support @view, @strip and @clip nodes.'''
#@ @+others
#@+node:ktenney.20041211072654.8:__init__
def __init__ (self,c):
self.c = c
# g.trace('View')
#@nonl
#@-node:ktenney.20041211072654.8:__init__
#@+node:ktenney.20041211072654.9:icondclick2
def icondclick2 (self, tag, keywords):
self.current = self.c.p
hs = self.current.h
g.trace(hs)
if hs.startswith('@view'):
self.view()
if hs.startswith('@strip'):
self.strip()
#@nonl
#@-node:ktenney.20041211072654.9:icondclick2
#@+node:ktenney.20041211203715:idle
def idle(self, tag, keywords):
try:
self.current = self.c.p
except AttributeError:
# c has been destroyed.
return
s = self.current.h
if s.startswith("@clip"):
self.clip()
#@nonl
#@-node:ktenney.20041211203715:idle
#@+node:ktenney.20041211072654.10:view
def view(self):
'''Place the contents of a file in the body pane
the file is either in the current headstring,
or found by ascending the tree
'''
# get a path object for this position
currentPath = self.getCurrentPath()
# g.trace(currentPath.exists(),currentPath)
if currentPath.exists():
g.es('currentPath: %s' % currentPath.abspath())
if currentPath.isfile():
self.processFile(currentPath, self.current)
if currentPath.isdir():
self.processDirectory(currentPath, self.current)
else:
g.es('path does not exist: %s' % (str(currentPath)),color='blue')
#@nonl
#@-node:ktenney.20041211072654.10:view
#@+node:ktenney.20041212102137:clip
def clip(self):
'''Watch the clipboard, and copy new items to the body.'''
if not win32clipboard:
return
c = self.c
divider = '\n' + ('_-' * 34) + '\n'
win32clipboard.OpenClipboard()
clipboard = ""
if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_TEXT):
clipboard = win32clipboard.GetClipboardData()
else:
banner = '*' * 8
clipboard = banner + 'Image data was copied to the clipboard' + banner
win32clipboard.CloseClipboard()
body = self.current.b.split(divider)
if not body[0] == clipboard:
g.es('clipboard now holds %s' % clipboard)
body.insert(0, clipboard)
c.setBodyText(self.current,divider.join(body))
#@nonl
#@-node:ktenney.20041212102137:clip
#@+node:ktenney.20041211072654.15:strip
def strip(self):
'''Display a file with all sentinel lines removed'''
# get a path object for this position
c = self.c
currentPath = self.getCurrentPath()
# g.trace(currentPath.exists(),currentPath)
if currentPath.exists():
path = currentPath.abspath()
s = 'currentPath: %s' % path
g.es_print(s)
filelines = path.lines()
# Add an @ignore directive.
lines = ['@ignore\n']
verbatim = False
for line in filelines:
if verbatim:
lines.append(line)
verbatim = False
elif line.strip().startswith('#@verbatim'):
verbatim = True
elif not line.strip().startswith('#@'):
lines.append(line)
c.setBodyText(self.current,''.join(lines))
else:
g.es('path does not exist: %s' % (str(currentPath)),color='blue')
#@nonl
#@-node:ktenney.20041211072654.15:strip
#@+node:ktenney.20041211072654.11:getCurrentPath
def getCurrentPath(self):
""" traverse the current tree and build a path
using all @path statements found
"""
pathFragments = []
# we are currently in a @view node; get the file or directory name
pathFragments.append(self.getPathFragment(self.current))
for p in self.current.parents():
pathFragments.append(self.getPathFragment(p))
if pathFragments:
currentPath = path.path(pathFragments.pop())
while pathFragments:
# pop takes the last appended, which is at the top of the tree
# build a path from the fragments
currentPath = currentPath / path.path(pathFragments.pop())
return currentPath.normpath()
#@nonl
#@-node:ktenney.20041211072654.11:getCurrentPath
#@+node:ktenney.20041211072654.12:getPathFragment
def getPathFragment (self,p):
"""
Return the path fragment if this node is a @path or @view or any @file node.
"""
head = p.h
for s in ('@path','@view','@strip','@file','@thin','@nosent','@asis'):
if head.startswith(s):
fragment = head [head.find(' '):].strip()
# g.trace(repr(fragment))
return fragment
return ''
#@nonl
#@-node:ktenney.20041211072654.12:getPathFragment
#@+node:ktenney.20041211072654.13:processFile
def processFile(self, path, node):
"""parameters are a path object and a node.
the path is a file, place it's contents into the node
"""
g.trace(node)
self.c.setBodyText(node,''.join(path.lines()))
#@nonl
#@-node:ktenney.20041211072654.13:processFile
#@+node:ktenney.20041211072654.14:processDirectory
def processDirectory(self, path, node):
"""
create child nodes for each member of the directory
@path is a path object for a directory
@node is the node to work with
"""
c = self.c
# delete all nodes before creating, to avoid duplicates
while node.firstChild():
node.firstChild().doDelete(node)
for file in path.files():
child = node.insertAsLastChild()
c.setHeadString(child,'@view %s' % file.name)
for file in path.dirs():
child = node.insertAsLastChild()
c.setHeadString(child,'@view %s' % file.name)
#@-node:ktenney.20041211072654.14:processDirectory
#@-others
#@nonl
#@-node:ktenney.20041211072654.7:class View
#@-others
if path and win32clipboard: # Ok for unit testing.
leoPlugins.registerHandler("after-create-leo-frame",onCreate)
elif not g.app.unitTesting:
s = 'at_view plugin not loaded: win32Clipboard not present.'
g.es_print(s)
#@nonl
#@-node:ktenney.20041211072654.1:@thin at_view.py
#@-leo
|