mirror of
https://github.com/gryf/.vim.git
synced 2025-12-17 19:40: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'*
|
'snippets' snipMate.txt /*'snippets'*
|
||||||
.snippet snipMate.txt /*.snippet*
|
.snippet snipMate.txt /*.snippet*
|
||||||
.snippets snipMate.txt /*.snippets*
|
.snippets snipMate.txt /*.snippets*
|
||||||
|
:AcpDisable acp.txt /*:AcpDisable*
|
||||||
|
:AcpEnable acp.txt /*:AcpEnable*
|
||||||
|
:AcpLock acp.txt /*:AcpLock*
|
||||||
|
:AcpUnlock acp.txt /*:AcpUnlock*
|
||||||
:CVSEdit vcscommand.txt /*:CVSEdit*
|
:CVSEdit vcscommand.txt /*:CVSEdit*
|
||||||
:CVSEditors vcscommand.txt /*:CVSEditors*
|
:CVSEditors vcscommand.txt /*:CVSEditors*
|
||||||
:CVSUnedit vcscommand.txt /*:CVSUnedit*
|
:CVSUnedit vcscommand.txt /*:CVSUnedit*
|
||||||
@@ -152,6 +156,21 @@ VCSCommandSplit vcscommand.txt /*VCSCommandSplit*
|
|||||||
VCSCommandVCSTypeOverride vcscommand.txt /*VCSCommandVCSTypeOverride*
|
VCSCommandVCSTypeOverride vcscommand.txt /*VCSCommandVCSTypeOverride*
|
||||||
VimwikiWeblinkHandler vimwiki.txt /*VimwikiWeblinkHandler*
|
VimwikiWeblinkHandler vimwiki.txt /*VimwikiWeblinkHandler*
|
||||||
abc fuf.txt /*abc*
|
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:VCSCommandCommand vcscommand.txt /*b:VCSCommandCommand*
|
||||||
b:VCSCommandOriginalBuffer vcscommand.txt /*b:VCSCommandOriginalBuffer*
|
b:VCSCommandOriginalBuffer vcscommand.txt /*b:VCSCommandOriginalBuffer*
|
||||||
b:VCSCommandSourceFile vcscommand.txt /*b:VCSCommandSourceFile*
|
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-vimrc-example fuf.txt /*fuf-vimrc-example*
|
||||||
fuf.txt fuf.txt /*fuf.txt*
|
fuf.txt fuf.txt /*fuf.txt*
|
||||||
fuzzyfinder fuf.txt /*fuzzyfinder*
|
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_abbrevMap fuf.txt /*g:fuf_abbrevMap*
|
||||||
g:fuf_autoPreview fuf.txt /*g:fuf_autoPreview*
|
g:fuf_autoPreview fuf.txt /*g:fuf_autoPreview*
|
||||||
g:fuf_bookmarkdir_keyDelete fuf.txt /*g:fuf_bookmarkdir_keyDelete*
|
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 smartindent
|
||||||
setlocal autoindent
|
setlocal autoindent
|
||||||
setlocal formatoptions=tcq "set VIms default
|
setlocal formatoptions=tcq "set VIms default
|
||||||
|
let g:blogger_login="gryf73"
|
||||||
if exists("b:did_rst_plugin")
|
let g:blogger_name="rdobosz"
|
||||||
finish " only load once
|
let g:blogger_browser=1
|
||||||
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
|
|
||||||
|
|||||||
@@ -57,3 +57,12 @@ snippet figure
|
|||||||
:figclass: ${3:custclass}
|
:figclass: ${3:custclass}
|
||||||
|
|
||||||
$2
|
$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