#@+leo-ver=4
#@+node:@file rst2.py
"""If a headline starts with @rst <filename>, double-clicking on it will 
write a file in outline order, with the headlines converted to reStructuredText 
section headings.

If the name of the <filename> has the extension .html, .htm or .tex, and if you have
docutils installed, it will generate HTML or LaTeX, respectively."""

# By Josef Dalcolmo: contributed under the same licensed as Leo.py itself.

# EKR: The code now lets other plugins handle @folder and @url nodes.

# S. Zatz: some modifications to create the ability to combine program code and documentation
# using @rst nodes (with no file name) in orde to produce combined code/documentation HTML output.
# See the 'about this plugin' section for more information

from leoPlugins import *
from leoGlobals import *

import os
#import reST_HTML

#@<< about this plugin >>
#@+node:<<about this plugin >>
#@+at 
#@nonl
# This plugin writes out @rst nodes as a reStructuredText file.
# 
# If the filename ends in .html, .htm or .tex and if you have docutils_ (a 
# Python
# module) installed, then it will be written as HTML or LaTeX, respectively. 
# The HTML converter is far
# from bug-free, but remember, docutils is alpha software. (Perhaps a future
# version will allow automatic translation to other formats, like 
# OpenOffice.org
# as well).
# 
# Headlines are translated into reStructuredText headlines, e.g. underlined
# depending on the level and empty line separated from body text otherwise, 
# text
# is written as it is. The "#" character is not used for underlining, so it 
# may
# be used for a title as in::
# 
#     #####
#     Title
#     #####
# 
# Otherwise, section underlining is discouraged, since it is automatically 
# generated.
# 
# .. _docutils: http://docutils.sourceforge.net
# 
# --------------------------------------------------------
# 
# S Zatz modifications
# 
# Assumes Leo outlines are in the form
# 
# @rst somefilename.[txt/html/tex]
# ..@file-nosent somefilename.py
# ....code node
# ......@rst
# ......another code node
# ........@rst
# ......more code
# ........@rst
# 
# and so on
# 
# If you want a table of contents, put the following:  '.. contents:: Table of 
# Contents'
# on its own line in the body of the root '@rst somefilename.[txt/html/tex]' 
# node.
# (Maybe this should be done in the plugin?)
# 
# Double-clicking on a @rst somefilename.ext node generates a reST-structured 
# [txt/html/tex] file that combines
# program code nodes with reST documentation from @rst nodes that have no 
# associated filename.
# 
# Note: if the SilverCity lexing package is present then code is presented 
# with syntax highlighting.  For the
# HTML output to look OK you need the following cascading style sheets:
#     1) default.css -> docutils default style sheet
#     2) leo_rst.css -> contains some style 'improvements' mostly based on 
# Gunnar Schwant's DocFactory
#     3) silver_city.css -> if SilverCity is present, this is the style sheet 
# that supports syntax highlighting
# The latter two style sheets are imported at the end of the default.css.  
# Since I know only enough css to be dangerous,
# would be great to have someone clean this up.  I am following David Goodger 
# request that the default docutils
# style sheet be kept intact with modifications done via imported style 
# sheets.
#@-at
#@-node:<<about this plugin >>
#@nl
#@<< change log >>
#@+node:<< change log >>
#@+at 
#@nonl
# Change log:
# 
# - New tree types: @rst has been added.
# 
# - EKR: The code now lets other plugins handle @folder and @url nodes.
# 
# - HTML generation: @rst nodes can now generate HTML, if Python docutils_ are
#   installed. Simply give the filename an extension .htm or .html. You can 
# try
#   this out by renaming the filename in this @rst tree.
# 
# - underlines: I changed the order of the underline characters again. The ">" 
# is
#   doesn't really look good as an underline in my opinion, so I moved it to a 
# very
#   low level.
# 
# - JD 2003-03-10 (rev 1.3): some more corrections to the unicode-> encoding 
# translation.
#   No only check for missing docutils (doesn't mask other errors any more).
# 
# - JD 2003-03-11 (rev 1.4): separated out the file launching code to a 
# different pluging.
# 
# - 2003-11-02 Added generation of LaTeX files, just make the extension of the 
# filename '.tex'. --Timo Honkasalo
# 
# - 2003-12-24 S Zatz modifications to introduce concept of plain @rst nodes 
# to improve program documentation
# 
# - 2004-01-17 S Zatz allow whitespace in paths.
#@-at
#@nonl
#@-node:<< change log >>
#@nl

#@+others
#@+node:onIconDoubleClick
# by Josef Dalcolmo 2003-01-13
#
# this does not check for proper filename syntax.
# path is the current dir, or the place @folder points to
# this should probably be changed to @path or so.

