From 18a8c3dd2589d265912cf2107ef1f60bc39198b1 Mon Sep 17 00:00:00 2001 From: Christian Heinrich Date: Fri, 29 May 2015 11:43:59 +0200 Subject: [PATCH 1/3] [SYNTAX] Fix syntax for #+BEGIN_* blocks - Without this fix, all #+BEGIN_* blocks are not correctly highlighted; this fix just allows whitespace to occur before the #+BEGIN blocks, which is quite common in documents. --- syntax/org.vim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/syntax/org.vim b/syntax/org.vim index d6a867b2..22105adc 100644 --- a/syntax/org.vim +++ b/syntax/org.vim @@ -298,9 +298,9 @@ hi def link org_title Title " TODO: http://vim.wikia.com/wiki/Different_syntax_highlighting_within_regions_of_a_file syntax match org_verbatim /^\s*>.*/ syntax match org_code /^\s*:.*/ -syntax region org_verbatim start="^#+BEGIN_.*" end="^#+END_.*" keepend contains=org_block_delimiter -syntax region org_code start="^#+BEGIN_SRC" end="^#+END_SRC" keepend contains=org_block_delimiter -syntax region org_code start="^#+BEGIN_EXAMPLE" end="^#+END_EXAMPLE" keepend contains=org_block_delimiter +syntax region org_verbatim start="^\s*#+BEGIN_.*" end="^\s*#+END_.*" keepend contains=org_block_delimiter +syntax region org_code start="^\s*#+BEGIN_SRC" end="^\s*#+END_SRC" keepend contains=org_block_delimiter +syntax region org_code start="^\s*#+BEGIN_EXAMPLE" end="^\s*#+END_EXAMPLE" keepend contains=org_block_delimiter hi def link org_code String hi def link org_verbatim String From eadd813bb13ecc99d278040ad89adb0259a7c09c Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Tue, 10 Feb 2015 12:52:22 -0500 Subject: [PATCH 2/3] typo on "folding" --- README.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.org b/README.org index ea8bee8d..275195b2 100644 --- a/README.org +++ b/README.org @@ -19,7 +19,7 @@ list of the already supported features: - Proper syntax highlighting - - Cycle visibility of headings (foliding) + - Cycle visibility of headings (folding) - Navigate between headings - Edit the structure of the document: add, move, promote, denote headings and more From 71d342579254c0c384e469713d1cf58167962216 Mon Sep 17 00:00:00 2001 From: Christian Heinrich Date: Tue, 14 Jul 2015 19:24:40 +0200 Subject: [PATCH 3/3] Added support for extracting source code blocks (tangling) - This feature needs emacs, though. - Updated documentation as well. - Tests do not yet work correctly... --- doc/orgguide.txt | 62 +++++++++++- ftplugin/org.vim | 2 +- ftplugin/orgmode/plugins/BabelTangle.py | 122 ++++++++++++++++++++++++ tests/orgmode_testfile.org | 17 ++-- tests/run_tests.py | 2 + tests/test_plugin_babel_tangle.py | 44 +++++++++ 6 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 ftplugin/orgmode/plugins/BabelTangle.py create mode 100644 tests/test_plugin_babel_tangle.py diff --git a/doc/orgguide.txt b/doc/orgguide.txt index 779dcc60..338f23f9 100644 --- a/doc/orgguide.txt +++ b/doc/orgguide.txt @@ -1120,7 +1120,67 @@ PUBLISHING *orgguide-publishing* ============================================================================== WORKING WITH SOURCE CODE *orgguide-source* - Not yet implemented in vim-orgmode~ + +NOTE: vim-orgmode relies on Emacs for this feature. Emacs _and_ Emacs' + org-mode need to be installed! + +------------------------------------------------------------------------------ +Extracting Source Code~ + *orgguide-source-extract* + +vim-orgmode allows to extract ("tangle") source blocks, that is, to extract source code +from your org-file and write them into file(s) on your filesystem. This +actually uses emacs in the background, meaning that the behavior of +vim-orgmode is identical with emacs org-mode! One implication of this is that +"noweb" syntax can be used to re-order code blocks in your org document. For +more details, please see the org-manual Section 14.10 (available at +http://orgmode.org/manual/Noweb-reference-syntax.html#Noweb-reference-syntax) +and the noweb reference: http://www.cs.tufts.edu/~nr/noweb/ + +Currently, the following commands are supported: +> + :OrgBabelTangle + :OrgBabelTangleFile +< +While the first command simply tangles the current file, the second +command prompts for a filename to be entered; this file will then be tangled. + +Here is an example of a code block with the tangle header: + +> + #+BEGIN_SRC sh :tangle filename + print -- "This Works!" + #+END_SRC +< +You can explicitly exclude a code block from being tangled (though this is the +default): + +> + #+BEGIN_SRC sh :tangle no + print -- "Excluded from tangling!" + #+END_SRC +< + +Another way to mark a block for tangling is the following: +> + #+BEGIN_SRC sh :tangle yes + print -- "Included" + #+END_SRC +< +In the last example, the output will be written to org-file-name.sh, as the +filename will be the filename of your orgfile with the ".org"-extension being +replaced by the language name (here: "sh"). +------------------------------------------------------------------------------ +Keybindings~ + + *orgguide-cvt* + cvt Call :OrgBabelTangle -- this tangles the current file + only + + *orgguide-cvf* + cvf Call :OrgBabelTangleFile -- prompts for a filename to + be entered and attempts to tangle this file. + Unfortunately, there is no autocompletion available... ============================================================================== MISCELLANEOUS *orgguide-misc* diff --git a/ftplugin/org.vim b/ftplugin/org.vim index 7bfb3a86..1d561293 100644 --- a/ftplugin/org.vim +++ b/ftplugin/org.vim @@ -42,7 +42,7 @@ let g:loaded_org = 1 " Default org plugins that will be loaded (in the given order) if ! exists('g:org_plugins') && ! exists('b:org_plugins') - let g:org_plugins = ['ShowHide', '|', 'Navigator', 'EditStructure', 'EditCheckbox', '|', 'Hyperlinks', '|', 'Todo', 'TagsProperties', 'Date', 'Agenda', 'Misc', '|', 'Export'] + let g:org_plugins = ['ShowHide', '|', 'Navigator', 'EditStructure', 'EditCheckbox', '|', 'Hyperlinks', '|', 'Todo', 'TagsProperties', 'Date', 'Agenda', 'Misc', '|', 'Export', '|', 'BabelTangle'] endif if ! exists('g:org_syntax_highlight_leading_stars') && ! exists('b:org_syntax_highlight_leading_stars') diff --git a/ftplugin/orgmode/plugins/BabelTangle.py b/ftplugin/orgmode/plugins/BabelTangle.py new file mode 100644 index 00000000..afd6342f --- /dev/null +++ b/ftplugin/orgmode/plugins/BabelTangle.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +import os +import subprocess + +import vim + +from orgmode._vim import ORGMODE, echoe, echom, get_user_input +from orgmode.menu import Submenu, ActionEntry, add_cmd_mapping_menu +from orgmode.keybinding import Keybinding, Plug, Command +from orgmode import settings + + +class BabelTangle(object): + u""" + Tangle source code blocks using emacs. + """ + + def __init__(self): + u""" Initialize plugin """ + object.__init__(self) + # menu entries this plugin should create + self.menu = ORGMODE.orgmenu + Submenu(u'Babel') + + # key bindings for this plugin + # key bindings are also registered through the menu so only additional + # bindings should be put in this variable + self.keybindings = [] + + # commands for this plugin + self.commands = [] + + @classmethod + def _get_init_script(cls): + init_script = settings.get(u'org_export_init_script', u'') + if init_script: + init_script = os.path.expandvars(os.path.expanduser(init_script)) + if os.path.exists(init_script): + return init_script + else: + echoe(u'Unable to find init script %s' % init_script) + + @classmethod + def _callFunction(cls, function): + """Export current file to format_. + + :format_: elisp function to call + :returns: return code + """ + emacsbin = os.path.expandvars(os.path.expanduser( + settings.get(u'org_export_emacs', u'/usr/bin/emacs'))) + if not os.path.exists(emacsbin): + echoe(u'Unable to find emacs binary %s' % emacsbin) + + # build the export command + cmd = [ + emacsbin, + u'-nw', + u'--batch', + u'--visit=%s' % vim.eval(u'expand("%:p")'), + u'--execute=%s' % function + ] + # source init script as well + init_script = cls._get_init_script() + if init_script: + cmd.extend(['--script', init_script]) + + # export + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p.wait() + + if p.returncode != 0 or settings.get(u'org_export_verbose') == 1: + echom('\n'.join(p.communicate())) + return p.returncode + + @classmethod + def tangle(cls): + u"""Tangle all codeblocks of the current buffer""" + ret = cls._callFunction(u'(funcall \'org-babel-tangle)') + if ret != 0: + echoe('Could not tangle file; make sure org-babel-tangle is callable from within emacs.') + else: + echom(u'Tangling successful') + + @classmethod + def tangleFile(cls): + u"""Tangle all codeblocks of the specified filename""" + msg = u'Specify filename (relative to current path)' + filename = get_user_input(msg) + ret = cls._callFunction(u'(org-babel-tangle-file "'+filename+'")') + if ret != 0: + echoe('Could not tangle file; make sure org-babel-tangle-file is callable from within emacs.') + else: + echom(u' Successfully tangled file ' + filename + '!') + + def register(self): + u"""Registration and keybindings.""" + + # path to emacs executable + settings.set(u'org_export_emacs', u'/usr/bin/emacs') + # verbose output for export + settings.set(u'org_export_verbose', 0) + # allow the user to define an initialization script + settings.set(u'org_export_init_script', u'') + + add_cmd_mapping_menu( + self, + name=u'OrgBabelTangle', + function=u':py ORGMODE.plugins[u"BabelTangle"].tangle()', + key_mapping=u'cvt', + menu_desrc=u'Tangle file (via Emacs)' + ) + + add_cmd_mapping_menu( + self, + name=u'OrgBabelTangleFile', + function=u':py ORGMODE.plugins[u"BabelTangle"].tangleFile()', + key_mapping=u'cvf', + menu_desrc=u'Tangle file (via Emacs)' + ) + +# vim: set noexpandtab: diff --git a/tests/orgmode_testfile.org b/tests/orgmode_testfile.org index 7eda72ff..324b1f35 100644 --- a/tests/orgmode_testfile.org +++ b/tests/orgmode_testfile.org @@ -1,18 +1,21 @@ - +* SRC blocks + #+BEGIN_SRC sh :tangle tmp_tangled_file + print -- "Yes!" + #+END_SRC * bold, italics and underline syntax matching ** Should match: -*foo* *foo* +*foo* *foo* *Really, quite long sentence*. -_foo_ _foo_ +_foo_ _foo_ _really, quite long sentence._. - *Übermensch á* *eä* *ý€* + *Übermensch á* *eä* *ý€* _Ÿ ï_ *sdf l.* - *sdfsdf ,.* - *foo_ sdf /* + *sdfsdf ,.* + *foo_ sdf /* /sdf sdf sdf ./ /google.com/ @@ -25,7 +28,7 @@ _really, quite long sentence._. ** Should not match http://google.com/ //google.com/ - * sdf* _ sdf_ + * sdf* _ sdf_ *sdfsdf sdf,* *foo * foo_not underlined_bar diff --git a/tests/run_tests.py b/tests/run_tests.py index baa149cc..f5c4bcef 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -12,6 +12,7 @@ import test_liborgdatetime import test_liborgtimerange +import test_plugin_babel_tangle import test_plugin_date import test_plugin_edit_structure import test_plugin_edit_checkbox @@ -41,6 +42,7 @@ tests.addTests(test_liborgtimerange.suite()) # plugins + tests.addTests(test_plugin_babel_tangle.suite()) tests.addTests(test_plugin_date.suite()) tests.addTests(test_plugin_edit_structure.suite()) tests.addTests(test_plugin_edit_checkbox.suite()) diff --git a/tests/test_plugin_babel_tangle.py b/tests/test_plugin_babel_tangle.py new file mode 100644 index 00000000..27ef66d0 --- /dev/null +++ b/tests/test_plugin_babel_tangle.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +import unittest +import sys +sys.path.append(u'../ftplugin') + +import vim +import os.path + +from orgmode._vim import ORGMODE + +PLUGIN_NAME = u'BabelTangle' + +counter = 0 + +class BabelTangleTestCase(unittest.TestCase): + + def setUp(self): + global counter + counter += 1 + vim.CMDHISTORY = [] + vim.CMDRESULTS = {} + vim.EVALHISTORY = [] + vim.current.buffer[:] = [ i.encode(u'utf-8') for i in u""" +* Heading 1 + This is some text, followed by a source block + + #+BEGIN_SRC sh :tangle tmp_tangle_fileoutput + print -- "Everything ok!" + #+END_SRC +""".split(u'\n') ] + + def test_tangling(self): + global counter + counter += 1 + # test on self.c1 + # update_checkboxes_status + vim.command("OrgBabelTangle") + self.assertTrue(os.path.isfile("tmp_tangle_fileoutput")) + +def suite(): + return unittest.TestLoader().loadTestsFromTestCase(BabelTangleTestCase) + +# vim: set noexpandtab