From f0bb910453a456d1cbe1430bb2a38fdbc43afa75 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Mon, 5 Dec 2016 18:47:18 -0600 Subject: [PATCH 01/12] FIXED buf_list INDEX ERROR IN vim_encoding_check() IMPROVED BUFFER NAME AND BUFFER EMPTY CHECK IN blog_wise_open_view() --- plugin/blog.vim | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/plugin/blog.vim b/plugin/blog.vim index 41ae7e9..a03a277 100644 --- a/plugin/blog.vim +++ b/plugin/blog.vim @@ -119,7 +119,7 @@ def exception_check(func): except IOError, e: echoerr("network error: %s" % e) except Exception, e: - echoerr("something wrong: %s" % e) + echoerr("something wrong: %s" % traceback.format_exc()) raise return __check @@ -623,14 +623,20 @@ def vim_encoding_check(func): "correctly.") elif orig_enc != "utf-8": modified = vim.eval("&modified") + + # CONVERTS CURRENT BUFFER TO UTF-8 buf_list = '\n'.join(vim.current.buffer).decode(orig_enc).encode('utf-8').splitlines() del vim.current.buffer[:] vim.command("setl encoding=utf-8") - vim.current.buffer[0] = buf_list[0] - if len(buf_list) > 1: - vim.current.buffer.append(buf_list[1:]) + + # 2016-12-05: JSTEWART: FIXED INDEX ERROR BY CHANGING FROM 1 TO 0 + # REFILL BUFFER AFTER CONVERSION + if len(buf_list) > 0: + vim.current.buffer.append(buf_list[0:]) + if modified == '0': vim.command('setl nomodified') + return func(*args, **kw) return __check @@ -679,14 +685,28 @@ def blog_wise_open_view(): """ Wisely decides whether to wipe out the content of current buffer or open a new splited window. """ - if vim.current.buffer.name is None and \ - (vim.eval('&modified') == '0' or - len(vim.current.buffer) == 1): + + curBuf = vim.current.buffer + bufname = curBuf.name + bEmpty = False + bNoMod = False + + if( vim.eval('&modified') == '0' ): + bNoMod = True + + if( (len(curBuf) <= 1) and (len(curBuf[0]) <= 1) ): + bEmpty = True + + # 2016-12-05: JSTEWART: BUFFER NAME LENGTH CHECK IN ADDITION TO None CHECK + # WINDOWS WERE MULTIPLYING LIKE RABBITS SINCE + # buffer.name NEVER SEEMS TO EVALUATE TO None + if ( ((bufname is None) or (len(bufname) == 0)) and (bNoMod or bEmpty) ): vim.command('setl modifiable') del vim.current.buffer[:] vim.command('setl nomodified') else: vim.command(":new") + vim.command('setl syntax=blogsyntax') vim.command('setl completefunc=Completable') From 9ed3f4fcdd4b49a4e6364f4e9a7c5d81b5f97683 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Tue, 6 Dec 2016 00:17:32 -0600 Subject: [PATCH 02/12] UNROLL STACK FOR UNHANDLED EXCEPTIONS UP TO 14 ITEMS DEEP --- plugin/blog.vim | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/plugin/blog.vim b/plugin/blog.vim index a03a277..e5eea79 100644 --- a/plugin/blog.vim +++ b/plugin/blog.vim @@ -85,6 +85,7 @@ import urllib import xmlrpclib import re import os +import sys, traceback import mimetypes import webbrowser import tempfile @@ -105,6 +106,23 @@ except ImportError: markdown = markdown_stub() +# 2016-12-06: JSTEWART: ADJUST LINE NUMBERS FOR UNHANDLED EXCEPTIONS +# UNROLL STACK UP TO 14 ITEMS DEEP +def MsgException(e) : + + exc_type, exc_value, exc_traceback = sys.exc_info() + + szMsg = "{}\n".format(repr(e)) + i = 1 + + for (szFile, nLine, szMod, szLine) in traceback.extract_tb(exc_traceback, 14) : + # OFFSET LINE NUMBER TO BEGINNING OF PYTHON TEXT + szMsg += "[{}] {}:{}\n".format(i, "VimRepress", nLine + 81) + i +=1 + + echoerr(szMsg) + + def exception_check(func): def __check(*args, **kwargs): try: @@ -118,8 +136,8 @@ def exception_check(func): echoerr("xmlrpc error: %s" % e.faultString.encode("utf-8")) except IOError, e: echoerr("network error: %s" % e) - except Exception, e: - echoerr("something wrong: %s" % traceback.format_exc()) + except Exception as e: + MsgException(e) raise return __check From 2ab73c6519786002b7d019e79d202af21b09bc7e Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 29 Apr 2018 06:36:09 -0500 Subject: [PATCH 03/12] Create LICENSE --- LICENSE | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. From 3d4454bcdbcee81d327d60963ac809d7c40bbff1 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 29 Apr 2018 07:08:51 -0500 Subject: [PATCH 04/12] VimRepressPy3 v3.3.0b --- README | 40 -- README.md | 65 +++ doc/tags | 6 + doc/vimpress.txt | 39 +- plugin/{blog.vim => vimrepress.py} | 670 ++++++++++++++--------------- plugin/vimrepress.vim | 80 ++++ 6 files changed, 485 insertions(+), 415 deletions(-) delete mode 100644 README create mode 100644 README.md create mode 100644 doc/tags rename plugin/{blog.vim => vimrepress.py} (59%) create mode 100644 plugin/vimrepress.vim diff --git a/README b/README deleted file mode 100644 index ce823a8..0000000 --- a/README +++ /dev/null @@ -1,40 +0,0 @@ -This is a mirror of http://www.vim.org/scripts/script.php?script_id=3510 - -VimRepress is a plugin for managing wordpress blog from Vim, a rewritten of vimscript #1953 , which is broken for years. - -Now VimRepress lives with more powerful again. - -*REQUIREMENT* - -- Vim 7.3+ with python 2.6/2.7 support -- Python Environment matched wtih Vim's support -- python-markdown/python-markdown2 installed -- wordpress 3.0.0 + - - -COMMAND EXAMPLES - -Some commands list above contain special usage, example below may clearify them for you. - - - :BlogList - List 30 recent posts. - :BlogList page - List 30 recent pages. - :BlogList post 100 - List 100 recent posts. - - :BlogNew post - Write an new post. - :BlogNew page - Write an new page. - - :BlogSave - Save (defautely published.) - :BlogSave draft - Save as draft. - - :BlogPreview local - Preview page/post locally in your browser. - :BlogPreview publish - Same as `:BlogSave publish' with brower opened. - - :BlogOpen 679 - :BlogOpen http://your-first-blog.com/archives/679 - :BlogOpen http://your-second-blog.com/?p=679 - :BlogOpen http://your-third-blog.com/with-your-custom-permalink - -More detailed about this commands, type :help vimpress while you have vimrepress installed. - -Developing Repository: https://bitbucket.org/pentie/vimrepress diff --git a/README.md b/README.md new file mode 100644 index 0000000..11e63e0 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# VimRepressPy3 + + - A mod of a mod of a mod of Vimpress, updated for Python 3. + - A vim plugin for writting your WordPress blog. + - Write with Markdown, control posts format precisely. + - Stores Markdown rawtext in WordPress custom fields. + +### Requirements: + + - Vim 7.3+ with Python 3 support + - Python Environment matched wtih Vim's support + - `python-markdown` / `python-markdown2` installed + - WordPress 3.0.0+ + +### Configuration: + +Create account configure as `~/.vimpressrc` in the following format: + +``` +[Blog0] +blog_url = http://a-blog.com/ +username = admin +password = 123456 + +[Blog1] +blog_url = https://someone.wordpress.com/ +username = someone +password = +``` + +### Command Examples: + +``` + + :BlogList - List 30 recent posts. + :BlogList page - List 30 recent pages. + :BlogList post 100 - List 100 recent posts. + + :BlogNew post - Write a new post. + :BlogNew page - Write a new page. + + :BlogSave - Save (defautely published.) + :BlogSave draft - Save as draft. + + :BlogPreview local - Preview page/post locally in your browser. + :BlogPreview publish - Same as `:BlogSave publish' with browser opened. + + :BlogOpen 679 + :BlogOpen http://your-first-blog.com/archives/679 + :BlogOpen http://your-second-blog.com/?p=679 + :BlogOpen http://your-third-blog.com/with-your-custom-permalink + +``` + +For more details, type `:help vimpress` after this plugin has been loaded. + +### Contributors: + + - Adrien Friggeri + - Pigeond + - Justin Sattery + - Lenin Lee + - Conner McDaniel + - Preston M.[BOYPT] + - Jason Stewart diff --git a/doc/tags b/doc/tags new file mode 100644 index 0000000..7db52e4 --- /dev/null +++ b/doc/tags @@ -0,0 +1,6 @@ +COMMANDS vimpress.txt /*COMMANDS* +CONFIGURE vimpress.txt /*CONFIGURE* +EXAMPLES vimpress.txt /*EXAMPLES* +INSTALL vimpress.txt /*INSTALL* +TIPS vimpress.txt /*TIPS* +vimpress.txt vimpress.txt /*vimpress.txt* diff --git a/doc/vimpress.txt b/doc/vimpress.txt index 88c6725..b8d5d44 100644 --- a/doc/vimpress.txt +++ b/doc/vimpress.txt @@ -1,15 +1,16 @@ -*vimpress.txt* Plugin for managing wordpress blog from Vim. +*vimpress.txt* Plugin for managing WordPress blog from Vim. -Script: blog.vim +Script: vimrepress.vim Authors: Adrien Friggeri Pigeond - * Preston M.[BOYPT] + Preston M.[BOYPT] Justin Sattery - Lenin Lee - * Conner McDaniel - (* Currently developing) - Conner's Repository: https://github.com/connermcd/VimRepress - Preston's Repository: https://bitbucket.org/pentie/vimrepress + Lenin Lee + Conner McDaniel + * Jason Stewart + + (* Python 3 Version) + https://github.com/BourgeoisBear/VimRepressPy3 License: Same terms as Vim itself (see |license|) @@ -45,20 +46,20 @@ For Upgraded Users: Hardcoding the password is optional. If a password is not provided, the plugin will prompt for one the first time it's needed. -If you need Markdown support, simply run `sudo apt-get install python-markdown' in Ubuntu. +If you need Markdown support, simply run `sudo apt-get install python-markdown' in Ubuntu. -If you use other distributions (or OSs), refer to your package manager or the python-markdown +If you use other distributions (or OSs), refer to your package manager or the python-markdown project page: http://www.freewisdom.org/projects/python-markdown/Installation *COMMANDS* -Vimpress Commands (parameters in square brackets are optional): +Vimpress Commands (parameters in square brackets are optional): > :BlogList [] [] < Lists a specified number of blog posts or pages for the current blog - starting the with most recent. In this view, you can press + starting the with most recent. In this view, you can press to open a post for edit, or press to move a post to trash. - The Delete function doesn't actually remove your post, but move to + The Delete function doesn't actually remove your post, but move to the trash. [] - either post or page, [Default post]. [] - number to display (only for posts, Default 30) @@ -69,17 +70,17 @@ Vimpress Commands (parameters in square brackets are optional): > :BlogSave [] < Saves the current editing window. - [] - either post or publish. [Default:draft] + [] - either post or publish. [Default:draft] > :BlogPreview [] -< If set to local, converts the editing window to HTML and displays it - locally in a file browser. Otherwise, the command is the same as +< If set to local, converts the editing window to HTML and displays it + locally in a file browser. Otherwise, the command is the same as :BlogSave except that it opens a preview of the post or page on the blog. [] - either local, post, or publish. [Default:local] > :BlogOpen -< Opens the specified post. - - link you copied from the browser, or simply the +< Opens the specified post. + - link you copied from the browser, or simply the numberic post id. > :BlogSwitch [] @@ -122,7 +123,7 @@ Some commands list above contain special usage, example below may clearify them :BlogSave - Save (defautely published.) :BlogSave draft - Save as draft. - :BlogPreview local - Preview page/post locally in your browser. + :BlogPreview local - Preview page/post locally in your browser. :BlogPreview publish - Same as `:BlogSave publish' with brower opened. :BlogOpen 679 diff --git a/plugin/blog.vim b/plugin/vimrepress.py similarity index 59% rename from plugin/blog.vim rename to plugin/vimrepress.py index e5eea79..241cc82 100644 --- a/plugin/blog.vim +++ b/plugin/vimrepress.py @@ -1,190 +1,133 @@ -"####################################################################### -" Copyright (C) 2007 Adrien Friggeri. -" -" This program is free software; you can redistribute it and/or modify -" it under the terms of the GNU General Public License as published by -" the Free Software Foundation; either version 2, or (at your option) -" any later version. -" -" This program is distributed in the hope that it will be useful, -" but WITHOUT ANY WARRANTY; without even the implied warranty of -" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -" GNU General Public License for more details. -" -" You should have received a copy of the GNU General Public License -" along with this program; if not, write to the Free Software Foundation, -" Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -" -" Contributors: Adrien Friggeri -" Pigeond -" Justin Sattery -" Lenin Lee -" Conner McDaniel -" -" Forked By: Preston M.[BOYPT] -" Repository: https://bitbucket.org/pentie/vimrepress -" -" URL: http://www.friggeri.net/projets/vimblog/ -" http://pigeond.net/blog/2009/05/07/vimpress-again/ -" http://pigeond.net/git/?p=vimpress.git -" http://fzysqr.com/ -" http://apt-blog.net -" -" VimRepress -" - A mod of a mod of a mod of Vimpress. -" - A vim plugin fot writting your wordpress blog. -" - Write with Markdown, control posts format precisely. -" - Stores Markdown rawtext in wordpress custom fields. -" -" Version: 3.2.0 -" -" Config: Create account configure as `~/.vimpressrc' in the following -" format: -" -"[Blog0] -"blog_url = http://a-blog.com/ -"username = admin -"password = 123456 -" -"[Blog1] -"blog_url = https://someone.wordpress.com/ -"username = someone -"password = -" -"####################################################################### - -if !has("python") - finish -endif - -function! CompSave(ArgLead, CmdLine, CursorPos) - return "publish\ndraft\n" -endfunction - -function! CompPrev(ArgLead, CmdLine, CursorPos) - return "local\npublish\ndraft\n" -endfunction - -function! CompEditType(ArgLead, CmdLine, CursorPos) - return "post\npage\n" -endfunction - -command! -nargs=? -complete=custom,CompEditType BlogList exec('py blog_list()') -command! -nargs=? -complete=custom,CompEditType BlogNew exec('py blog_new()') -command! -nargs=? -complete=custom,CompSave BlogSave exec('py blog_save()') -command! -nargs=? -complete=custom,CompPrev BlogPreview exec('py blog_preview()') -command! -nargs=1 -complete=file BlogUpload exec('py blog_upload_media()') -command! -nargs=1 BlogOpen exec('py blog_guess_open()') -command! -nargs=? BlogSwitch exec('py blog_config_switch()') -command! -nargs=? BlogCode exec('py blog_append_code()') - -python << EOF # -*- coding: utf-8 -*- import vim -import urllib -import xmlrpclib +import urllib.request, urllib.parse, urllib.error +import xmlrpc.client import re import os -import sys, traceback +import sys import mimetypes import webbrowser import tempfile -from ConfigParser import SafeConfigParser +from configparser import SafeConfigParser -try: - import markdown -except ImportError: - try: - import markdown2 as markdown - except ImportError: - class markdown_stub(object): - def markdown(self, n): - raise VimPressException("The package python-markdown is " - "required and is either not present or not properly " - "installed.") +# -------------------------------- CONSTANTS -------------------------------- - markdown = markdown_stub() +class VRP_CONST: + @staticmethod + def MARKER(): + return dict( + bg = "====================== Meta =========================", + mid = "=====================================================", + ed = "===================== Content =======================", + more = '" =============== Press Here for More ===============', + list_title = '" ====== %(edit_type)s List in %(blog_url)s =========', + ) + + @staticmethod + def APP_NAME(): + return "VimRepressPy3" + + @staticmethod + def IMAGE_TEMPLATE(): + return '' \ + '%(file)s' + + @staticmethod + def LIST_VIEW_KEY_MAP(): + return dict(enter="", delete="") + + @staticmethod + def DEFAULT_LIST_COUNT(): + return "15" + + @staticmethod + def CUSTOM_FIELD_KEY(): + return "mkd_text" +# -------------------------------- /CONSTANTS -------------------------------- -# 2016-12-06: JSTEWART: ADJUST LINE NUMBERS FOR UNHANDLED EXCEPTIONS -# UNROLL STACK UP TO 14 ITEMS DEEP -def MsgException(e) : - - exc_type, exc_value, exc_traceback = sys.exc_info() - - szMsg = "{}\n".format(repr(e)) - i = 1 +# ---------------------------------- UTLILS ---------------------------------- - for (szFile, nLine, szMod, szLine) in traceback.extract_tb(exc_traceback, 14) : - # OFFSET LINE NUMBER TO BEGINNING OF PYTHON TEXT - szMsg += "[{}] {}:{}\n".format(i, "VimRepress", nLine + 81) - i +=1 +class VRP_Exception(Exception): + pass + +class VRP_AssertException(Exception): + pass + +def VRP_Assert(bCond, szMsg, bInfo = False): + if not bCond: + if bInfo: + raise VRP_AssertException(szMsg) + else: + raise VRP_Exception(szMsg) + +# 2016-12-07: JSTEWART: USE STDIN / STDOUT FOR REPORTING. HAS SAME EFFECT PER +# DOCS AT http://vimdoc.sourceforge.net/htmldoc/if_pyth.html +# UNDER *python-output* +def echomsg(s, bNewline = True): + sys.stdout.write(s) - echoerr(szMsg) + if bNewline: + sys.stdout.write("\n") +def echoerr(s): + sys.stderr.write("ERROR: %s\n" % s) def exception_check(func): def __check(*args, **kwargs): try: return func(*args, **kwargs) - except (VimPressException, AssertionError), e: + except (VRP_AssertException) as e: + echomsg(str(e)) + except (VRP_Exception) as e: echoerr(str(e)) - except (xmlrpclib.Fault, xmlrpclib.ProtocolError), e: + except (xmlrpc.client.Fault, xmlrpc.client.ProtocolError) as e: if getattr(e, "faultString", None) is None: - echoerr("xmlrpc error: %s" % e) + echoerr("(XMLRPC) %s" % e) else: - echoerr("xmlrpc error: %s" % e.faultString.encode("utf-8")) - except IOError, e: - echoerr("network error: %s" % e) - except Exception as e: - MsgException(e) - raise - - return __check + echoerr("(XMLRPC) %s" % e.faultString) + except IOError as e: + echoerr("(NETWORK) %s" % e) -echomsg = lambda s: vim.command('echomsg "%s"' % s) -echoerr = lambda s: vim.command('echoerr "%s"' % s) + # 2016-12-07: JSTEWART: LET UNHANDLED EXCEPTIONS BUBBLE-UP, PREVIOUS echoerr() + # DUPLICATED MESSAGE AND ABBREVIATED STACK TRACE -################################################ -# Helper Classes -################################################# + return __check +# ---------------------------------- /UTLILS ---------------------------------- -class VimPressException(Exception): - pass +try: + import markdown +except ImportError: + try: + import markdown2 as markdown + except ImportError: + class markdown_stub(object): + def markdown(self, n): + raise VRP_Exception("The package python-markdown is " + "required and is either not present or not properly " + "installed.") + markdown = markdown_stub() class DataObject(object): - #CONST - DEFAULT_LIST_COUNT = "15" - IMAGE_TEMPLATE = '' \ - '%(file)s' - MARKER = dict(bg="=========== Meta ============", - mid="=============================", - ed="========== Content ==========", - more='"====== Press Here for More ======', - list_title='"====== ' - '%(edit_type)s List in %(blog_url)s =========') - - LIST_VIEW_KEY_MAP = dict(enter="", delete="") - CUSTOM_FIELD_KEY = "mkd_text" - - #Temp variables. - __xmlrpc = None + # TEMP VARIABLES + __oXMLRPC = None __conf_index = 0 - __config = None + __config = None view = 'edit' vimpress_temp_dir = '' - blog_username = property(lambda self: self.xmlrpc.username) - blog_url = property(lambda self: self.xmlrpc.blog_url) - conf_index = property(lambda self: self.__conf_index) - current_post_id = property(lambda self: self.xmlrpc.current_post_id, - lambda self, d: setattr(self.xmlrpc, "current_post_id", d)) - post_cache = property(lambda self: self.xmlrpc.post_cache) + blog_username = property(lambda self: self.oXMLRPC.username) + blog_url = property(lambda self: self.oXMLRPC.blog_url) + conf_index = property(lambda self: self.__conf_index) + post_cache = property(lambda self: self.oXMLRPC.post_cache) + current_post_id = property( + lambda self: self.oXMLRPC.current_post_id, + lambda self, d: setattr(self.oXMLRPC, "current_post_id", d)) @property def current_post(self): @@ -198,7 +141,8 @@ def current_post(self): else: self.post_cache[''] = post - assert post is not None, "current_post, no way to return None" + VRP_Assert(post is not None, "current_post, no way to return None") + return post @current_post.setter @@ -218,23 +162,24 @@ def conf_index(self, index): try: index = int(index) except ValueError: - raise VimPressException("Invalid Index: %s" % index) + raise VRP_Exception("Invalid Index: %s" % index) - #auto increase + # auto increase if index < 0: self.__conf_index += 1 if self.__conf_index >= len(self.config): self.__conf_index = 0 - # user enter index + + # user enter index else: - assert index < len(self.config), "Invalid Index: %d" % index + VRP_Assert(index < len(self.config), "Invalid Index: %d" % index) self.__conf_index = index - self.__xmlrpc = None + self.__oXMLRPC = None @property - def xmlrpc(self): - if self.__xmlrpc is None: + def oXMLRPC(self): + if self.__oXMLRPC is None: conf_index = self.conf_index config = self.config[conf_index] @@ -243,27 +188,28 @@ def xmlrpc(self): blog_username = config['username'] blog_password = config.get('password', '') blog_url = config['blog_url'] - except KeyError, e: - raise VimPressException("Configuration error: %s" % e) - echomsg("Connecting to '%s' ... " % blog_url) + except KeyError as e: + raise VRP_Exception("Configuration error: %s" % e) + + echomsg("Connecting to '%s'... " % blog_url, False) + if blog_password == '': - blog_password = vim_input( - "Enter password for %s" % blog_url, True) - config["xmlrpc_obj"] = wp_xmlrpc(blog_url, - blog_username, blog_password) + blog_password = vim_input("Enter password for %s" % blog_url, True) - self.__xmlrpc = config["xmlrpc_obj"] + config["xmlrpc_obj"] = wp_xmlrpc(blog_url, blog_username, blog_password) + + self.__oXMLRPC = config["xmlrpc_obj"] # Setting tags and categories for completefunc - categories = config.get("categories", None) - if categories is None: - categories = [i["description"].encode("utf-8") - for i in self.xmlrpc.get_categories()] - config["categories"] = categories + categories = [] + for i in self.__oXMLRPC.get_categories(): + categories.append(i["categoryName"]) - vim.command('let s:completable = "%s"' % '|'.join(categories)) + szCats = "|".join(categories) + vim.command('let s:completable = "%s"' % szCats) echomsg("done.") - return self.__xmlrpc + + return self.__oXMLRPC @property def config(self): @@ -278,46 +224,13 @@ def config(self): confpsr.read(confile) for sec in confpsr.sections(): values = [confpsr.get(sec, i) for i in conf_options] - conf_list.append(dict(zip(conf_options, values))) + conf_list.append(dict(list(zip(conf_options, values)))) if len(conf_list) > 0: self.__config = conf_list - else: - raise VimPressException( - "You have an empty `~/.vimpressrc', " - "thus no configuration will be read. " - "If you still have your account info in " - "`.vimrc', remove `~/.vimpressrc' and " - "try again.") - - else: - try: - self.__config = vim.eval("VIMPRESS") - except vim.error: - pass - else: - # wirte config to `~/.vimpressrc`, - # coding account in .vimrc is obsolesced. - if not os.path.exists(confile) and \ - self.__config is not None: - with open(confile, 'w') as f: - for i, c in enumerate(self.__config): - sec = "Blog%d" % i - confpsr.add_section(sec) - for i in conf_options: - confpsr.set(sec, i, c.get(i, '')) - confpsr.write(f) - - echomsg("Your Blog accounts are now copied to " - "`~/.vimpressrc', definding account info " - "in `.vimrc` is now obsolesced, and may " - "lead to secret leak if you share your " - "vim configuration with public. Please " - "REMOVE the `let VIMPRESS =' code in your " - "`.vimrc'. ") if self.__config is None or len(self.__config) == 0: - raise VimPressException("Could not find vimpress " + raise VRP_Exception("Could not find ~/.vimpressrc " "configuration. Please read ':help vimpress' " "for more information.") @@ -326,19 +239,28 @@ def config(self): class wp_xmlrpc(object): + blog_url = None + username = None + password = None + mw_api = None + wp_api = None + mt_api = None + demo_api = None + def __init__(self, blog_url, username, password): self.blog_url = blog_url self.username = username self.password = password - p = xmlrpclib.ServerProxy(os.path.join(blog_url, "xmlrpc.php")) + p = xmlrpc.client.ServerProxy(os.path.join(blog_url, "xmlrpc.php")) self.mw_api = p.metaWeblog self.wp_api = p.wp self.mt_api = p.mt self.demo_api = p.demo - assert self.demo_api.sayHello() == "Hello!", \ - "XMLRPC Error with communication with '%s'@'%s'" % \ - (username, blog_url) + VRP_Assert( + self.demo_api.sayHello() == "Hello!", \ + "XMLRPC Error with communication with '%s'@'%s'" % (username, blog_url) \ + ) self.cache_reset() self.post_cache = dict() @@ -383,6 +305,9 @@ def get_recent_post_titles(self, retrive_count=0): get_categories = lambda self: self.mw_api.getCategories('', self.username, self.password) + new_category = lambda self, category: self.wp_api.newCategory('', + self.username, self.password, category) + new_media_object = lambda self, object_struct: \ self.mw_api.newMediaObject('', self.username, self.password, object_struct) @@ -406,8 +331,8 @@ class ContentStruct(object): @property def META_TEMPLATE(self): KEYS_BASIC = ("StrID", "Title", "Slug") - KEYS_EXT = ("Cats", "Tags") - KEYS_BLOG = ("EditType", "EditFormat", "BlogAddr") + KEYS_EXT = ("Cats", "Tags") + KEYS_BLOG = ("EditType", "EditFormat", "BlogAddr") pt = ['"{k:<6}: {{{t}}}'.format(k=p, t=p.lower()) for p in KEYS_BASIC] if self.EDIT_TYPE == "post": @@ -416,7 +341,7 @@ def META_TEMPLATE(self): pm = "\n".join(pt) bm = "\n".join(['"{k:<11}: {{{t}}}'.format(k=p, t=p.lower()) for p in KEYS_BLOG]) - return u'"{bg}\n{0}\n"{mid}\n{1}\n"{ed}\n'.format(pm, bm, **G.MARKER) + return '"{bg}\n{0}\n"{mid}\n{1}\n"{ed}\n'.format(pm, bm, **VRP_CONST.MARKER()) POST_BEGIN = property(lambda self: len(self.META_TEMPLATE.splitlines())) raw_text = '' @@ -443,33 +368,32 @@ def __init__(self, edit_type=None, post_id=None): def parse_buffer(self): start = 0 - while not vim.current.buffer[start][1:].startswith(G.MARKER['bg']): + while not vim.current.buffer[start][1:].startswith(VRP_CONST.MARKER()['bg']): start += 1 end = start + 1 - while not vim.current.buffer[end][1:].startswith(G.MARKER['ed']): + while not vim.current.buffer[end][1:].startswith(VRP_CONST.MARKER()['ed']): if not vim.current.buffer[end].startswith('"===='): line = vim.current.buffer[end][1:].strip().split(":") k, v = line[0].strip().lower(), ':'.join(line[1:]) - self.buffer_meta[k.strip().lower()] = v.strip().decode('utf-8') + self.buffer_meta[k.strip().lower()] = v.strip() end += 1 if self.EDIT_TYPE != self.buffer_meta["edittype"]: self.EDIT_TYPE = self.buffer_meta["edittype"] self.buffer_meta["content"] = '\n'.join( - vim.current.buffer[end + 1:]).decode('utf-8') + vim.current.buffer[end + 1:]) def fill_buffer(self): meta = dict(strid="", title="", slug="", - cats="", tags="", editformat="Markdown", edittype="") + cats="", tags="", editformat="HTML", edittype="") meta.update(self.buffer_meta) - meta_text = self.META_TEMPLATE.format(**meta)\ - .encode('utf-8').splitlines() + meta_text = self.META_TEMPLATE.format(**meta).splitlines() + vim.command("set ft=html") vim.current.buffer[0] = meta_text[0] vim.current.buffer.append(meta_text[1:]) - content = self.buffer_meta.get("content", ' ')\ - .encode('utf-8').splitlines() + content = self.buffer_meta.get("content", ' ').splitlines() vim.current.buffer.append(content) def update_buffer_meta(self): @@ -479,17 +403,17 @@ def update_buffer_meta(self): """ kw = self.buffer_meta start = 0 - while not vim.current.buffer[start][1:].startswith(G.MARKER['bg']): + while not vim.current.buffer[start][1:].startswith(VRP_CONST.MARKER()['bg']): start += 1 end = start + 1 - while not vim.current.buffer[end][1:].startswith(G.MARKER['ed']): + while not vim.current.buffer[end][1:].startswith(VRP_CONST.MARKER()['ed']): if not vim.current.buffer[end].startswith('"===='): line = vim.current.buffer[end][1:].strip().split(":") k, v = line[0].strip().lower(), ':'.join(line[1:]) if k in kw: - new_line = u"\"%s: %s" % (line[0], kw[k]) - vim.current.buffer[end] = new_line.encode('utf-8') + new_line = "\"%s: %s" % (line[0], kw[k]) + vim.current.buffer[end] = new_line end += 1 def refresh_from_buffer(self): @@ -510,12 +434,12 @@ def refresh_from_buffer(self): #Translate markdown and save in custom fields. if meta["editformat"].lower() == "markdown": for f in struct["custom_fields"]: - if f["key"] == G.CUSTOM_FIELD_KEY: + if f["key"] == VRP_CONST.CUSTOM_FIELD_KEY(): f["value"] = rawtext break # Not found, add new custom field. else: - field = dict(key=G.CUSTOM_FIELD_KEY, value=rawtext) + field = dict(key=VRP_CONST.CUSTOM_FIELD_KEY(), value=rawtext) struct["custom_fields"].append(field) struct["description"] = self.html_text = markdown.markdown(rawtext) @@ -523,11 +447,12 @@ def refresh_from_buffer(self): struct["description"] = self.html_text = rawtext def refresh_from_wp(self, post_id): - # get from wp - self.post_struct_meta = struct = getattr(g_data.xmlrpc, + + # get from wp + self.post_struct_meta = struct = getattr(g_data.oXMLRPC, "get_" + self.EDIT_TYPE)(post_id) - # struct buffer meta + # struct buffer meta meta = dict(editformat="HTML", title=struct["title"], slug=struct["wp_slug"]) @@ -543,18 +468,19 @@ def refresh_from_wp(self, post_id): self.html_text = content = struct["description"] - #detect more text + # detect more text post_more = struct.get(MORE_KEY, '') if len(post_more) > 0: - content += u'' + post_more + content += '' + post_more struct[MORE_KEY] = '' self.html_text = struct["description"] = content - #Use Markdown text if exists in custom fields + # Use Markdown text if exists in custom fields for field in struct["custom_fields"]: - if field["key"] == G.CUSTOM_FIELD_KEY: + if field["key"] == VRP_CONST.CUSTOM_FIELD_KEY(): meta['editformat'] = "Markdown" self.raw_text = content = field["value"] + vim.command("set ft=markdown") break else: self.raw_text = content @@ -567,18 +493,18 @@ def save_post(self): ps = self.post_struct_meta if self.EDIT_TYPE == "post": if ps.get("postid", '') == '' and self.post_id == '': - post_id = g_data.xmlrpc.new_post(ps) + post_id = g_data.oXMLRPC.new_post(ps) else: post_id = ps["postid"] if "postid" in ps \ else int(self.post_id) - g_data.xmlrpc.edit_post(post_id, ps) + g_data.oXMLRPC.edit_post(post_id, ps) else: if ps.get("page_id", '') == '' and self.post_id == '': - post_id = g_data.xmlrpc.new_post(ps) + post_id = g_data.oXMLRPC.new_post(ps) else: post_id = ps["page_id"] if "page_id" in ps \ else int(self.post_id) - g_data.xmlrpc.edit_post(post_id, ps) + g_data.oXMLRPC.edit_post(post_id, ps) self.refresh_from_wp(post_id) @@ -602,11 +528,11 @@ def html_preview(self): g_data.vimpress_temp_dir = tempfile.mkdtemp(suffix="vimpress") html = \ - u""" Vimpress Local Preview: %(title)s %(content)s + """ Vimpress Local Preview: %(title)s %(content)s """ % dict(content=self.html_text, title=self.buffer_meta["title"]) with open(os.path.join( g_data.vimpress_temp_dir, "vimpress_temp.html"), 'w') as f: - f.write(html.encode('utf-8')) + f.write(html) webbrowser.open("file://%s" % f.name) def remote_preview(self, pub="draft"): @@ -617,33 +543,32 @@ def remote_preview(self, pub="draft"): ################################################# -# Golbal Variables +# Global Variables ################################################# -G = DataObject g_data = DataObject() ################################################# # Helper Functions ################################################# - -def vim_encoding_check(func): - """ +""" Decorator. Check vim environment. wordpress via xmlrpc only support unicode data, setting vim to utf-8 for all data compatible. - """ +""" + +def vim_encoding_check(func): + def __check(*args, **kw): orig_enc = vim.eval("&encoding") if orig_enc is None: - echomsg("Failed to detech current vim encoding. Make sure your" - " content encoded in UTF-8 to have vimpress work " - "correctly.") + echomsg("Failed to detect current text encoding.") + echomsg("%s expects utf-8 encoded text." % VRP_CONST.APP_NAME()) elif orig_enc != "utf-8": modified = vim.eval("&modified") - + # CONVERTS CURRENT BUFFER TO UTF-8 - buf_list = '\n'.join(vim.current.buffer).decode(orig_enc).encode('utf-8').splitlines() + buf_list = '\n'.join(vim.current.buffer).decode(orig_enc, 'strict').splitlines() del vim.current.buffer[:] vim.command("setl encoding=utf-8") @@ -658,37 +583,37 @@ def __check(*args, **kw): return func(*args, **kw) return __check - -def view_switch(view = "", assert_view = "", reset = False): - """ +""" Decorator. For commands to switch between edit/list view, data/status need to be configured. - """ +""" +def view_switch(view = "", assert_view = "", reset = False): + def switch(func): def __run(*args, **kw): if assert_view != '': if g_data.view != assert_view: - raise VimPressException("Command only available at '%s' view." % assert_view) + raise VRP_Exception("Command only available at '%s' view." % assert_view) - if func.func_name == "blog_new": + if func.__name__ == "blog_new": if g_data.view == "list": kw["currentContent"] = [''] else: kw["currentContent"] = vim.current.buffer[:] - elif func.func_name == "blog_config_switch": + elif func.__name__ == "blog_config_switch": if g_data.view == "list": kw["refresh_list"] = True if reset: - g_data.xmlrpc.cache_reset() + g_data.oXMLRPC.cache_reset() if view != '': - #Switching view + # Switching view if g_data.view != view: - #from list view + # from list view if g_data.view == "list": - for v in g_data.LIST_VIEW_KEY_MAP.values(): + for v in list(VRP_CONST.LIST_VIEW_KEY_MAP().values()): if vim.eval("mapcheck('%s')" % v): vim.command('unmap %s' % v) @@ -698,17 +623,16 @@ def __run(*args, **kw): return __run return switch - -def blog_wise_open_view(): - """ +""" Wisely decides whether to wipe out the content of current buffer or open a new splited window. - """ +""" +def blog_wise_open_view(): curBuf = vim.current.buffer bufname = curBuf.name bEmpty = False bNoMod = False - + if( vim.eval('&modified') == '0' ): bNoMod = True @@ -718,7 +642,7 @@ def blog_wise_open_view(): # 2016-12-05: JSTEWART: BUFFER NAME LENGTH CHECK IN ADDITION TO None CHECK # WINDOWS WERE MULTIPLYING LIKE RABBITS SINCE # buffer.name NEVER SEEMS TO EVALUATE TO None - if ( ((bufname is None) or (len(bufname) == 0)) and (bNoMod or bEmpty) ): + if( ((bufname is None) or (len(bufname) == 0)) and (bNoMod or bEmpty) ): vim.command('setl modifiable') del vim.current.buffer[:] vim.command('setl nomodified') @@ -726,38 +650,43 @@ def blog_wise_open_view(): vim.command(":new") vim.command('setl syntax=blogsyntax') - vim.command('setl completefunc=Completable') + vim.command('setl completefunc=vimrepress#CateComplete') @vim_encoding_check def vim_input(message = 'input', secret = False): + CONST_VAR_INPUT = "g:vimpressInput" vim.command('call inputsave()') - vim.command("let user_input = %s('%s :')" % (("inputsecret" if secret else "input"), message)) + szCmd = "let %s = %s('%s :')" % (CONST_VAR_INPUT, ("inputsecret" if secret else "input"), message) + vim.command(szCmd) + valRet = vim.eval(CONST_VAR_INPUT) vim.command('call inputrestore()') - return vim.eval('user_input') + echomsg("\n \n", False) + return valRet ################################################# # Command Functions ################################################# +""" + Saves the current editing buffer. + @params pub - either "draft" or "publish" +""" @exception_check @vim_encoding_check @view_switch(assert_view = "edit", reset = True) def blog_save(pub = None): - """ - Saves the current editing buffer. - @params pub - either "draft" or "publish" - """ + if pub not in ("publish", "draft", None): - raise VimPressException(":BlogSave draft|publish") + raise VRP_Exception(":BlogSave draft|publish") cp = g_data.current_post - assert cp is not None, "Can't get current post obj." + VRP_Assert(cp is not None, "Can't get current post obj.") cp.refresh_from_buffer() if cp.buffer_meta["blogaddr"] != g_data.blog_url and cp.post_id != '': confirm = vim_input("Are u sure saving it to \"%s\" ? BlogAddr in current buffer does NOT matched. \nStill saving it ? (may cause data lost) [yes/NO]" % g_data.blog_url) - assert confirm.lower() == 'yes', "Aborted." + VRP_Assert(confirm.lower() == 'yes', "Aborted.", True) cp.post_status = pub cp.save_post() @@ -767,33 +696,50 @@ def blog_save(pub = None): echomsg(notify) vim.command('setl nomodified') - +""" + Creates a new editing buffer of specified type. + @params edit_type - either "post" or "page" +""" @exception_check @vim_encoding_check @view_switch(view = "edit") def blog_new(edit_type = "post", currentContent = None): - """ - Creates a new editing buffer of specified type. - @params edit_type - either "post" or "page" - """ - if edit_type.lower() not in ("post", "page"): - raise VimPressException("Invalid option: %s " % edit_type) - blog_wise_open_view() - g_data.current_post = ContentStruct(edit_type = edit_type) - cp = g_data.current_post - cp.fill_buffer() + if edit_type.lower() not in ("post", "page", "category"): + raise VRP_Exception("Invalid option: %s " % edit_type) -@view_switch(view = "edit") -def blog_edit(edit_type, post_id): - """ + if edit_type.lower() == "category": + category_name = vim_input("New Category name") + category_slug = vim_input("Category slug (optional)") + ret = g_data.oXMLRPC.new_category(dict(name = category_name, slug = category_slug)) + + if type(ret) is int: + echomsg("Category '%s' created with ID %d. Updating local cache ... " + % (category_name, ret)) + categories = [i["categoryName"] + for i in g_data.oXMLRPC.get_categories()] + vim.command('let s:completable = "%s"' % '|'.join(categories)) + echomsg("Done.") + else: + echoerr("(CATEGORY CREATE) %s" % str(ret)) + + else: + blog_wise_open_view() + g_data.current_post = ContentStruct(edit_type = edit_type) + cp = g_data.current_post + cp.fill_buffer() + +""" Opens a new editing buffer with blog content of specified type and id. @params edit_type - either "post" or "page" post_id - the id of the post or page - """ +""" +@view_switch(view = "edit") +def blog_edit(edit_type, post_id): + blog_wise_open_view() if edit_type.lower() not in ("post", "page"): - raise VimPressException("Invalid option: %s " % edit_type) + raise VRP_Exception("Invalid option: %s " % edit_type) post_id = str(post_id) if post_id in g_data.post_cache: @@ -805,35 +751,34 @@ def blog_edit(edit_type, post_id): vim.current.window.cursor = (cp.POST_BEGIN, 0) vim.command('setl nomodified') vim.command('setl textwidth=0') - for v in G.LIST_VIEW_KEY_MAP.values(): + for v in list(VRP_CONST.LIST_VIEW_KEY_MAP().values()): if vim.eval("mapcheck('%s')" % v): vim.command('unmap %s' % v) -@view_switch(assert_view = "list") -def blog_delete(edit_type, post_id): - """ +""" Deletes a page or post of specified id. @params edit_type - either "page" or "post" post_id - the id of the post or page - """ +""" +@view_switch(assert_view = "list") +def blog_delete(edit_type, post_id): if edit_type.lower() not in ("post", "page"): - raise VimPressException("Invalid option: %s " % edit_type) - deleted = getattr(g_data.xmlrpc, "delete_" + edit_type)(post_id) - assert deleted is True, "There was a problem deleting the %s." % edit_type - echomsg("Deleted %s id %s. " % (edit_type, str(post_id))) - g_data.xmlrpc.cache_remove_post(post_id) + raise VRP_Exception("Invalid option: %s " % edit_type) + deleted = getattr(g_data.oXMLRPC, "delete_" + edit_type)(post_id) + VRP_Assert(deleted is True, "There was a problem deleting the %s." % edit_type) + echomsg("Deleted %s id %s." % (edit_type, str(post_id))) + g_data.oXMLRPC.cache_remove_post(post_id) blog_list(edit_type) - +""" + Calls blog open on the current line of a listing buffer. +""" @exception_check @view_switch(assert_view = "list") def blog_list_on_key_press(action, edit_type): - """ - Calls blog open on the current line of a listing buffer. - """ if action.lower() not in ("open", "delete"): - raise VimPressException("Invalid option: %s" % action) + raise VRP_Exception("Invalid option: %s" % action) row = vim.current.window.cursor[0] line = vim.current.buffer[row - 1] @@ -844,23 +789,23 @@ def blog_list_on_key_press(action, edit_type): int(id) except ValueError: if line.find("More") != -1: - assert g_data.xmlrpc.is_reached_title_max is False, "No more posts." + VRP_Assert(g_data.oXMLRPC.is_reached_title_max is False, "No more posts.", True) vim.command("setl modifiable") del vim.current.buffer[len(vim.current.buffer) - 1:] append_blog_list(edit_type) - vim.current.buffer.append(G.MARKER['more']) + vim.current.buffer.append(VRP_CONST.MARKER()['more']) vim.command("setl nomodified") vim.command("setl nomodifiable") return else: - raise VimPressException("Move cursor to a post/page line and press Enter.") + raise VRP_Exception("Move cursor to a post/page line and press Enter.") if len(title) > 30: title = title[:30] + ' ...' if action.lower() == "delete": confirm = vim_input("Confirm Delete [%s]: %s? [yes/NO]" % (id, title)) - assert confirm.lower() == 'yes', "Delete Aborted." + VRP_Assert(confirm.lower() == 'yes', "Delete Aborted.", True) vim.command("setl modifiable") del vim.current.buffer[:] @@ -872,53 +817,60 @@ def blog_list_on_key_press(action, edit_type): blog_delete(edit_type, int(id)) -def append_blog_list(edit_type, count = G.DEFAULT_LIST_COUNT): +def append_blog_list(edit_type, count = VRP_CONST.DEFAULT_LIST_COUNT()): if edit_type.lower() == "post": current_posts = len(vim.current.buffer) - 1 retrive_count = int(count) + current_posts - posts_titles = g_data.xmlrpc.get_recent_post_titles(retrive_count) + posts_titles = g_data.oXMLRPC.get_recent_post_titles(retrive_count) vim.current.buffer.append( - [(u"%(postid)s\t%(title)s" % p).encode('utf-8') + [("%(postid)s\t%(title)s" % p) for p in posts_titles[current_posts:]]) else: - pages = g_data.xmlrpc.get_page_list() + pages = g_data.oXMLRPC.get_page_list() vim.current.buffer.append( - [(u"%(page_id)s\t%(page_title)s" % p).encode('utf-8') for p in pages]) + [("%(page_id)s\t%(page_title)s" % p) for p in pages]) +def objDump(obj): + for attr in dir(obj): + if hasattr( obj, attr ): + print( "obj.%s = %s" % (attr, getattr(obj, attr))) +""" + Creates a listing buffer of specified type. + @params edit_type - either "post(s)" or "page(s)" +""" @exception_check @vim_encoding_check @view_switch(view = "list") def blog_list(edit_type = "post", keep_type = False): - """ - Creates a listing buffer of specified type. - @params edit_type - either "post(s)" or "page(s)" - """ + if keep_type: first_line = vim.current.buffer[0] - assert first_line.find("List") != -1, "Failed to detect current list type." + VRP_Assert(first_line.find("List") != -1, "Failed to detect current list type.") edit_type = first_line.split()[1].lower() blog_wise_open_view() - vim.current.buffer[0] = G.MARKER["list_title"] % \ - dict(edit_type = edit_type.capitalize(), blog_url = G.blog_url) + vim.current.buffer[0] = VRP_CONST.MARKER()["list_title"] % \ + dict(edit_type = edit_type.capitalize(), blog_url = g_data.blog_url) if edit_type.lower() not in ("post", "page"): - raise VimPressException("Invalid option: %s " % edit_type) + raise VRP_Exception("Invalid option: %s " % edit_type) - append_blog_list(edit_type, G.DEFAULT_LIST_COUNT) + append_blog_list(edit_type, VRP_CONST.DEFAULT_LIST_COUNT()) if edit_type == "post": - vim.current.buffer.append(G.MARKER['more']) + vim.current.buffer.append(VRP_CONST.MARKER()['more']) vim.command("setl nomodified") vim.command("setl nomodifiable") vim.current.window.cursor = (2, 0) - vim.command("map %(enter)s :py blog_list_on_key_press('open', '%%s')" - % G.LIST_VIEW_KEY_MAP % edit_type) - vim.command("map %(delete)s :py blog_list_on_key_press('delete', '%%s')" - % G.LIST_VIEW_KEY_MAP % edit_type) + + vim.command("map %(enter)s :py3 blog_list_on_key_press('open', '%%s')" + % VRP_CONST.LIST_VIEW_KEY_MAP() % edit_type) + vim.command("map %(delete)s :py3 blog_list_on_key_press('delete', '%%s')" + % VRP_CONST.LIST_VIEW_KEY_MAP() % edit_type) + echomsg("Press to edit. to move to trash.") @@ -931,18 +883,18 @@ def blog_upload_media(file_path): @params file_path - the file's path """ if not os.path.exists(file_path): - raise VimPressException("File does not exist: %s" % file_path) + raise VRP_Exception("File does not exist: %s" % file_path) name = os.path.basename(file_path) filetype = mimetypes.guess_type(file_path)[0] with open(file_path) as f: - bits = xmlrpclib.Binary(f.read()) + bits = xmlrpc.client.Binary(f.read()) - result = g_data.xmlrpc.new_media_object(dict(name = name, type = filetype, bits = bits)) + result = g_data.oXMLRPC.new_media_object(dict(name = name, type = filetype, bits = bits)) ran = vim.current.range if filetype.startswith("image"): - img = G.IMAGE_TEMPLATE % result + img = VRP_CONST.IMAGE_TEMPLATE() % result ran.append(img) else: ran.append(result["url"]) @@ -986,7 +938,7 @@ def blog_preview(pub = "local"): if pub == "draft": echomsg("You have to login in the browser to preview the post when save as draft.") else: - raise VimPressException("Invalid option: %s " % pub) + raise VRP_Exception("Invalid option: %s " % pub) @exception_check @@ -994,19 +946,20 @@ def blog_guess_open(what): """ Tries several methods to get the post id from different user inputs, such as args, url, postid etc. """ - post_id = '' + post_id = '' blog_index = -1 + if type(what) is str: - for i, p in enumerate(vim.eval("VIMPRESS")): - if what.startswith(p["blog_url"]): - blog_index = i + for ix, oCfg in enumerate(g_data.config): + if what.startswith(oCfg["blog_url"]): + blog_index = ix # User input a url contained in the profiles if blog_index != -1: guess_id = re.search(r"\S+?p=(\d+)$", what) - # permantlinks + # permalinks if guess_id is None: # try again for /archives/%post_id% @@ -1014,10 +967,15 @@ def blog_guess_open(what): # fail, try get full link from headers if guess_id is None: - headers = urllib.urlopen(what).headers.headers - for link in headers: - if link.startswith("Link:"): - post_id = re.search(r"<\S+?p=(\d+)>", link).group(1) + + httpResp = urllib.request.urlopen(what) + links = httpResp.getheaders() + + for key, val in links: + if key == 'Link': + oFind = re.search(r"<\S+?p=(\d+)>", val) + if oFind is not None: + post_id = oFind.group(1) else: post_id = guess_id.group(1) @@ -1027,18 +985,18 @@ def blog_guess_open(what): post_id = guess_id.group(1) # detected something ? - assert post_id != '', "Failed to get post/page id from '%s'." % what + VRP_Assert(post_id != '', "Failed to get post/page id from '%s'." % what) - #switch view if needed. + # switch view if needed. if blog_index != -1 and blog_index != g_data.conf_index: blog_config_switch(blog_index) - # Uesr input something not a usabe url, try numberic + # User input something not a usable URL, try numeric else: try: post_id = str(int(what)) except ValueError: - raise VimPressException("Failed to get post/page id from '%s'." % what) + raise VRP_Exception("Failed to get post/page id from '%s'." % what) blog_edit("post", post_id) @@ -1053,4 +1011,4 @@ def blog_config_switch(index = -1, refresh_list = False): g_data.conf_index = index if refresh_list: blog_list(keep_type = True) - echomsg("Vimpress switched to '%s'@'%s'" % (g_data.blog_username, g_data.blog_url)) + echomsg("%s switched to '%s'@'%s'" % (VRP_CONST.APP_NAME(), g_data.blog_username, g_data.blog_url)) diff --git a/plugin/vimrepress.vim b/plugin/vimrepress.vim new file mode 100644 index 0000000..68a3954 --- /dev/null +++ b/plugin/vimrepress.vim @@ -0,0 +1,80 @@ +"#################################################################### +" +" VimRepressPy3 +" +" Forked from Vimpress, Copyright (C) 2007 Adrien Friggeri. +" +" See ../LICENSE for GPL conditions +" +" https://github.com/BourgeoisBear/VimRepressPy3 +" +" Version: 3.3.0b +" +"#################################################################### + +if !has("python3") + echoerr "VimRepress requires Python 3" + finish +endif + +let s:py_loaded = 0 +let s:vimpress_dir = fnamemodify(expand(""), ":p:h") + +function! s:CompSave(ArgLead, CmdLine, CursorPos) + return "publish\ndraft\n" +endfunction + +function! s:CompPrev(ArgLead, CmdLine, CursorPos) + return "local\npublish\ndraft\n" +endfunction + +function! s:CompEditType(ArgLead, CmdLine, CursorPos) + return "post\npage\n" +endfunction + +function! s:CompNewType(ArgLead, CmdLine, CursorPos) + return "post\npage\ncategory\n" +endfunction + +function! vimrepress#CateComplete(findstart, base) + if a:findstart + echoerr "findstart" + " locate the start of the word + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start - 1] =~ '\a' + let start -= 1 + endwhile + return start + else + echoerr "findstart-else" + " find matching items + let res = [] + for m in split(s:completable,"|") + if m =~ '^' . a:base + call add(res, m) + endif + endfor + return res + endif +endfun + +function! s:PyCMD(pyfunc) + if (s:py_loaded == 0) + exec("cd " . s:vimpress_dir) + let s:pyfile = fnamemodify("vimrepress.py", ":p") + exec("cd -") + exec("py3file " . s:pyfile) + let s:py_loaded = 1 + endif + exec('python3 ' . a:pyfunc) +endfunction + +command! -nargs=? -complete=custom,s:CompEditType BlogList call s:PyCMD('blog_list()') +command! -nargs=? -complete=custom,s:CompNewType BlogNew call s:PyCMD('blog_new()') +command! -nargs=? -complete=custom,s:CompSave BlogSave call s:PyCMD('blog_save()') +command! -nargs=? -complete=custom,s:CompPrev BlogPreview call s:PyCMD('blog_preview()') +command! -nargs=1 -complete=file BlogUpload call s:PyCMD('blog_upload_media()') +command! -nargs=1 BlogOpen call s:PyCMD('blog_guess_open()') +command! -nargs=? BlogSwitch call s:PyCMD('blog_config_switch()') +command! -nargs=? BlogCode call s:PyCMD('blog_append_code()') From 28bb73f692676ba57d5259ed2f08e80795f7dcd9 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 29 Apr 2018 17:10:59 -0500 Subject: [PATCH 05/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11e63e0..e9011bf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# VimRepressPy3 +# VimRepressPy3: Edit your WordPress blog from Vim. - A mod of a mod of a mod of Vimpress, updated for Python 3. - A vim plugin for writting your WordPress blog. From 61ca3a9e1f5824b85a7c3d98995221eb7654074b Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 29 Apr 2018 23:19:35 -0500 Subject: [PATCH 06/12] Changed file open mode to "rb" for :BlogUpload - Py3 defaults to utf-8 strings, so text mode for blobs is unacceptable (invalid utf-8 glyph errors) --- plugin/vimrepress.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugin/vimrepress.py b/plugin/vimrepress.py index 241cc82..73c22d0 100644 --- a/plugin/vimrepress.py +++ b/plugin/vimrepress.py @@ -4,6 +4,7 @@ import xmlrpc.client import re import os +import pprint import sys import mimetypes import webbrowser @@ -39,7 +40,7 @@ def LIST_VIEW_KEY_MAP(): @staticmethod def DEFAULT_LIST_COUNT(): - return "15" + return str(vim.current.window.height) @staticmethod def CUSTOM_FIELD_KEY(): @@ -874,20 +875,21 @@ def blog_list(edit_type = "post", keep_type = False): echomsg("Press to edit. to move to trash.") +""" + Uploads a file to the blog. + @params file_path - the file's path +""" @exception_check @vim_encoding_check @view_switch(assert_view = "edit") def blog_upload_media(file_path): - """ - Uploads a file to the blog. - @params file_path - the file's path - """ + if not os.path.exists(file_path): raise VRP_Exception("File does not exist: %s" % file_path) name = os.path.basename(file_path) filetype = mimetypes.guess_type(file_path)[0] - with open(file_path) as f: + with open(file_path, mode='rb') as f: bits = xmlrpc.client.Binary(f.read()) result = g_data.oXMLRPC.new_media_object(dict(name = name, type = filetype, bits = bits)) From 905b52a769a73849292120a92acdb8997cee3e97 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sat, 23 Oct 2021 02:14:42 +0000 Subject: [PATCH 07/12] python 3.2 configparser deprecation fix --- plugin/vimrepress.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/vimrepress.py b/plugin/vimrepress.py index 73c22d0..d3d269f 100644 --- a/plugin/vimrepress.py +++ b/plugin/vimrepress.py @@ -9,7 +9,7 @@ import mimetypes import webbrowser import tempfile -from configparser import SafeConfigParser +import configparser # -------------------------------- CONSTANTS -------------------------------- @@ -216,7 +216,7 @@ def oXMLRPC(self): def config(self): if self.__config is None or len(self.__config) == 0: - confpsr = SafeConfigParser() + confpsr = configparser.ConfigParser() confile = os.path.expanduser("~/.vimpressrc") conf_options = ("blog_url", "username", "password") From 4f2ae91c469e27a38aec64f66f1a0262de1d5e72 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 26 Dec 2021 07:00:53 -0500 Subject: [PATCH 08/12] - enabled code fencing in python markdown (w/ pygments) --- plugin/vimrepress.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/plugin/vimrepress.py b/plugin/vimrepress.py index d3d269f..f8babb9 100644 --- a/plugin/vimrepress.py +++ b/plugin/vimrepress.py @@ -101,16 +101,13 @@ def __check(*args, **kwargs): try: import markdown except ImportError: - try: - import markdown2 as markdown - except ImportError: - class markdown_stub(object): - def markdown(self, n): - raise VRP_Exception("The package python-markdown is " - "required and is either not present or not properly " - "installed.") + class markdown_stub(object): + def markdown(self, *args): + raise VRP_Exception("The package python-markdown is " + "required and is either not present or not properly " + "installed.") - markdown = markdown_stub() + markdown = markdown_stub() class DataObject(object): @@ -443,7 +440,17 @@ def refresh_from_buffer(self): field = dict(key=VRP_CONST.CUSTOM_FIELD_KEY(), value=rawtext) struct["custom_fields"].append(field) - struct["description"] = self.html_text = markdown.markdown(rawtext) + struct["description"] = self.html_text = markdown.markdown( + rawtext, + extensions=['fenced_code','codehilite'], + extension_configs={ + 'codehilite': { + 'use_pygments': True, + 'css_class': 'pygment', + 'noclasses': False, + 'guess_lang': False, + 'linenums': False + }}) else: struct["description"] = self.html_text = rawtext From 32cf08205e1512bfb820a2083a768b507e5ef15c Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 26 Dec 2021 21:33:43 -0500 Subject: [PATCH 09/12] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index e9011bf..d235046 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - Vim 7.3+ with Python 3 support - Python Environment matched wtih Vim's support - - `python-markdown` / `python-markdown2` installed + - requires `markdown` & `pygments` modules - WordPress 3.0.0+ ### Configuration: @@ -31,7 +31,6 @@ password = ### Command Examples: ``` - :BlogList - List 30 recent posts. :BlogList page - List 30 recent pages. :BlogList post 100 - List 100 recent posts. @@ -49,7 +48,6 @@ password = :BlogOpen http://your-first-blog.com/archives/679 :BlogOpen http://your-second-blog.com/?p=679 :BlogOpen http://your-third-blog.com/with-your-custom-permalink - ``` For more details, type `:help vimpress` after this plugin has been loaded. From e0af2bb06a9940727bf6e07c125877729ca9b9f4 Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Sun, 26 Dec 2021 21:53:42 -0500 Subject: [PATCH 10/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d235046..799e5de 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ### Configuration: -Create account configure as `~/.vimpressrc` in the following format: +Create account configure as `~/.vimpressrc` in the following format (be sure to `chmod 600` this file): ``` [Blog0] From bc3f71076234e737ad666c8c1c6b97dd3472f2fe Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Tue, 28 Dec 2021 02:48:11 +0000 Subject: [PATCH 11/12] - require 0o600 perms on .vimpressrc - fix missing module reporting for `markdown` import - set filetype to `ft=markdown` appropriately when opening post/page --- plugin/vimrepress.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/plugin/vimrepress.py b/plugin/vimrepress.py index f8babb9..0576b37 100644 --- a/plugin/vimrepress.py +++ b/plugin/vimrepress.py @@ -11,6 +11,17 @@ import tempfile import configparser +try: + import markdown +except ImportError: + class markdown_stub(object): + def markdown(self, markdown, extensions, extension_configs): + raise VRP_Exception("The package python-markdown is " + "required and is either not present or not properly " + "installed.") + + markdown = markdown_stub() + # -------------------------------- CONSTANTS -------------------------------- class VRP_CONST: @@ -98,17 +109,6 @@ def __check(*args, **kwargs): # ---------------------------------- /UTLILS ---------------------------------- -try: - import markdown -except ImportError: - class markdown_stub(object): - def markdown(self, *args): - raise VRP_Exception("The package python-markdown is " - "required and is either not present or not properly " - "installed.") - - markdown = markdown_stub() - class DataObject(object): # TEMP VARIABLES @@ -215,6 +215,13 @@ def config(self): confpsr = configparser.ConfigParser() confile = os.path.expanduser("~/.vimpressrc") + o_stat = os.stat(confile) + flags_ugo = 0x1FF & o_stat.st_mode + if flags_ugo != 0o600: + raise VRP_Exception( + "Please set permissions on ~/.vimpressrc to 600. " + "(cmd: chmod 600 ~/.vimpressrc)") + conf_options = ("blog_url", "username", "password") if os.path.exists(confile): @@ -384,11 +391,17 @@ def parse_buffer(self): vim.current.buffer[end + 1:]) def fill_buffer(self): + meta = dict(strid="", title="", slug="", cats="", tags="", editformat="HTML", edittype="") meta.update(self.buffer_meta) meta_text = self.META_TEMPLATE.format(**meta).splitlines() - vim.command("set ft=html") + + if meta['editformat'].lower() == "markdown": + vim.command("set ft=markdown") + else: + vim.command("set ft=html") + vim.current.buffer[0] = meta_text[0] vim.current.buffer.append(meta_text[1:]) content = self.buffer_meta.get("content", ' ').splitlines() From 399dbd9cdd675607c1651fb18befa4083114bf4a Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Mon, 27 Dec 2021 22:01:31 -0500 Subject: [PATCH 12/12] Update README.md --- README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 799e5de..68ee64a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ -# VimRepressPy3: Edit your WordPress blog from Vim. +# VimRepressPy3 + +### Edit your WordPress blog from Vim. - - A mod of a mod of a mod of Vimpress, updated for Python 3. - - A vim plugin for writting your WordPress blog. - Write with Markdown, control posts format precisely. - Stores Markdown rawtext in WordPress custom fields. + - Supports github-style fenced code-blocks. ### Requirements: @@ -28,6 +29,22 @@ username = someone password = ``` +### Pygments CSS + +To get pygments higlighting for fenced codeblocks, you will need to generate pygments CSS for your preferred colorscheme, and include it with your site CSS: + +```sh +pygmentize -f html -a .pygment -S +``` + +To see the list of available pygments styles on your computer: + +```sh +pygmentize -L styles +``` + +Or use their online demo at https://pygments.org/demo/. + ### Command Examples: ```