def onIconDoubleClick(tag,keywords):

	v = keywords.get("v")
	c = keywords.get("c")
	h = v.headString().strip()

	if match_word(h,0,"@rst"):
		if len(h) > 5:
			fname = h[5:]
			ext = os.path.splitext(fname)[1].lower()
			if ext in ('.htm','.html','.tex'):
				#@				<< write rST as HTML/LaTeX >>
				#@+node:<< write rST as HTML/LaTeX >>
				try:
					import docutils
				except:
					es('HTML/LaTeX generation requires docutils',color="blue")
					return
				else:
					from docutils.core import Publisher
					from docutils.io import StringOutput, StringInput
					import StringIO
					
				# Set the writer and encoding for the converted file
				if ext in ('.html','.htm'):
					writer='html'
					enc="utf-8"
				else:
					writer='latex'
					enc="iso-8859-1"
				
				if writer == 'html':
					try:
						import SilverCity
					except:
						es('SilverCity not present so no syntax highlighting')
						syntax = False
					else:
						#@		<< define code-block >>
						#@+node:<< define code-block >>
						# See Syntax-highlighted code blocks for docutils by Kevin Schluff in ASPN Python Cookbook
						# this code defines a new "code-block" directive for docutils
						import docutils.parsers.rst
						
						def code_block(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine):
							language = arguments[0]
							module = getattr(SilverCity, language)
							generator = getattr(module, language+"HTMLGenerator")
							io = StringIO.StringIO()
							generator().generate_html(io, '\n'.join(content))
							html = '<div class="code-block">\n%s\n</div>\n'%io.getvalue()
							raw = docutils.nodes.raw('',html, format='html') #(self, rawsource='', text='', *children, **attributes):
							return [raw]
						
						code_block.arguments = (1,0,0)
						code_block.options = {'language' : docutils.parsers.rst.directives.unchanged}
						code_block.content = 1
						  
						# Need to register the directive with docutils
						docutils.parsers.rst.directives.register_directive('code-block', code_block)
						
						#@-node:<< define code-block >>
						#@nl
						syntax = True     
				else:
					syntax = False
					
				rstFile = StringIO.StringIO()
				writeTreeAsRst(rstFile, fname, v, c, syntax)
				rstText = rstFile.getvalue()
				
				# this code snipped has been taken from code contributed by Paul Paterson 2002-12-05
				pub = Publisher()
				pub.source = StringInput(source=rstText)
				pub.destination = StringOutput(pub.settings, encoding=enc)
				pub.set_reader('standalone', None, 'restructuredtext')
				pub.set_writer(writer)
				output = pub.publish(argv=[]) # 1/18/04
				
				convertedFile = file(fname,'w')
				convertedFile.write(output)
				convertedFile.close()
				rstFile.close()
				es('written: '+str(fname))
				#@nonl
				#@-node:<< write rST as HTML/LaTeX >>
				#@nl
			else:
				#@				<< write rST file >>
				#@+node:<< write rST file >>
				rstFile = file(fname,'w')
				writeTreeAsRst(rstFile, fname, v, c)
				rstFile.close()
				es('written: '+str(fname))
				#@nonl
				#@-node:<< write rST file >>
				#@nl
		else:
			pass
			# if the headline only contains @rst then open the node and its parent in text editor
			# this works for me but needs to be generalized and should probably be a component
			# of the open_with plugin
			#c.openWith(("os.startfile", None, ".txt"))
			#c.selectVnode(v.parent())
			#c.openWith(("os.startfile", None, ".tp"))


#@-node:onIconDoubleClick
#@+node:writeTreeAsRst
def writeTreeAsRst(rstFile, fname, vnode, c, syntax=None):
	'Writes the tree under vnode to the file rstFile (fname is the filename)'
	# we don't write a title, so the titlepage can be customized
	# use '#' for title under/overline
	directives = scanDirectives(c, v=vnode) # changed name because don't want to use keyword dict
	
	encoding = directives.get("encoding",None)
	if encoding == None:
		encoding = app().config.default_derived_file_encoding
	
	if syntax:
		lang_dict = {'python':'Python', 'ruby':'Ruby', 'perl':'Perl', 'c':'CPP'}
		language = directives['language']
		# SilverCity modules have first letter in caps
		if language in lang_dict:
			code_dir = '**code**:\n\n.. code-block:: %s\n\n'%lang_dict[language]
		else:
			code_dir = '**code**:\n\n.. class:: code\n..\n\n::\n\n'
	else:
		code_dir = '**code**:\n\n.. class:: code\n..\n\n::\n\n'

	s = toEncodedString(fname,encoding,reportErrors=true)
	rstFile.write('.. filename: '+s+'\n')
	rstFile.write('\n')

	s = vnode.bodyString()
	s = toEncodedString(s,encoding,reportErrors=true)
	rstFile.write(s+'\n')		# write body of titlepage
	rstFile.write('\n')
	
	toplevel = vnode.level()+1 #Dec 20
	h = vnode.headString()
	stopHere = vnode.nodeAfterTree()
	v = vnode.threadNext()
	# repeat for all nodes in this tree
	while v != stopHere:
		h = v.headString().strip()
		if match_word(h,0,"@rst"):
			s = v.bodyString()
			s = toEncodedString(s,encoding,reportErrors=true)
			# next line is an total hack to take care of @ignore, @nocolor, @wrap in the @rst nodes
			s = s.split('\n',3)[3]
			rstFile.write('**comments**:\n%s\n'%s)
			rstFile.write('\n')
		else:
			if match_word(h,0,"@file-nosent"):
				h = h[13:]
			h = toEncodedString(h,encoding,reportErrors=true)
			s = v.bodyString()
			s = toEncodedString(s,encoding,reportErrors=true)
			rstFile.write(h+'\n')
			rstFile.write(underline(h,v.level()-toplevel))
			rstFile.write('\n')
			if s.strip():
				rstFile.write(code_dir)
				s = s.split('\n')
				for linenum,linetext in enumerate(s[:-1]):
					if "@others" in linetext: #deleting lines with @other directive from output
						continue
					rstFile.write('\t%2d  %s\n'%(linenum+1,linetext))
			rstFile.write('\n')
			
		v = v.threadNext()
#@nonl
#@-node:writeTreeAsRst
#@+node:underline
# note the first character is intentionally unused, to serve as the underline
# character in a title (in the body of the @rst node)

def underline(h,level):
	str = """#=+*^~"'`-:><_"""[level]
	return str*max(len(h),4)+'\n'
#@-node:underline
#@-others

# Register the handlers...
registerHandler("icondclick1",onIconDoubleClick)
__version__ = "2.0"
plugin_signon(__name__)


#@-node:@file rst2.py
#@-leo
