mirror of
https://github.com/gryf/.vim.git
synced 2025-12-17 11:30:29 +01:00
First attempt to write reST -> blogger interface
This commit is contained in:
45
doc/tags
45
doc/tags
@@ -27,6 +27,10 @@
|
||||
'snippets' snipMate.txt /*'snippets'*
|
||||
.snippet snipMate.txt /*.snippet*
|
||||
.snippets snipMate.txt /*.snippets*
|
||||
:AcpDisable acp.txt /*:AcpDisable*
|
||||
:AcpEnable acp.txt /*:AcpEnable*
|
||||
:AcpLock acp.txt /*:AcpLock*
|
||||
:AcpUnlock acp.txt /*:AcpUnlock*
|
||||
:CVSEdit vcscommand.txt /*:CVSEdit*
|
||||
:CVSEditors vcscommand.txt /*:CVSEditors*
|
||||
:CVSUnedit vcscommand.txt /*:CVSUnedit*
|
||||
@@ -152,6 +156,21 @@ VCSCommandSplit vcscommand.txt /*VCSCommandSplit*
|
||||
VCSCommandVCSTypeOverride vcscommand.txt /*VCSCommandVCSTypeOverride*
|
||||
VimwikiWeblinkHandler vimwiki.txt /*VimwikiWeblinkHandler*
|
||||
abc fuf.txt /*abc*
|
||||
acp acp.txt /*acp*
|
||||
acp-about acp.txt /*acp-about*
|
||||
acp-author acp.txt /*acp-author*
|
||||
acp-changelog acp.txt /*acp-changelog*
|
||||
acp-commands acp.txt /*acp-commands*
|
||||
acp-contact acp.txt /*acp-contact*
|
||||
acp-installation acp.txt /*acp-installation*
|
||||
acp-introduction acp.txt /*acp-introduction*
|
||||
acp-options acp.txt /*acp-options*
|
||||
acp-perl-omni acp.txt /*acp-perl-omni*
|
||||
acp-snipMate acp.txt /*acp-snipMate*
|
||||
acp-thanks acp.txt /*acp-thanks*
|
||||
acp-usage acp.txt /*acp-usage*
|
||||
acp.txt acp.txt /*acp.txt*
|
||||
autocomplpop acp.txt /*autocomplpop*
|
||||
b:VCSCommandCommand vcscommand.txt /*b:VCSCommandCommand*
|
||||
b:VCSCommandOriginalBuffer vcscommand.txt /*b:VCSCommandOriginalBuffer*
|
||||
b:VCSCommandSourceFile vcscommand.txt /*b:VCSCommandSourceFile*
|
||||
@@ -253,6 +272,32 @@ fuf-usage fuf.txt /*fuf-usage*
|
||||
fuf-vimrc-example fuf.txt /*fuf-vimrc-example*
|
||||
fuf.txt fuf.txt /*fuf.txt*
|
||||
fuzzyfinder fuf.txt /*fuzzyfinder*
|
||||
g:acp_behavior acp.txt /*g:acp_behavior*
|
||||
g:acp_behavior-command acp.txt /*g:acp_behavior-command*
|
||||
g:acp_behavior-completefunc acp.txt /*g:acp_behavior-completefunc*
|
||||
g:acp_behavior-meets acp.txt /*g:acp_behavior-meets*
|
||||
g:acp_behavior-onPopupClose acp.txt /*g:acp_behavior-onPopupClose*
|
||||
g:acp_behavior-repeat acp.txt /*g:acp_behavior-repeat*
|
||||
g:acp_behaviorCssOmniPropertyLength acp.txt /*g:acp_behaviorCssOmniPropertyLength*
|
||||
g:acp_behaviorCssOmniValueLength acp.txt /*g:acp_behaviorCssOmniValueLength*
|
||||
g:acp_behaviorFileLength acp.txt /*g:acp_behaviorFileLength*
|
||||
g:acp_behaviorHtmlOmniLength acp.txt /*g:acp_behaviorHtmlOmniLength*
|
||||
g:acp_behaviorKeywordCommand acp.txt /*g:acp_behaviorKeywordCommand*
|
||||
g:acp_behaviorKeywordIgnores acp.txt /*g:acp_behaviorKeywordIgnores*
|
||||
g:acp_behaviorKeywordLength acp.txt /*g:acp_behaviorKeywordLength*
|
||||
g:acp_behaviorPerlOmniLength acp.txt /*g:acp_behaviorPerlOmniLength*
|
||||
g:acp_behaviorPythonOmniLength acp.txt /*g:acp_behaviorPythonOmniLength*
|
||||
g:acp_behaviorRubyOmniMethodLength acp.txt /*g:acp_behaviorRubyOmniMethodLength*
|
||||
g:acp_behaviorRubyOmniSymbolLength acp.txt /*g:acp_behaviorRubyOmniSymbolLength*
|
||||
g:acp_behaviorSnipmateLength acp.txt /*g:acp_behaviorSnipmateLength*
|
||||
g:acp_behaviorUserDefinedFunction acp.txt /*g:acp_behaviorUserDefinedFunction*
|
||||
g:acp_behaviorUserDefinedMeets acp.txt /*g:acp_behaviorUserDefinedMeets*
|
||||
g:acp_behaviorXmlOmniLength acp.txt /*g:acp_behaviorXmlOmniLength*
|
||||
g:acp_completeOption acp.txt /*g:acp_completeOption*
|
||||
g:acp_completeoptPreview acp.txt /*g:acp_completeoptPreview*
|
||||
g:acp_enableAtStartup acp.txt /*g:acp_enableAtStartup*
|
||||
g:acp_ignorecaseOption acp.txt /*g:acp_ignorecaseOption*
|
||||
g:acp_mappingDriven acp.txt /*g:acp_mappingDriven*
|
||||
g:fuf_abbrevMap fuf.txt /*g:fuf_abbrevMap*
|
||||
g:fuf_autoPreview fuf.txt /*g:fuf_autoPreview*
|
||||
g:fuf_bookmarkdir_keyDelete fuf.txt /*g:fuf_bookmarkdir_keyDelete*
|
||||
|
||||
96
ftplugin/rst/blogger.vim
Normal file
96
ftplugin/rst/blogger.vim
Normal file
@@ -0,0 +1,96 @@
|
||||
" Blogger vim interface.
|
||||
" Provide some convinient functions for creating preview from the reST file
|
||||
" and to send articles to blog.
|
||||
|
||||
if exists("b:did_rst_plugin")
|
||||
finish " load only once
|
||||
else
|
||||
let b:did_rst_plugin = 1
|
||||
endif
|
||||
|
||||
if !exists("g:blogger_browser")
|
||||
let g:blogger_browser = 0
|
||||
endif
|
||||
|
||||
if !exists("g:blogger_name")
|
||||
let g:blogger_name = ""
|
||||
endif
|
||||
|
||||
if !exists("g:blogger_login")
|
||||
let g:blogger_login= ""
|
||||
endif
|
||||
|
||||
if !exists("g:blogger_pass")
|
||||
let g:blogger_pass = ""
|
||||
endif
|
||||
|
||||
map <F5> :call <SID>Restify()<cr>
|
||||
map <F6> :call <SID>Rst2Blogger()<cr>
|
||||
|
||||
if !exists('*s:Restify')
|
||||
python << EOF
|
||||
#{{{
|
||||
import os
|
||||
import sys
|
||||
import webbrowser
|
||||
|
||||
import vim
|
||||
|
||||
scriptdir = os.path.dirname(vim.eval('expand("<sfile>")'))
|
||||
sys.path.insert(0, scriptdir)
|
||||
from bloggervim.rest import blogPreview, blogArticleString
|
||||
from bloggervim.blogger import VimBlogger
|
||||
|
||||
#}}}
|
||||
EOF
|
||||
|
||||
" Translate reSt text into html fragment suitable for preview in browser.
|
||||
fun <SID>Restify()
|
||||
python << EOF
|
||||
# {{{
|
||||
bufcontent = "\n".join(vim.current.buffer)
|
||||
name = vim.current.buffer.name
|
||||
|
||||
name = name[:-4] + ".html"
|
||||
html = blogPreview(bufcontent)
|
||||
output_file = open(name, "w")
|
||||
output_file.write(html)
|
||||
output_file.close()
|
||||
if vim.eval("g:blogger_browser"):
|
||||
webbrowser.open(name)
|
||||
print "Generated HTML has been opened in browser"
|
||||
else:
|
||||
print "Generated HTML has been written to %s" % name
|
||||
#}}}
|
||||
EOF
|
||||
endfun
|
||||
|
||||
" Generate headless html, gather title, dates and tags from filed list and
|
||||
" then send it to blog.
|
||||
fun <SID>Rst2Blogger()
|
||||
python << EOF
|
||||
#{{{
|
||||
bufcontent = "\n".join(vim.current.buffer)
|
||||
name = vim.current.buffer.name
|
||||
html, attrs = blogArticleString(bufcontent)
|
||||
|
||||
login = vim.eval("g:blogger_login")
|
||||
password = vim.eval("g:blogger_pass")
|
||||
blogname = vim.eval("g:blogger_name")
|
||||
|
||||
if not password:
|
||||
password = vim.eval('inputsecret("Enter your gmail password: ")')
|
||||
|
||||
title = 'title' in attrs and attrs['title'] or None
|
||||
date = 'date' in attrs and attrs['date'] or None
|
||||
tags = 'tags' in attrs and attrs['tags'] or ""
|
||||
tags = [tag.strip() for tag in tags.split(',')]
|
||||
modified = 'modified' in attrs and attrs['modified'] or None
|
||||
|
||||
blog = VimBlogger(blogname, login, password)
|
||||
print blog.create_article(title, html, tags=tags)
|
||||
|
||||
#}}}
|
||||
EOF
|
||||
endfun
|
||||
endif
|
||||
130
ftplugin/rst/bloggervim/blogger.py
Normal file
130
ftplugin/rst/bloggervim/blogger.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# vim: fileencoding=utf8
|
||||
#
|
||||
# Blogger interface to make easy way to create/update articles for specified
|
||||
# blog.
|
||||
#
|
||||
# It is assumed one way communication only, so you may create or update an
|
||||
# article from reST source files. There is no way to recreate article from
|
||||
# html to reST format.
|
||||
#
|
||||
# requirements:
|
||||
#
|
||||
# - Vim compiled with +python
|
||||
# - python 2.x (tested with 2.6)
|
||||
# - modules
|
||||
# - gdata (http://code.google.com/p/gdata-python-client)
|
||||
# - docutils (http://docutils.sourceforge.net)
|
||||
# - pytz (http://pytz.sourceforge.net)
|
||||
#
|
||||
# USE CASES:
|
||||
# 1. Create new post
|
||||
#
|
||||
# use reST template:
|
||||
# ===8<---
|
||||
# :Title: Blog post title
|
||||
# :Date: optional publish date (for example: 2010-11-28 18:47:05),
|
||||
# default: now()
|
||||
# :Modified: optional, default: None
|
||||
# :Tags: comma separated blog tags
|
||||
#
|
||||
# .. more
|
||||
#
|
||||
# --->8===
|
||||
#
|
||||
# All four docinfo are optional, however it is nice to give at least a title
|
||||
# to the article :)
|
||||
#
|
||||
#
|
||||
#
|
||||
# which is provided under templates directory or as a
|
||||
# snipMate shoortcut (see .vim/snippets/rst.snippets)
|
||||
#
|
||||
|
||||
# vim.eval('inputsecret("Password: ")')
|
||||
# echomsg expand("%:p")
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
import getpass # TODO: remove
|
||||
import time
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
import atom
|
||||
from gdata.blogger.client import BloggerClient
|
||||
|
||||
|
||||
class VimBlogger(object):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, blogname, login, password):
|
||||
"""
|
||||
"""
|
||||
self.blog = None
|
||||
self.client = BloggerClient()
|
||||
self._authorize(login, password)
|
||||
|
||||
self.feed = self.client.get_blogs()
|
||||
self._set_blog(blogname)
|
||||
#self._get_arts(blogname)
|
||||
|
||||
def _set_blog(self, blogname):
|
||||
"""
|
||||
"""
|
||||
for blog in self.feed.entry:
|
||||
if blog.get_blog_name() == blogname:
|
||||
self.blog = blog
|
||||
break
|
||||
|
||||
|
||||
def _get_arts(self, blogname):
|
||||
"""
|
||||
"""
|
||||
feed = self.client.get_posts(self.blog.get_blog_id())
|
||||
for entry in feed.entry:
|
||||
print entry.title.text
|
||||
#
|
||||
import ipdb; ipdb.set_trace()
|
||||
#
|
||||
# entry.content obiekt zawiera ciało artykułu (entry.content.text
|
||||
# posiada czystą formę która mnie interesuje najbardziej, do której
|
||||
# można pisać
|
||||
#
|
||||
# entry.category - lista wszystkich kategorii (blogowych tagów), które
|
||||
# post posiada. Są to elementy klasy atom.data.Category, które
|
||||
# łatwiutko stworzyć i dodać do posta:
|
||||
# import atom
|
||||
# cat1 = atom.data.Category()
|
||||
# cat1.term = "nowy tag dla bloggera"
|
||||
# entry.category.append(cat1)
|
||||
#
|
||||
# entry.title przechowuje tytuł posta
|
||||
|
||||
def _authorize(self, login, password):
|
||||
"""
|
||||
"""
|
||||
source = 'Blogger_Python_Sample-2.0'
|
||||
service = 'blogger'
|
||||
|
||||
self.client.client_login(login,
|
||||
password,
|
||||
source=source,
|
||||
service=service)
|
||||
def create_article(self, title, html_doc, tags=None):
|
||||
"""
|
||||
"""
|
||||
|
||||
blog_id = self.blog.get_blog_id()
|
||||
if tags is None:
|
||||
tags = []
|
||||
return self.client.add_post(blog_id, title, html_doc, labels=tags,
|
||||
draft=True)
|
||||
|
||||
def update_article(self, title, html_doc, tags=None):
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
p = getpass.getpass("Password: ")
|
||||
b = VimBlogger("rdobosz", "gryf73@gmail.com", p)
|
||||
263
ftplugin/rst/bloggervim/rest.py
Normal file
263
ftplugin/rst/bloggervim/rest.py
Normal file
@@ -0,0 +1,263 @@
|
||||
import re
|
||||
|
||||
from docutils import core
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives, Directive
|
||||
from docutils.writers.html4css1 import Writer, HTMLTranslator
|
||||
|
||||
from pygments import highlight
|
||||
from pygments.lexers import get_lexer_by_name, TextLexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
|
||||
class Attrs(object):
|
||||
ATTRS = {}
|
||||
|
||||
class Pygments(Directive):
|
||||
"""
|
||||
Source code syntax hightlighting.
|
||||
"""
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
|
||||
def run(self):
|
||||
self.assert_has_content()
|
||||
try:
|
||||
lexer = get_lexer_by_name(self.arguments[0])
|
||||
except ValueError:
|
||||
# no lexer found - use the text one instead of an exception
|
||||
lexer = TextLexer()
|
||||
# take an arbitrary option if more than one is given
|
||||
formatter = HtmlFormatter(noclasses=True)
|
||||
parsed = highlight(u'\n'.join(self.content), lexer, formatter)
|
||||
return [nodes.raw('', parsed, format='html')]
|
||||
|
||||
directives.register_directive('sourcecode', Pygments)
|
||||
|
||||
class CustomHTMLTranslator(HTMLTranslator):
|
||||
"""
|
||||
Base class for reST files translations.
|
||||
There are couple of customizations for docinfo fields behaviour and
|
||||
abbreviations and acronyms.
|
||||
"""
|
||||
|
||||
def __init__(self, document):
|
||||
"""
|
||||
Set some nice defaults for articles translations
|
||||
"""
|
||||
HTMLTranslator.__init__(self, document)
|
||||
self.initial_header_level = 4
|
||||
|
||||
def visit_section(self, node):
|
||||
"""
|
||||
Don't affect document, just keep track of the section levels
|
||||
"""
|
||||
self.section_level += 1
|
||||
|
||||
def depart_section(self, node):
|
||||
self.section_level -= 1
|
||||
|
||||
def visit_meta(self, node):
|
||||
pass
|
||||
|
||||
def depart_meta(self, node):
|
||||
pass
|
||||
|
||||
def visit_document(self, node):
|
||||
pass
|
||||
|
||||
def depart_document(self, node):
|
||||
pass
|
||||
|
||||
def depart_docinfo(self, node):
|
||||
"""
|
||||
Reset body, remove unnecesairy content.
|
||||
"""
|
||||
self.body = []
|
||||
|
||||
def visit_date(self, node):
|
||||
pass
|
||||
|
||||
def depart_date(self, node):
|
||||
pass
|
||||
|
||||
def visit_literal(self, node):
|
||||
"""
|
||||
This is almos the same as the original one from HTMLTranslator class.
|
||||
The only difference is in used HTML tag: it uses 'code' instead of
|
||||
'tt'
|
||||
"""
|
||||
self.body.append(self.starttag(node, 'code', ''))
|
||||
text = node.astext()
|
||||
for token in self.words_and_spaces.findall(text):
|
||||
if token.strip():
|
||||
# Protect text like "--an-option" and the regular expression
|
||||
# ``[+]?(\d+(\.\d*)?|\.\d+)`` from bad line wrapping
|
||||
if self.sollbruchstelle.search(token):
|
||||
self.body.append('<span class="pre">%s</span>'
|
||||
% self.encode(token))
|
||||
else:
|
||||
self.body.append(self.encode(token))
|
||||
elif token in ('\n', ' '):
|
||||
# Allow breaks at whitespace:
|
||||
self.body.append(token)
|
||||
else:
|
||||
# Protect runs of multiple spaces; the last space can wrap:
|
||||
self.body.append(' ' * (len(token) - 1) + ' ')
|
||||
self.body.append('</code>')
|
||||
# Content already processed:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_acronym(self, node):
|
||||
"""
|
||||
Define missing acronym HTML tag
|
||||
"""
|
||||
node_text = node.children[0].astext()
|
||||
node_text = node_text.replace('\n', ' ')
|
||||
patt = re.compile(r'^(.+)\s<(.+)>')
|
||||
|
||||
if patt.match(node_text):
|
||||
node.children[0] = nodes.Text(patt.match(node_text).groups()[0])
|
||||
self.body.append(\
|
||||
self.starttag(node, 'acronym',
|
||||
'', title=patt.match(node_text).groups()[1]))
|
||||
|
||||
else:
|
||||
self.body.append(self.starttag(node, 'acronym', ''))
|
||||
|
||||
def visit_abbreviation(self, node):
|
||||
"""
|
||||
Define missing abbr HTML tag
|
||||
"""
|
||||
node_text = node.children[0].astext()
|
||||
node_text = node_text.replace('\n', ' ')
|
||||
patt = re.compile(r'^(.+)\s<(.+)>')
|
||||
|
||||
if patt.match(node_text):
|
||||
node.children[0] = nodes.Text(patt.match(node_text).groups()[0])
|
||||
self.body.append(\
|
||||
self.starttag(node, 'abbr',
|
||||
'', title=patt.match(node_text).groups()[1]))
|
||||
|
||||
else:
|
||||
self.body.append(self.starttag(node, 'abbr', ''))
|
||||
|
||||
class NoHeaderHTMLTranslator(CustomHTMLTranslator):
|
||||
"""
|
||||
Special subclass for generating only body of an article
|
||||
"""
|
||||
def __init__(self, document):
|
||||
"""
|
||||
Remove all needless parts of HTML document.
|
||||
"""
|
||||
CustomHTMLTranslator.__init__(self, document)
|
||||
self.head = []
|
||||
self.meta = []
|
||||
self.head_prefix = ['','','','','']
|
||||
self.body_prefix = []
|
||||
self.body_suffix = []
|
||||
self.stylesheet = []
|
||||
self.generator = ('')
|
||||
|
||||
def visit_field(self, node):
|
||||
"""
|
||||
Harvest docinfo fields and store it in global dictionary.
|
||||
"""
|
||||
key, val = [n.astext() for n in node]
|
||||
key = key.lower()
|
||||
Attrs.ATTRS[key] = val
|
||||
|
||||
def visit_date(self, node):
|
||||
"""
|
||||
Store published date in global dictionary.
|
||||
"""
|
||||
Attrs.ATTRS['date'] = node.astext()
|
||||
|
||||
class PreviewHTMLTranslator(CustomHTMLTranslator):
|
||||
"""
|
||||
Class for dislpay article in the browser as a preview.
|
||||
"""
|
||||
def __init__(self, document):
|
||||
"""
|
||||
Alter levels for the heading tags, define custom, blog specific
|
||||
stylesheets. Note, that style_custom is present only locally to adjust
|
||||
way of display the page
|
||||
"""
|
||||
CustomHTMLTranslator.__init__(self, document)
|
||||
self.initial_header_level = 1
|
||||
self.section_level = 1
|
||||
# order of css files is important
|
||||
self.default_stylesheets = ["css/widget_css_2_bundle.css",
|
||||
"css/style_custom.css",
|
||||
"css/style_blogger.css"]
|
||||
self.stylesheet = [self.stylesheet_link % self.encode(css) \
|
||||
for css in self.default_stylesheets]
|
||||
self.body_ = []
|
||||
|
||||
|
||||
def depart_docinfo(self, node):
|
||||
"""
|
||||
Overwrite body with some custom one. body_ will hold the first heading
|
||||
with title of the document.
|
||||
"""
|
||||
self.body = self.body_
|
||||
|
||||
def visit_field(self, node):
|
||||
"""
|
||||
Additional 'keyword' for the ODF metadata
|
||||
"""
|
||||
key, node_ = [n.astext() for n in node]
|
||||
key = key.lower()
|
||||
if key == 'title':
|
||||
self.head.append('<title>%s</title>\n' % self.encode(node_))
|
||||
self.body_.append('<h1 class="post-title entry-title">'
|
||||
'<a href="#">%s</a></h1>\n' % self.encode(node_))
|
||||
|
||||
class BlogBodyWriter(Writer):
|
||||
"""
|
||||
Custom Writer class for generating HTML partial with the article
|
||||
"""
|
||||
def __init__(self):
|
||||
Writer.__init__(self)
|
||||
self.translator_class = NoHeaderHTMLTranslator
|
||||
|
||||
def translate(self):
|
||||
self.document.settings.output_encoding = "utf-8"
|
||||
Writer.translate(self)
|
||||
|
||||
class BlogPreviewWriter(Writer):
|
||||
"""
|
||||
Custom Writer class for generating full HTML of the article
|
||||
"""
|
||||
def __init__(self):
|
||||
Writer.__init__(self)
|
||||
self.translator_class = PreviewHTMLTranslator
|
||||
|
||||
def translate(self):
|
||||
self.document.settings.output_encoding = "utf-8"
|
||||
Writer.translate(self)
|
||||
|
||||
|
||||
def blogPreview(string):
|
||||
"""
|
||||
Returns partial HTML of the article, and attribute dictionary
|
||||
string argument is an article in reST
|
||||
"""
|
||||
html_output = core.publish_string(string, writer=BlogPreviewWriter())
|
||||
html_output = html_output.strip()
|
||||
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
|
||||
return html_output
|
||||
|
||||
def blogArticleString(string):
|
||||
"""
|
||||
Returns partial HTML of the article, and attribute dictionary
|
||||
string argument is an article in reST
|
||||
"""
|
||||
# reset ATTRS
|
||||
Attrs.ATTRS = {}
|
||||
html_output = core.publish_string(string, writer=BlogBodyWriter())
|
||||
html_output = html_output.strip()
|
||||
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
|
||||
return html_output, Attrs.ATTRS
|
||||
|
||||
@@ -5,169 +5,6 @@ setlocal spell
|
||||
setlocal smartindent
|
||||
setlocal autoindent
|
||||
setlocal formatoptions=tcq "set VIms default
|
||||
|
||||
if exists("b:did_rst_plugin")
|
||||
finish " only load once
|
||||
else
|
||||
let b:did_rst_plugin = 1
|
||||
endif
|
||||
|
||||
map <F5> :call <SID>Rst2Blogger()<cr>
|
||||
|
||||
if !exists('*s:Rst2Blogger')
|
||||
" Simple function, that translates reSt text into html with specified format,
|
||||
" suitable to copy and paste into blogger post.
|
||||
fun <SID>Rst2Blogger()
|
||||
python << EOF
|
||||
import re
|
||||
|
||||
from docutils import core
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives, Directive
|
||||
from docutils.writers.html4css1 import Writer, HTMLTranslator
|
||||
|
||||
from pygments import highlight
|
||||
from pygments.lexers import get_lexer_by_name, TextLexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
|
||||
import vim
|
||||
|
||||
class Pygments(Directive):
|
||||
"""
|
||||
Source code syntax hightlighting.
|
||||
"""
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
|
||||
def run(self):
|
||||
self.assert_has_content()
|
||||
try:
|
||||
lexer = get_lexer_by_name(self.arguments[0])
|
||||
except ValueError:
|
||||
# no lexer found - use the text one instead of an exception
|
||||
lexer = TextLexer()
|
||||
# take an arbitrary option if more than one is given
|
||||
formatter = HtmlFormatter(noclasses=True)
|
||||
parsed = highlight(u'\n'.join(self.content), lexer, formatter)
|
||||
return [nodes.raw('', parsed, format='html')]
|
||||
|
||||
directives.register_directive('sourcecode', Pygments)
|
||||
|
||||
class NoHeaderHTMLTranslator(HTMLTranslator):
|
||||
def __init__(self, document):
|
||||
HTMLTranslator.__init__(self,document)
|
||||
self.head_prefix = ['','','','','']
|
||||
self.body_prefix = []
|
||||
self.body_suffix = []
|
||||
self.stylesheet = []
|
||||
self.head = []
|
||||
self.meta = []
|
||||
self.generator = ('')
|
||||
self.initial_header_level = 2
|
||||
self.section_level = 2
|
||||
|
||||
def visit_document(self, node):
|
||||
pass
|
||||
|
||||
def depart_document(self, node):
|
||||
pass
|
||||
|
||||
def visit_section(self, node):
|
||||
pass
|
||||
|
||||
def depart_section(self, node):
|
||||
pass
|
||||
|
||||
def visit_acronym(self, node):
|
||||
node_text = node.children[0].astext()
|
||||
node_text = node_text.replace('\n', ' ')
|
||||
patt = re.compile(r'^(.+)\s<(.+)>')
|
||||
|
||||
if patt.match(node_text):
|
||||
node.children[0] = nodes.Text(patt.match(node_text).groups()[0])
|
||||
self.body.append(\
|
||||
self.starttag(node, 'acronym',
|
||||
'', title=patt.match(node_text).groups()[1]))
|
||||
|
||||
else:
|
||||
self.body.append(self.starttag(node, 'acronym', ''))
|
||||
|
||||
def visit_abbreviation(self, node):
|
||||
node_text = node.children[0].astext()
|
||||
node_text = node_text.replace('\n', ' ')
|
||||
patt = re.compile(r'^(.+)\s<(.+)>')
|
||||
|
||||
if patt.match(node_text):
|
||||
node.children[0] = nodes.Text(patt.match(node_text).groups()[0])
|
||||
self.body.append(\
|
||||
self.starttag(node, 'abbr',
|
||||
'', title=patt.match(node_text).groups()[1]))
|
||||
|
||||
else:
|
||||
self.body.append(self.starttag(node, 'abbr', ''))
|
||||
|
||||
|
||||
_w = Writer()
|
||||
_w.translator_class = NoHeaderHTMLTranslator
|
||||
|
||||
def blogify(string):
|
||||
return core.publish_string(string, writer=_w)
|
||||
|
||||
bufcontent = "\n".join(vim.current.buffer)
|
||||
name = vim.current.buffer.name
|
||||
if name.lower().endswith(".rst"):
|
||||
name = name[:-4] + ".html"
|
||||
vim.command('new')
|
||||
|
||||
vim.current.buffer[:] = blogify(bufcontent).split("\n")
|
||||
try:
|
||||
vim.command(r'silent! %s/<tt class="docutils literal">/<code>/g')
|
||||
vim.command(r'silent! %s/<\/tt>/<\/code>/g')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
vim.command(r'silent! %s/<!-- more -->/\r<!-- more -->\r/g')
|
||||
except:
|
||||
pass
|
||||
vim.command('w %s' % name.replace(' ', '\ '))
|
||||
vim.command('bd')
|
||||
else:
|
||||
print "Ihis is not reSt file. File should have '.rst' extension."
|
||||
|
||||
EOF
|
||||
endfun
|
||||
endif
|
||||
|
||||
if !exists('*s:Restify')
|
||||
" This is similar to that above, but creates full html document
|
||||
fun <SID>Restify()
|
||||
python << EOF
|
||||
from docutils import core
|
||||
from docutils.writers.html4css1 import Writer, HTMLTranslator
|
||||
import vim
|
||||
|
||||
_w = Writer()
|
||||
_w.translator_class = HTMLTranslator
|
||||
|
||||
def reSTify(string):
|
||||
return core.publish_string(string,writer=_w)
|
||||
|
||||
bufcontent = "\n".join(vim.current.buffer)
|
||||
name = vim.current.buffer.name
|
||||
if name.lower().endswith(".rst"):
|
||||
name = name[:-4] + ".html"
|
||||
vim.command('new')
|
||||
|
||||
vim.current.buffer[:] = reSTify(bufcontent).split("\n")
|
||||
vim.command(r'silent %s/<tt class="docutils literal">/<code>/g')
|
||||
vim.command(r'silent %s/<\/tt>/<\/code>/g')
|
||||
vim.command('w %s' % name)
|
||||
vim.command('bd')
|
||||
else:
|
||||
print "It's not reSt file!"
|
||||
|
||||
EOF
|
||||
endfun
|
||||
endif
|
||||
let g:blogger_login="gryf73"
|
||||
let g:blogger_name="rdobosz"
|
||||
let g:blogger_browser=1
|
||||
|
||||
@@ -57,3 +57,12 @@ snippet figure
|
||||
:figclass: ${3:custclass}
|
||||
|
||||
$2
|
||||
snippet article
|
||||
:Title: ${1:Blog post title}
|
||||
:Date: ${2:`strftime("%Y-%m-%d %H:%M:%S")`}
|
||||
:Modified: ${3}
|
||||
:Tags: ${4:blogtag1, blogtag2}
|
||||
|
||||
${5}
|
||||
|
||||
.. more
|
||||
|
||||
Reference in New Issue
Block a user