vim/vim/plugin/trac.py

1574 lines
59 KiB
Python

import os
import sys
import vim
import xmlrpclib
import re
########################
# RPC Base Class
########################
class TracRPC:
""" General xmlrpc RPC routines """
def __init__ (self, server_url):
self.server_url = server_url
self.server = xmlrpclib.ServerProxy(server_url)
self.multicall = xmlrpclib.MultiCall(self.server)
def setServer (self, url):
self.server_url = url
self.server = xmlrpclib.ServerProxy(url)
########################
# User Interface Base Classes
########################
class VimWindow:
""" wrapper class of window of vim """
def __init__(self, name = 'WINDOW'):
""" initialize """
self.name = name
self.buffer = None
self.firstwrite = 1
self.winnr = 0
def isprepared(self):
""" check window is OK """
if self.buffer == None or len(dir(self.buffer)) == 0 or self.getwinnr() == -1:
return 0
return 1
def prepare(self):
""" check window is OK, if not then create """
if not self.isprepared():
self.create()
def on_create(self):
""" On Create is used by the VimWindow subclasses to define vim
mappings and buffer settings
"""
pass
def getwinnr(self):
""" Returns the vim window number for wincmd calls """
return int(vim.eval("bufwinnr('"+self.name+"')"))
def write(self, msg):
""" write to a vim buffer """
self.prepare()
if self.firstwrite == 1:
self.firstwrite = 0
#TODO tickets #7 and #56 setting to utf-8 causes sporadic ticket Encoding errors
msg = msg.encode('utf-8', 'ignore')
#msg = msg.encode('ascii', 'ignore')
self.buffer[:] = str(msg).split('\n')
else:
self.buffer.append(str(msg).split('\n'))
self.command('normal gg')
self.on_write()
def on_before_write(self):
pass
def on_write(self):
''' for vim commands after a write is made to a buffer '''
pass
def dump (self):
""" returns the contents buffer as a string """
return "\n".join (self.buffer[:])
def create(self, method = 'new'):
""" creates a window """
vim.command('silent ' + method + ' ' + self.name)
vim.command("setlocal buftype=nofile")
self.buffer = vim.current.buffer
self.width = int( vim.eval("winwidth(0)") )
self.height = int( vim.eval("winheight(0)") )
self.winnr = self.getwinnr()
self.on_create()
def destroy(self):
""" destroy window """
if self.buffer == None or len(dir(self.buffer)) == 0:
return
#if self.name == 'LOG___WINDOW':
# self.command('hide')
#else:
self.command('bdelete ' + self.name)
self.firstwrite = 1
def clean(self):
""" clean all datas in buffer """
self.prepare()
self.buffer[:] = []
self.firstwrite = 1
def command(self, cmd):
""" go to my window & execute command """
self.prepare()
winnr = self.getwinnr()
if winnr != int(vim.eval("winnr()")):
vim.command(str(winnr) + 'wincmd w')
vim.command(cmd)
def set_focus(self):
""" Set focus on the current window """
vim.command( str(self.winnr) + ' wincmd w')
def resize_width(self, size = False):
""" resizes to default width or specified size """
self.set_focus()
if size == False:
size = self.width
vim.command('vertical resize ' + str(size))
class NonEditableWindow(VimWindow):
def on_before_write(self):
vim.command("setlocal modifiable")
def on_write(self):
pass
vim.command("setlocal nomodifiable")
def clean(self):
""" clean all datas in buffer """
self.prepare()
vim.command('setlocal modifiable')
self.buffer[:] = []
self.firstwrite = 1
class UI:
""" User Interface Base Class """
def __init__(self):
""" Initialize the User Interface """
def open(self):
""" change mode to a vim window view """
if self.mode == 1: # is wiki mode ?
return
self.mode = 1
self.create()
def normal_mode(self):
""" restore mode to normal """
if self.mode == 0: # is normal mode ?
return
# destory all created windows
self.destroy()
#self.winbuf.clear()
self.file = None
self.line = None
self.mode = 0
self.cursign = None
########################
# Wiki Module
########################
class TracWiki(TracRPC):
""" Trac Wiki Class """
def __init__ (self, server_url):
TracRPC.__init__(self, server_url)
self.a_pages = []
self.revision = 1
self.currentPage = False
def getAllPages(self):
""" Gets a List of Wiki Pages """
self.a_pages = self.server.wiki.getAllPages()
return "\n".join(self.a_pages)
def getPage(self, name, b_create = False, revision = None):
""" Get Wiki Page """
global trac
self.currentPage = name
try:
if revision == None:
wikitext = self.server.wiki.getPage(name)
else:
wikitext = self.server.wiki.getPage(name,revision)
except:
wikitext = "Describe " + name + " here."
if b_create == True:
try:
self.server.wiki.putPage(name, wikitext, {"comment" : "Initializing"})
return wikitext
except:
print "Could not create page " + name
else:
print "Could not find page " + name + ". Use :TWCreate " + name+ " to create it"
#TODO this will create the page anyway. possible bug if theres a network error
self.currentPage = name
return "Describe " + name + " here."
return wikitext
def save (self, comment):
""" Saves a Wiki Page """
global trac
if comment == '':
comment = trac.default_comment
self.server.wiki.putPage(self.currentPage, trac.uiwiki.wikiwindow.dump() , {"comment" : comment})
def get_page_info(self):
""" Returns page revision info most recent author """
info = self.server.wiki.getPageInfo(self.currentPage)
self.revision = info['version']
return 'Page: ' + info['name'] + ' Revision: ' + str(info['version']) + ' Author: ' + info['author']
def createPage (self, name, content, comment):
""" Saves a Wiki Page """
return self.server.wiki.putPage(name, content , {"comment" : comment})
def addAttachment (self, file):
''' Add attachment '''
file_name = os.path.basename (file)
self.server.wiki.putAttachment(self.currentPage + '/' + file_name , xmlrpclib.Binary(open(file).read()))
def getAttachment (self, file):
''' Add attachment '''
buffer = self.server.wiki.getAttachment( file )
file_name = os.path.basename (file)
if os.path.exists(file_name) == False:
fp = open(file_name , 'w')
fp.write (buffer.data)
fp.close()
else:
print "Will not overwrite existing file " + file_name
def listAttachments(self):
""" Look for attachments on the current page """
self.current_attachments = self.server.wiki.listAttachments(self.currentPage)
def getWikiHtml(self, wikitext):
""" Converts the wikitext from a buffer to html for previews """
return self.server.wiki.wikiToHtml(wikitext)
def html_view(self, page):
""" Displays a wiki in a preview browser as set in trac.vim """
global browser
if page == False:
page = vim.current.line
html = '<html><body>' + self.server.wiki.getPageHTML(page)+ '</body></html>'
file_name = vim.eval ('g:tracTempHtml')
fp = open(file_name , 'w')
fp.write (html)
fp.close()
vim.command ('!' + browser +" file://" + file_name)
def get_options (self):
""" returns a list of a sites wiki pages for command completes """
vim.command ('let g:tracOptions = "' + "|".join (self.a_pages) + '"')
def vim_diff(self, revision = None):
""" Creates a vimdiff of an earlier wiki revision """
global trac
#default to previous revision
if revision == None:
revision = self.revision - 1
diffwindow = WikiVimDiffWindow()
diffwindow.create('vertical belowright diffsplit')
wikitext = self.getPage(self.currentPage, False, revision)
if wikitext != False:
diffwindow.write(wikitext)
trac.uiwiki.tocwindow.resize_width(30)
trac.uiwiki.wikiwindow.set_focus()
#trac.uiwiki.wikiwindow.resize_width(int (trac.uiwiki.wikiwindow.width / 2))
diffwindow.resize_width(80)
class TracWikiUI(UI):
""" Trac Wiki User Interface Manager """
def __init__(self):
""" Initialize the User Interface """
self.wikiwindow = WikiWindow()
self.tocwindow = WikiTOContentsWindow()
self.wiki_attach_window = WikiAttachmentWindow()
self.mode = 0 #Initialised to default
#self.winbuf = {}
def destroy(self):
""" destroy windows """
self.wikiwindow.destroy()
self.tocwindow.destroy()
self.wiki_attach_window.destroy()
vim.command ("call UnloadWikiCommands()")
def create(self):
""" create windows and load the internal Commands """
vim.command ("call LoadWikiCommands()")
style = vim.eval ('g:tracWikiStyle')
if style == 'full':
vim.command('tabnew')
self.wikiwindow.create(' 30 vnew')
vim.command('call TracOpenViewCallback()')
vim.command ("only")
self.tocwindow.create("vertical aboveleft new")
return False
if style == 'top':
self.wikiwindow.create("aboveleft new")
self.tocwindow.create("vertical aboveleft new")
return False
self.tocwindow.create("belowright new")
self.wikiwindow.create("vertical belowright new")
class WikiWindow (VimWindow):
""" Wiki Window """
def __init__(self, name = 'WIKI_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> <c-]> :python trac.wiki_view ("<C-R><C-W>")<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
vim.command('nnoremap <buffer> :wq<cr> :python trac.save_wiki('')<cr>:python trac.normal_view()<cr>')
vim.command('nnoremap <buffer> <2-LeftMouse> :python trac.wiki_view("<C-R><C-W>")<cr>')
#map gf to a new buffer (switching buffers doesnt work with nofile)
vim.command('nnoremap <buffer> gf <c-w><c-f><c-w>K')
vim.command('vertical resize +70')
vim.command('nnoremap <buffer> :w<cr> :TWSave')
vim.command('setlocal syntax=wiki')
vim.command('setlocal linebreak')
vim.command('setlocal noswapfile')
class WikiTOContentsWindow (NonEditableWindow):
""" Wiki Table Of Contents """
def __init__(self, name = 'WIKITOC_WINDOW'):
VimWindow.__init__(self, name)
if vim.eval('tracHideTracWiki') == 'yes':
self.hide_trac_wiki = True
else:
self.hide_trac_wiki = False
def on_create(self):
vim.command('nnoremap <buffer> <cr> :python trac.wiki_view("CURRENTLINE")<cr>')
vim.command('nnoremap <buffer> <2-LeftMouse> :python trac.wiki_view("CURRENTLINE")<cr>')
vim.command('nnoremap <buffer> <Space> :python trac.html_view ()<cr><cr><cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
vim.command('setlocal winwidth=30')
vim.command('vertical resize 30')
vim.command('setlocal cursorline')
vim.command('setlocal linebreak')
vim.command('setlocal noswapfile')
def on_write(self):
if self.hide_trac_wiki == True:
vim.command('silent g/^Trac/d _')
vim.command('silent g/^Wiki/d _')
vim.command('silent g/^InterMapTxt$/d _')
vim.command('silent g/^InterWiki$/d _')
vim.command('silent g/^SandBox$/d _')
vim.command('silent g/^InterTrac$/d _')
vim.command('silent g/^TitleIndex$/d _')
vim.command('silent g/^RecentChanges$/d _')
vim.command('silent g/^CamelCase$/d _')
vim.command('sort')
vim.command('silent norm ggOWikiStart')
NonEditableWindow.on_write(self)
class WikiAttachmentWindow(NonEditableWindow):
""" Wiki's attachments """
def __init__(self, name = 'WIKIATT_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> <cr> :python trac.get_attachment("CURRENTLINE")<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
#vim.command('setlocal winwidth=30')
#vim.command('vertical resize 30')
vim.command('setlocal cursorline')
vim.command('setlocal linebreak')
vim.command('setlocal noswapfile')
class WikiVimDiffWindow (NonEditableWindow):
""" For Earlier revisions """
def __init__(self, name = 'WIKI_DIFF_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> <c-]> :python trac.wiki_view ("<C-R><C-W>")<cr>')
vim.command('nnoremap <buffer> :q!<cr> :python trac.uiwiki.tocwindow.resize_width(30)<cr>')
#map gf to a new buffer (switching buffers doesnt work with nofile)
vim.command('nnoremap <buffer> gf <c-w><c-f><c-w>K')
vim.command('vertical resize +70')
vim.command('setlocal syntax=wiki')
vim.command('setlocal linebreak')
vim.command('setlocal noswapfile')
########################
# Search Module
########################
class TracSearch(TracRPC):
""" Search for tickets and Wiki's """
def __init__ (self, server_url):
TracRPC.__init__(self, server_url)
def search(self , search_pattern):
""" Perform a search call """
a_search = self.server.search.performSearch(search_pattern)
str_result = "Results for " + search_pattern + "\n\n"
str_result += "(Hit <enter> or <space >on a line containing Ticket:>>)"
for search in a_search:
if search[0].find('/ticket/') != -1:
str_result += "\nTicket:>> " + os.path.basename (search[0])+ "\n "
if search[0].find('/wiki/')!= -1:
str_result += "\nWiki:>> " + os.path.basename(search[0]) + "\n "
if search[0].find('/changeset/')!= -1:
str_result += "\nChangeset:>> " + search[0] + "\n " #os.path.basename(search[0])
str_result += "\n ".join (search[4].strip().split("\n")) + "\n"
str_result += "\n-------------------------------------------------"
return str_result
class TracSearchUI(UI):
""" Search UI manager """
def __init__(self):
""" Initialize the User Interface """
self.searchwindow = TracSearchWindow()
self.mode = 0 #Initialised to default
#self.winbuf = {}
def destroy(self):
""" destroy windows """
self.searchwindow.destroy()
def create(self):
""" create windows """
style = vim.eval ('g:tracSearchStyle')
if style == 'right':
self.searchwindow.create("vertical belowright new")
else:
self.searchwindow.create("vertical aboveleft new")
class TracSearchWindow(NonEditableWindow):
""" for displaying search results """
def __init__(self, name = 'SEARCH_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
""" Buffer Specific Mappings for The Search Window """
vim.command('nnoremap <buffer> <c-]> :python trac.wiki_view ("<cword>")<cr>')
vim.command('nnoremap <buffer> <cr> :python trac.search_open(False)<cr>')
#vim.command('nnoremap <buffer> <space> :python trac.search_open(True)<cr>') This messes folds
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
vim.command('setlocal syntax=text')
vim.command('setlocal foldmethod=indent')
vim.command('setlocal linebreak')
vim.command('setlocal noswapfile')
def on_write (self):
""" Basic Highlighting """
NonEditableWindow.on_write(self)
vim.command('syntax reset')
vim.command('syn match Keyword /\w*:>> .*$/ contains=Title')
vim.command('syn match Title /\w*:>>/ contained')
#vim.command('highlight Title ctermbg=255 guibg=255')
vim.command('syn match SpecialKey /^-*$/')
########################
# Ticket Module
########################
class TracTicket(TracRPC):
""" Trac Ticket Class """
def __init__ (self, server_url):
TracRPC.__init__(self, server_url)
self.current_ticket_id = False
self.a_option = []
self.a_tickets = []
self.filter = TracTicketFilter()
self.sort = TracTicketSort()
def setServer (self, url):
self.server = xmlrpclib.ServerProxy(url)
self.getOptions()
def getOptions (self):
""" Get all milestone/ priority /status options """
multicall = xmlrpclib.MultiCall(self.server)
multicall.ticket.milestone.getAll()
multicall.ticket.type.getAll()
multicall.ticket.status.getAll()
multicall.ticket.resolution.getAll()
multicall.ticket.priority.getAll()
multicall.ticket.severity.getAll()
multicall.ticket.component.getAll()
a_option = []
for option in multicall():
a_option.append(option)
for milestone in a_option[0]:
multicall.ticket.milestone.get(milestone)
a_option.append(multicall())
self.a_option = a_option
def getAllTickets(self,owner, b_use_cache = False):
""" Gets a List of Ticket Pages """
if self.a_option == []:
self.getOptions()
if b_use_cache:
tickets = self.a_tickets
else:
multicall = xmlrpclib.MultiCall(self.server)
#for ticket in self.server.ticket.query("owner=" + owner):
for ticket in self.server.ticket.query(vim.eval('g:tracTicketClause')):
multicall.ticket.get(ticket)
tickets = multicall()
self.a_tickets = tickets
tickets = self.sort.sort(tickets)
ticket_list = "(Hit <enter> or <space> on a line containing Ticket:>>)\n"
if self.filter.filters != []:
ticket_list += "(filtered)\n"
i = 1
ticket_list += self.filter.list()
milestone = ''
for ticket in tickets:
if ticket[3]["status"] != "closed" and self.filter.check(ticket):
str_ticket = ''
#This wont work without ordering
#last_milestone = ticket[3]["milestone"]
#if milestone != last_milestone and last_milestone != '':
#milestone = ticket[3]["milestone"]
#str_ticket += "\n--------------------------------------------" + "\n"
#str_ticket += 'MILESTONE: ' + milestone + "\n"
#str_ticket += "--------------------------------------------" + "\n"
str_ticket += "\nTicket:>> " + str(ticket[0]) + "\n"
str_ticket += " * Summary: " + ticket[3]["summary"] + "\n"
str_ticket += " * Priority: " + ticket[3]["priority"] + "\n"
str_ticket += " * Status: " + ticket[3]["status"] + "\n"
milestone = ticket[3]["milestone"]
if (milestone == ''):
milestone = 'NOMILESTONE'
component = ticket[3]["component"]
if (component == ''):
component = 'NOCOMPONENT'
str_ticket += " * Component: " + component + "\n"
str_ticket += " * Milestone: " + milestone + "\n"
str_ticket += " * Type: " + ticket[3]["type"] + "\n"
str_ticket += " * Owner: " + ticket[3]["owner"] + "\n "
if self.session_is_present(ticket[0]):
str_ticket += " * Session: PRESENT \n"
str_ticket += "\n ".join (ticket[3]["description"].strip().split("\n")) + "\n"
#str_ticket += "--------------------------------------------"
ticket_list += str_ticket
ticket_list += "\n"
return ticket_list
def getAllTicketsSummary(self,owner, b_use_cache = False):
""" Gets a List of Ticket Pages """
if self.a_option == []:
self.getOptions()
if b_use_cache:
tickets = self.a_tickets
else:
multicall = xmlrpclib.MultiCall(self.server)
#for ticket in self.server.ticket.query("owner=" + owner):
for ticket in self.server.ticket.query():
multicall.ticket.get(ticket)
tickets = multicall()
self.a_tickets = tickets
#ticket_list = "(Hit <enter> or <space> on a line containing Ticket:>>)\n"
ticket_list = ""
#if self.filter.filters != []:
#ticket_list += "(filtered)\n"
#i = 1
#ticket_list += self.filter.list()
milestone = ''
tickets = self.sort.sort(tickets)
for ticket in tickets:
if ticket[3]["status"] != "closed" and self.filter.check(ticket):
str_ticket = ''
#This wont work without ordering
#last_milestone = ticket[3]["milestone"]
#if milestone != last_milestone and last_milestone != '':
#milestone = ticket[3]["milestone"]
#str_ticket += "\n--------------------------------------------" + "\n"
#str_ticket += 'MILESTONE: ' + milestone + "\n"
#str_ticket += "--------------------------------------------" + "\n"
str_ticket += "" + str(ticket[0])
str_ticket += ". || " + ticket[3]["summary"][0:50]
if len(ticket[3]["summary"]) > 50 :
str_ticket += "..."
str_ticket += " || " + ticket[3]["priority"]
str_ticket += " || " + ticket[3]["status"]
milestone = ticket[3]["milestone"]
if (milestone == ''):
milestone = 'NOMILESTONE'
component = ticket[3]["component"]
if (component == ''):
component = 'NOCOMPONENT'
str_ticket += " || " + component
str_ticket += " || " + milestone
str_ticket += " || " + ticket[3]["type"]
str_ticket += " || " + ticket[3]["owner"] + "\n"
#if self.session_is_present(ticket[0]):
#str_ticket += " || Session: PRESENT \n"
#str_ticket += "\n ".join (ticket[3]["description"].strip().split("\n")) + "\n"
#str_ticket += "--------------------------------------------"
ticket_list += str_ticket
ticket_list += "\n"
return ticket_list
def getTicket(self, id):
""" Get Ticket Page """
#print "Fetching: " + str(id)
ticket = self.server.ticket.get(int (id))
self.current_ticket_id = id
self.current_component = ticket[3]["component"]
self.listAttachments()
ticket_changelog = self.server.ticket.changeLog(id)
#ticket_options = self.server.ticket.getAvailableActions(id)
str_ticket = "= Ticket Summary =\n\n"
str_ticket += "* Ticket ID: " + str(ticket[0]) + "\n"
str_ticket += "* Owner: " + ticket[3]["owner"] + "\n"
str_ticket += "* Status: " + ticket[3]["status"] + "\n"
str_ticket += "* Summary: " + ticket[3]["summary"] + "\n"
str_ticket += "* Type: " + ticket[3]["type"] + "\n"
str_ticket += "* Priority: " + ticket[3]["priority"] + "\n"
str_ticket += "* Component: " + ticket[3]["component"] + "\n"
str_ticket += "* Milestone: " + ticket[3]["milestone"] + "\n"
if ticket[3].has_key('version'):
str_ticket += "* Version: " + ticket[3]["version"] + "\n"
#look for session files
if self.session_is_present():
str_ticket += "* Session: PRESENT \n"
else:
str_ticket += "* Session: not present\n"
str_ticket += "* Attachments: " + "\n"
for attach in self.current_attachments:
str_ticket += ' ' + attach
str_ticket += "\n---------------------------------------------------\n"
str_ticket += "= Description: =\n\n "
str_ticket += "\n ".join (ticket[3]["description"].strip().split("\n")) + "\n"
str_ticket += "= CHANGELOG =\n\n"
import datetime
for change in ticket_changelog:
if change[4] != '':
if isinstance(change[0], xmlrpclib.DateTime):
dt = datetime.datetime.strptime(change[0].value, "%Y%m%dT%H:%M:%S")
else:
dt = datetime.datetime.fromtimestamp(change[0])
my_time = dt.strftime("%a %d/%m/%Y %H:%M:%S")
#just mention if a ticket has been changed
brief = vim.eval('g:tracTicketBriefDescription')
if change[2] == 'comment':
str_ticket += '== ' + my_time + " (" + change[1] + ": comment) ==\n "
str_ticket += "\n ".join (change[4].strip().split("\n")) + "\n"
elif brief == 0:
if change[2] == 'description':
str_ticket += '== ' + my_time + " (" + change[1] + ": modified description) ==\n"
else :
str_ticket += '== ' + my_time + " (" + change[1] + " set " +change[2] +" to " + change[4] + ") ==\n"
return str_ticket
def updateTicket(self, comment, attribs = {}, notify = False):
""" add ticket comments change attributes """
return self.server.ticket.update(self.current_ticket_id,comment,attribs,notify)
def createTicket (self, description, summary, attributes = {}):
""" create a trac ticket """
self.current_ticket_id = self.server.ticket.create(summary, description, attributes, False)
def addAttachment (self, file):
''' Add attachment '''
file_name = os.path.basename (file)
self.server.ticket.putAttachment(self.current_ticket_id, file,'attachment' , xmlrpclib.Binary(open(file).read()))
def listAttachments(self):
a_attach = self.server.ticket.listAttachments(self.current_ticket_id)
self.current_attachments = []
for attach in a_attach:
self.current_attachments.append (attach[0])
def get_options(self,op_id):
vim.command ('let g:tracOptions = "' + "|".join (self.a_option[op_id]) + '"')
def getAttachment (self, file):
''' Add attachment '''
buffer = self.server.ticket.getAttachment( self.current_ticket_id , file )
file_name = os.path.basename (file)
if os.path.exists(file_name) == False:
fp = open(file_name , 'w')
fp.write (buffer.data)
fp.close()
else:
print "Will not overwrite existing file " + file_name
def set_attr (self,option,value):
global trac
if value == '':
print option + " was empty. No changes made."
return 0
if trac.uiticket.mode == 0 or trac.ticket.current_ticket_id == False:
print "Cannot make changes when there is no current ticket open in Ticket View"
return 0
comment = trac.uiticket.commentwindow.dump()
trac.uiticket.commentwindow.clean()
#if a milestone setting mate set status to assigned TODO Thisshuold be optional
if value == 'milestone':
attribs = {value:option, 'status':'assigned'}
else:
attribs = {value:option}
trac.ticket.updateTicket(comment, attribs, False)
trac.ticket_view(trac.ticket.current_ticket_id, True)
def add_comment(self):
""" Adds Comment window comments to the current ticket """
global trac
if trac.uiticket.mode == 0 or trac.ticket.current_ticket_id == False:
print "Cannot make changes when there is no current ticket is open in Ticket View"
return 0
comment = trac.uiticket.commentwindow.dump()
attribs = {}
if comment == '':
print "Comment window is empty. Not adding to ticket"
trac.ticket.updateTicket(comment, attribs, False)
trac.uiticket.commentwindow.clean()
trac.ticket_view(trac.ticket.current_ticket_id)
def update_description(self):
""" Adds Comment window as a description to the current ticket """
global trac
confirm = vim.eval('confirm("Overwrite Description?", "&Yes\n&No\n",2)')
if int (confirm) == 2:
print "Cancelled."
return False
if trac.uiticket.mode == 0 or trac.ticket.current_ticket_id == False:
print "Cannot make changes when there is no current ticket is open in Ticket View"
return 0
comment = trac.uiticket.commentwindow.dump()
attribs = {'description': comment}
if comment == '':
print "Comment window is empty. Not adding to ticket"
trac.ticket.updateTicket('', attribs, False)
trac.uiticket.commentwindow.clean()
trac.ticket_view(trac.ticket.current_ticket_id)
def create(self, summary = 'new ticket', type = False, server = False):
""" writes comment window to a new ticket """
global trac
#Used in quick tickets
if server != False:
trac.set_current_server(server,True, 'ticket')
description = ''
else:
description = trac.uiticket.commentwindow.dump()
if trac.uiticket.mode == 0 and server == False:
print "Can't create a ticket when not in Ticket View"
return 0
confirm = vim.eval('confirm("Create Ticket on ' + trac.server_name + '?", "&Yes\n&No\n",2)')
if int (confirm) == 2:
print "Cancelled."
return False
if type == False:
attribs = {}
else:
attribs = {'type':type}
if description == '' :
print "Description is empty. Ticket needs more info"
trac.ticket.createTicket(description,summary , attribs)
trac.uiticket.commentwindow.clean()
trac.ticket_view(trac.ticket.current_ticket_id)
def close_ticket(self, comment):
self.updateTicket(comment, {'status': 'closed'})
def resolve_ticket(self, comment, resolution):
self.updateTicket(comment, {'status': 'closed','resolution':resolution})
def session_save (self):
global trac
if self.current_ticket_id == False:
print "You need to have an active ticket"
return False
directory = vim.eval('g:tracSessionDirectory')
if os.path.isfile(directory) != False:
print "Cant create session directory"
return False
if os.path.isdir(directory) == False:
os.mkdir(directory)
serverdir = re.sub (r'[^\w]', '', trac.server_name)
if os.path.isdir(directory + '/' + serverdir) == False:
os.mkdir(directory + '/' + serverdir)
sessfile = directory + '/' + serverdir + "/vimsess." + str(self.current_ticket_id)
vim.command('mksession! ' + sessfile )
print "Session file Created: " + sessfile
def session_load (self):
global trac
if self.current_ticket_id == False:
print "You need to have an active ticket"
return False
serverdir = re.sub (r'[^\w]', '', trac.server_name)
directory = vim.eval('g:tracSessionDirectory')
sessfile = directory + '/' + serverdir + "/vimsess." + str(self.current_ticket_id)
if os.path.isfile(sessfile) == False:
print "This ticket does not have a session: " + sessfile
return False
vim.command("bdelete TICKETTOC_WINDOW")
vim.command("bdelete TICKET_WINDOW")
vim.command("bdelete TICKET_COMMENT_WINDOW")
vim.command('source ' + sessfile )
vim.command("bdelete TICKETTOC_WINDOW")
vim.command("bdelete TICKET_WINDOW")
vim.command("bdelete TICKET_COMMENT_WINDOW")
trac.ticket_view(self.current_ticket_id)
def session_component_save(self, component = False):
""" Save a session based on the component supplied or the current ticket """
global trac
if component == False:
if self.current_component == False:
print "You need to have an active ticket or a component as an argument"
return False
else:
component = self.current_component
directory = vim.eval('g:tracSessionDirectory')
if os.path.isfile(directory) != False:
print "Cant create session directory"
return False
if os.path.isdir(directory) == False:
os.mkdir(directory)
serverdir = re.sub (r'[^\w]', '', trac.server_name)
component = re.sub (r'[^\w]', '', component)
if os.path.isdir(directory + '/' + serverdir) == False:
os.mkdir(directory + '/' + serverdir)
sessfile = directory + '/' + serverdir + "/vimsess." + str(component)
vim.command('mksession! ' + sessfile )
print "Session file Created: " + sessfile
def session_component_load(self, component):
""" Loads a session based on the component supplied or the current ticket """
global trac
if component == False:
if self.current_component == False:
print "You need to have an active ticket or a component as an argument"
return False
else:
component = self.current_component
serverdir = re.sub (r'[^\w]', '', trac.server_name)
component = re.sub (r'[^\w]', '', component)
directory = vim.eval('g:tracSessionDirectory')
sessfile = directory + '/' + serverdir + "/vimsess." + str(component)
if os.path.isfile(sessfile) == False:
print "This ticket does not have a session: " + sessfile
return False
vim.command("bdelete TICKETTOC_WINDOW")
vim.command("bdelete TICKET_WINDOW")
vim.command("bdelete TICKET_COMMENT_WINDOW")
vim.command('source ' + sessfile )
vim.command("bdelete TICKETTOC_WINDOW")
vim.command("bdelete TICKET_WINDOW")
vim.command("bdelete TICKET_COMMENT_WINDOW")
trac.ticket_view(self.current_ticket_id)
def get_session_file(self, id = False):
global trac
if id == False:
id = self.current_ticket_id
directory = vim.eval('g:tracSessionDirectory')
serverdir = re.sub (r'[^\w]', '', trac.server_name)
return directory + '/' + serverdir + "/vimsess." + str (id)
def session_is_present(self, id = False):
sessfile = self.get_session_file(id)
return os.path.isfile(sessfile)
def set_summary(self, summary):
confirm = vim.eval('confirm("Overwrite Summary?", "&Yes\n&No\n",2)')
if int (confirm) == 2:
print "Cancelled."
return False
attribs = {'summary': summary}
trac.ticket.updateTicket('', attribs, False)
def context_set(self):
line = vim.current.line
if (re.match("Milestone:", line) != None):
self.get_options(0)
elif (re.match("Type:",line) != None):
self.get_options(1)
elif (re.match("Status:",line) != None):
self.get_options(2)
elif (re.match("Resolution:",line) != None):
self.get_options(3)
elif (re.match("Priority:",line) != None):
self.get_options(4)
elif (re.match("Severity:",line) != None):
self.get_options(5)
elif (re.match("Component:",line) != None):
self.get_options(6)
else:
print "This only works on ticket property lines"
#return False
self.get_options(0)
vim.command('setlocal modifiable')
setting = vim.eval("complete(col('.'), g:tracOptions)")
print setting
def summary_view(self):
global trac
trac.uiticket.summarywindow.create('belowright 10 new')
trac.uiticket.summarywindow.write(self.getAllTicketsSummary(trac.user,False ))
trac.uiticket.mode = 2
class TracTicketSort:
sortby = 'milestone'
def sort(self,tickets):
""" Ticket sorting TODO should probably use python sort"""
if self.sortby == 'priority':
return tickets
sorted_tickets = []
#for milestone in trac.ticket.a_option[7]:
for milestone in trac.ticket.a_option[0]:
for ticket in tickets:
#if ticket[3]['milestone'] == milestone['name']:
if ticket[3]['milestone'] == milestone:
sorted_tickets.append(ticket)
#append tickets without milestones
for ticket in tickets:
if ticket[3]['milestone'] == '':
sorted_tickets.append(ticket)
return sorted_tickets
def set_sortby(self, sort_option):
self.sortby = sort_option
trac.ticket_view()
class TracTicketFilter:
def __init__(self):
self.filters = []
def add (self, keyword,attribute, b_whitelist = True, b_refresh_ticket = True):
self.filters.append({'attr':attribute,'key':keyword,'whitelist':b_whitelist})
if b_refresh_ticket == True:
self.refresh_tickets()
def clear(self):
self.filters = []
self.refresh_tickets()
def delete (self, number):
number = int(number)
try:
del self.filters[number -1]
except:
return False
self.refresh_tickets()
def list (self):
if self.filters == []:
return ''
i = 0
str_list = ""
for filter in self.filters:
i+=1
is_whitelist = 'whitelist'
if (filter['whitelist'] == False):
is_whitelist = 'blacklist'
str_list += ' ' + str(i) + '. ' + filter['attr'] + ': ' + filter['key'] + " : " + is_whitelist + "\n"
return str_list
def check (self, ticket):
for filter in self.filters:
if ticket[3][filter['attr']] == filter['key']:
if filter['whitelist'] == False:
return False
else:
if filter['whitelist'] == True:
return False
return True
def refresh_tickets(self):
global trac
trac.ticket_view(trac.ticket.current_ticket_id, True)
class TracTicketUI (UI):
""" Trac Wiki User Interface Manager """
def __init__(self):
""" Initialize the User Interface """
self.ticketwindow = TicketWindow()
self.tocwindow = TicketTOContentsWindow()
self.commentwindow = TicketCommentWindow()
self.summarywindow = TicketSummaryWindow()
self.mode = 0 #Initialised to default
def normal_mode(self):
""" restore mode to normal """
if self.mode == 0: # is normal mode ?
return
if self.mode == 2:
self.summarywindow.destroy()
return
# destory all created windows
self.destroy()
#self.winbuf.clear()
self.file = None
self.line = None
self.mode = 0
self.cursign = None
def destroy(self):
""" destroy windows """
vim.command ("call UnloadTicketCommands()")
self.ticketwindow.destroy()
self.tocwindow.destroy()
self.commentwindow.destroy()
self.summarywindow.destroy()
def create(self):
""" create windows """
style = vim.eval ('g:tracTicketStyle')
if style == 'right':
self.tocwindow.create("vertical belowright new")
self.ticketwindow.create("belowright new")
self.commentwindow.create("belowright new")
elif style == 'left':
self.commentwindow.create("vertical aboveleft new")
self.ticketwindow.create("aboveleft new")
self.tocwindow.create(" aboveleft new")
elif style == 'top':
self.commentwindow.create("aboveleft new")
self.ticketwindow.create("vertical aboveleft new")
self.tocwindow.create("vertical aboveleft new")
elif style == 'bottom':
self.tocwindow.create("belowright new")
self.ticketwindow.create("vertical belowright new")
self.commentwindow.create("vertical belowright new")
elif style == 'summary':
vim.command('tabnew')
self.ticketwindow.create('vertical belowright new')
vim.command('call TracOpenViewCallback()')
vim.command('only')
self.summarywindow.create('belowright 9 new')
vim.command('wincmd k')
self.commentwindow.create('belowright 7 new')
self.summarywindow.set_focus()
else:
self.tocwindow.create("belowright new")
vim.command('call TracOpenViewCallback()')
vim.command('only')
self.ticketwindow.create("vertical belowright 150 new")
self.commentwindow.create("belowright 15 new")
vim.command ("call LoadTicketCommands()")
class TicketSummaryWindow(VimWindow):
""" Ticket Table Of Contents """
def __init__(self, name = 'TICKETSUMMARY_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> <cr> :python trac.ticket_view ("SUMMARYLINE")<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
vim.command('nnoremap <buffer> <2-LeftMouse> :python trac.ticket_view("SUMMARYLINE")<cr>')
vim.command('setlocal cursorline')
vim.command('setlocal linebreak')
vim.command('setlocal syntax=text')
vim.command('setlocal foldmethod=indent')
vim.command('setlocal nowrap')
vim.command('silent norm gg')
vim.command('setlocal noswapfile')
def on_write(self):
try:
vim.command('%Align ||')
except:
vim.command('echo you should get the Align Plugin to make this view work best')
vim.command('syn match Ignore /||/')
#vim.command("setlocal nomodifiable")
vim.command('norm gg')
class TicketWindow (NonEditableWindow):
""" Ticket Window """
def __init__(self, name = 'TICKET_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('setlocal noswapfile')
vim.command('setlocal textwidth=100')
#vim.command('nnoremap <buffer> <c-]> :python trac_ticket_view("CURRENTLINE") <cr>')
#vim.command('resize +20')
#vim.command('nnoremap <buffer> :w<cr> :TracSaveTicket<cr>')
#vim.command('nnoremap <buffer> :wq<cr> :TracSaveTicket<cr>:TracNormalView<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
#map gf to a new buffer (switching buffers doesnt work with nofile)
vim.command('nnoremap <buffer> gf <c-w><c-f><c-w>K')
#vim.command('setlocal linebreak')
vim.command('setlocal syntax=wiki')
vim.command('nnoremap <buffer> <c-p> :python trac.ticket.context_set()<cr>')
class TicketCommentWindow (VimWindow):
""" For adding Comments to tickets """
def __init__ (self,name = 'TICKET_COMMENT_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> :w<cr> :python trac.ticket.add_comment()<cr>')
vim.command('nnoremap <buffer> :wq<cr> :python trac.ticket.add_comment()<cr>:python trac.normal_view()<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
vim.command('setlocal syntax=wiki')
vim.command('setlocal noswapfile')
class TicketTOContentsWindow (NonEditableWindow):
""" Ticket Table Of Contents """
def __init__(self, name = 'TICKETTOC_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> <cr> :python trac.ticket_view ("CURRENTLINE")<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
vim.command('nnoremap <buffer> <2-LeftMouse> :python trac.ticket_view("CURRENTLINE")<cr>')
vim.command('setlocal cursorline')
vim.command('setlocal linebreak')
vim.command('setlocal syntax=wiki')
vim.command('setlocal foldmethod=indent')
vim.command('setlocal nowrap')
vim.command('silent norm ggf: <esc>')
vim.command('setlocal noswapfile')
vim.command('setlocal winwidth=50')
vim.command('vertical resize 50')
#########################
# Trac Server (UI Not Implemented)
#########################
class TracServerUI (UI):
""" Server User Interface View """
def __init__(self):
self.serverwindow = ServerWindow()
self.mode = 0 #Initialised to default
def server_mode (self):
""" Displays server mode """
self.create()
vim.command('2wincmd w') # goto srcview window(nr=1, top-left)
self.cursign = '1'
def create(self):
""" create windows """
self.serverwindow.create("belowright new")
def destroy(self):
""" destroy windows """
self.serverwindow.destroy()
class ServerWindow(NonEditableWindow):
""" Server Window """
def __init__(self, name = 'SERVER_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
########################
# Timeline Module
########################
class TracTimeline:
def read_timeline(self):
""" Call the XML Rpc list """
global trac
try:
import feedparser
except ImportError:
print "Please install feedparser.py!"
return False
from time import strftime
import re
feed = trac.wiki.server_url.replace('login/xmlrpc' , 'timeline?ticket=on&changeset=on&wiki=on&max=50&daysback=90&format=rss')
d = feedparser.parse(feed)
str_feed = "(Hit <enter> or <space >on a line containing Ticket:>>)\n"
str_feed += "(feed: " + feed + ")\n\n"
for item in d['items']:
#Each item is a dictionary mapping properties to values
str_feed += "Update: " + strftime("%Y-%m-%d %H:%M:%S", item.updated_parsed ) + "\n"
m = re.match(r"^Ticket #(\d+) (.*)$", item.title)
if m != None:
str_feed += "Ticket:>> " + m.group(1) + "\n"
str_feed += m.group(2) + "\n"
m = re.match(r"^([\w\d]+) (edited by .*)$", item.title)
if m != None:
str_feed += "Wiki:>> " + m.group(1) + "\n"
str_feed += m.group(2) + "\n"
m = re.match(r"^Changeset \[([\d]+)\]: (.*)$", item.title)
if m != None:
str_feed += "Changeset:>> " + m.group(1) + "\n"
str_feed += m.group(2) + "\n"
str_feed += "Link: " + item.link + "\n"
str_feed += '-----------------------------------------------------------------' + "\n"
return str_feed
class TracTimelineUI(UI):
""" UI Manager for Timeline View """
def __init__(self):
self.timeline_window = TracTimelineWindow()
self.mode = 0
def create (self):
style = vim.eval ('g:tracTimelineStyle')
if style == 'right':
self.timeline_window.create("vertical belowright new")
elif style == 'bottom':
self.timeline_window.create("belowright new")
else:
self.timeline_window.create("vertical aboveleft new")
def destroy (self):
self.timeline_window.destroy()
class TracTimelineWindow(NonEditableWindow):
""" RSS Feed Window """
def __init__(self, name = 'TIMELINE_WINDOW'):
VimWindow.__init__(self, name)
def on_create(self):
vim.command('nnoremap <buffer> <c-]> :python trac.wiki_view("<cword>")<cr>')
vim.command('nnoremap <buffer> :q<cr> :python trac.normal_view()<cr>')
#vim.command('vertical resize +70')
vim.command('setlocal syntax=wiki')
vim.command('setlocal linebreak')
vim.command('nnoremap <buffer> <cr> :python trac.search_open(False)<cr>')
vim.command('nnoremap <buffer> <space> :python trac.search_open(True)<cr>')
vim.command('setlocal noswapfile')
#########################
# Main Class
#########################
class Trac:
""" Main Trac class """
def __init__ (self, comment , server_list):
""" initialize Trac """
self.server_list = server_list
self.server_url = server_list.values()[0]
self.server_name = server_list.keys()[0]
self.default_comment = comment
self.wiki = TracWiki(self.server_url)
self.search = TracSearch(self.server_url)
self.ticket = TracTicket(self.server_url)
self.timeline = TracTimeline()
self.uiwiki = TracWikiUI()
self.uiserver = TracServerUI()
self.uiticket = TracTicketUI()
self.uisearch = TracSearchUI()
self.uitimeline = TracTimelineUI()
self.user = self.get_user(self.server_url)
def wiki_view(self , page = False, b_create = False) :
if page == False:
if self.wiki.currentPage == False:
page = 'WikiStart'
else:
page = self.wiki.currentPage
""" Creates The Wiki View """
if page == 'CURRENTLINE':
page = vim.current.line
print 'Connecting...'
self.normal_view()
if (page == False):
page = 'WikiStart'
self.normal_view()
self.uiwiki.open()
self.uiwiki.tocwindow.clean()
self.uiwiki.tocwindow.write(self.wiki.getAllPages())
self.uiwiki.wikiwindow.clean()
self.uiwiki.wikiwindow.write(self.wiki.getPage(page, b_create))
self.wiki.listAttachments();
if (self.wiki.current_attachments != []):
self.uiwiki.wiki_attach_window.create('belowright 3 new')
self.uiwiki.wiki_attach_window.write("\n".join(self.wiki.current_attachments))
print self.wiki.get_page_info()
def ticket_view(self ,id = False, b_use_cache = False) :
""" Creates The Ticket View """
print 'Connecting...'
if id == 'CURRENTLINE':
id = vim.current.line
if (id.find('Ticket:>>') == -1):
pos = vim.current.window.cursor
if pos[0] < 3:
print "Click within a tickets area"
return False
vim.command('call search (":>>", "b", line("w0"))');
id = vim.current.line
if (id.find('Ticket:>>') == -1):
print "Click within a tickets area"
return False
id = id.replace ('Ticket:>> ' ,'')
if id == 'SUMMARYLINE':
m = re.search(r'^([0123456789]+)',vim.current.line)
id = int(m.group(0))
self.normal_view()
self.uiticket.open()
style = vim.eval ('g:tracTicketStyle')
if style == 'summary':
self.uiticket.summarywindow.clean()
self.uiticket.summarywindow.write(self.ticket.getAllTicketsSummary(self.user, b_use_cache))
else:
self.uiticket.tocwindow.clean()
self.uiticket.tocwindow.write(self.ticket.getAllTickets(self.user, b_use_cache))
self.uiticket.ticketwindow.clean()
if (id == False):
if self.ticket.current_ticket_id == False:
self.uiticket.ticketwindow.write("Select Ticket To Load")
else:
self.uiticket.ticketwindow.write(self.ticket.getTicket(trac.ticket.current_ticket_id))
#This sets the cursor to the TOC if theres no active ticket
vim.command("wincmd h")
else:
self.uiticket.ticketwindow.write(self.ticket.getTicket(id))
#self.ticket.listAttachments()
if self.ticket.a_option == []:
self.ticket.getOptions()
def server_view(self):
""" Display's The Server list view """
self.uiserver.server_mode()
self.uiserver.serverwindow.clean()
servers = "\n".join(self.server_list.keys())
self.uiserver.serverwindow.write(servers)
def search_open(self,keyword, b_preview = False):
line = vim.current.line
if (line.find(':>>') == -1):
vim.command('call search (":>>", "b", line("w0"))');
line = vim.current.line
if (line.find('Ticket:>> ') != -1):
self.ticket_view(line.replace('Ticket:>> ', ''))
elif (line.find('Wiki:>> ')!= -1):
if b_preview == False:
self.wiki_view(line.replace('Wiki:>> ', ''))
else:
self.html_view(line.replace('Wiki:>> ', ''))
elif (line.find('Changeset:>> ')!= -1):
self.changeset_view(line.replace('Changeset:>> ', ''))
def search_view (self, keyword):
""" run a search """
self.normal_view()
output_string = self.search.search(keyword)
self.uisearch.open()
self.uisearch.searchwindow.clean()
self.uisearch.searchwindow.write(output_string)
def timeline_view(self):
self.normal_view()
output_string = self.timeline.read_timeline()
self.uitimeline.open()
self.uitimeline.timeline_window.clean()
self.uitimeline.timeline_window.write((output_string))
def set_current_server (self, server_key, quiet = False, view = False):
""" Sets the current server key """
self.ticket.current_ticket_id = False
self.wiki.currentPage = False
self.server_url = self.server_list[server_key]
self.server_name = server_key
self.user = self.get_user(self.server_url)
self.wiki.setServer(self.server_url)
self.ticket.setServer(self.server_url)
self.search.setServer(self.server_url)
self.user = self.get_user(self.server_url)
trac.normal_view()
if quiet == False:
print "SERVER SET TO : " + server_key
#Set view to default or custom
if view == False:
view = vim.eval ('g:tracDefaultView')
{ 'wiki' : self.wiki_view,
'ticket' : self.ticket_view,
'timeline' : self.timeline_view
} [view]()
def get_user (self, server_url):
#TODO fix for https
return re.sub('http://(.*):.*$',r'\1',server_url)
def normal_view(self) :
trac.uiserver.normal_mode()
trac.uiwiki.normal_mode()
trac.uiticket.normal_mode()
trac.uisearch.normal_mode()
trac.uitimeline.normal_mode()
def add_attachment (self, file):
""" add an attachment to current wiki / ticket """
if self.uiwiki.mode == 1:
print "Adding attachment to wiki " + str(self.wiki.currentPage)+ '...'
self.wiki.addAttachment (file)
print 'Done.'
elif self.uiticket.mode == 1:
print "Adding attachment to ticket #" + str(self.ticket.current_ticket_id) + '...'
self.ticket.addAttachment (file)
print 'Done.'
else:
print "You need an active ticket or wiki open!"
def get_attachment (self, file):
''' retrieves attachment '''
if (file == 'CURRENTLINE'):
file = vim.current.line
if self.uiwiki.mode == 1:
print "Retrieving attachment from wiki " + self.wiki.currentPage + '...'
self.wiki.getAttachment (file)
print 'Done.'
elif self.uiticket.mode == 1:
print "Retrieving attachment from ticket #" + self.ticket.current_ticket_id + '...'
self.ticket.getAttachment (file)
print 'Done.'
else:
print "You need an active ticket or wiki open!"
def list_attachments(self):
if self.uiwiki.mode == 1:
option = self.wiki.current_attachments
print self.wiki.current_attachments
elif self.uiticket.mode == 1:
option = self.ticket.current_attachments
else:
print "You need an active ticket or wiki open!"
vim.command ('let g:tracOptions = "' + "|".join (option) + '"')
def preview (self, b_dump = False):
''' browser view of current wiki buffer '''
global browser
if self.uiwiki.mode == 1:
print "Retrieving preview from wiki " + self.wiki.currentPage + '...'
wikitext = self.uiwiki.wikiwindow.dump()
elif self.uiticket.mode == 1:
print "Retrieving preview from ticket #" + self.ticket.current_ticket_id + '...'
wikitext = self.uiticket.commentwindow.dump()
else:
print "You need an active ticket or wiki open!"
return False
html = '<html><body>' + self.wiki.getWikiHtml (wikitext) + '</body></html>'
file_name = vim.eval ('g:tracTempHtml')
fp = open(file_name , 'w')
fp.write (html)
fp.close()
if b_dump == True:
#self.normal_view()
#vim.command ('split')
vim.command ('enew')
vim.command ('setlocal buftype=nofile')
vim.command ('r!lynx -dump ' + file_name );
vim.command ('set ft=text');
vim.command ('norm gg');
else:
vim.command ('!' + browser +" file://" + file_name);
def changeset_view(self, changeset, b_full_path = False):
#if b_full_path == True:
changeset = self.wiki.server_url.replace('login/xmlrpc' , 'changeset/' + changeset)
self.normal_view()
vim.command ('belowright split')
vim.command ('enew')
vim.command("setlocal buftype=nofile")
vim.command ('silent Nread ' + changeset + '?format=diff');
vim.command ('set ft=diff');
#########################
# VIM API FUNCTIONS
#########################
def trac_init():
''' Initialize Trac Environment '''
global trac
global browser
# get needed vim variables
comment = vim.eval('tracDefaultComment')
if comment == '':
comment = 'VimTrac update'
server_list = vim.eval('g:tracServerList')
trac = Trac(comment, server_list)
browser = vim.eval ('g:tracBrowser')
def trac_window_resize():
global mode
mode = mode + 1
if mode >= 3:
mode = 0
if mode == 0:
vim.command("wincmd =")
elif mode == 1:
vim.command("wincmd |")
if mode == 2:
vim.command("wincmd _")