├── .gitignore ├── .pylintrc ├── .travis.yml ├── CHANGELOG.org ├── LICENSE ├── Makefile ├── README.org ├── doc └── orgguide.txt ├── examples ├── mylife.gif ├── mylife.org ├── mylife.png └── plugins │ └── PluginExample.py ├── ftdetect └── org.vim ├── ftplugin ├── org.cnf ├── org.vim └── orgmode │ ├── __init__.py │ ├── _vim.py │ ├── docs │ ├── Makefile │ ├── conf.py │ ├── index.rst │ ├── make.bat │ ├── orgmode.liborgmode.rst │ ├── orgmode.plugins.rst │ ├── orgmode.py3compat.rst │ └── orgmode.rst │ ├── exceptions.py │ ├── keybinding.py │ ├── liborgmode │ ├── __init__.py │ ├── agenda.py │ ├── agendafilter.py │ ├── base.py │ ├── checkboxes.py │ ├── documents.py │ ├── dom_obj.py │ ├── headings.py │ └── orgdate.py │ ├── menu.py │ ├── plugins │ ├── Agenda.py │ ├── Date.py │ ├── EditCheckbox.py │ ├── EditStructure.py │ ├── Export.py │ ├── Hyperlinks.py │ ├── LoggingWork.py │ ├── Misc.py │ ├── Navigator.py │ ├── ShowHide.py │ ├── TagsProperties.py │ ├── Todo.py │ └── __init__.py │ ├── py3compat │ ├── __init__.py │ ├── encode_compatibility.py │ ├── py_py3_string.py │ ├── unicode_compatibility.py │ └── xrange_compatibility.py │ ├── settings.py │ └── vimbuffer.py ├── indent └── org.vim ├── syntax ├── org.vim ├── orgagenda.vim └── orgtodo.vim └── tests ├── orgmode_testfile.org ├── run_tests.py ├── test_libagendafilter.py ├── test_libbase.py ├── test_libcheckbox.py ├── test_libheading.py ├── test_liborgdate.py ├── test_liborgdate_parsing.py ├── test_liborgdate_utf8.py ├── test_liborgdatetime.py ├── test_liborgtimerange.py ├── test_plugin_date.py ├── test_plugin_edit_checkbox.py ├── test_plugin_edit_structure.py ├── test_plugin_mappings.py ├── test_plugin_misc.py ├── test_plugin_navigator.py ├── test_plugin_show_hide.py ├── test_plugin_tags_properties.py ├── test_plugin_todo.py ├── test_vimbuffer.py └── vim.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | tags 4 | .ropeproject 5 | .cover* 6 | cover* 7 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Specify a configuration file. 4 | #rcfile= 5 | 6 | # Python code to execute, usually for sys.path manipulation such as 7 | # pygtk.require(). 8 | init-hook=sys.path.append(os.path.abspath('ftplugin')) 9 | 10 | # Profiled execution. 11 | profile=no 12 | 13 | # Add files or directories to the blacklist. They should be base names, not 14 | # paths. 15 | ignore=.git 16 | 17 | # Pickle collected data for later comparisons. 18 | persistent=yes 19 | 20 | # List of plugins (as comma separated values of python modules names) to load, 21 | # usually to register additional checkers. 22 | load-plugins= 23 | 24 | 25 | [MESSAGES CONTROL] 26 | 27 | # Enable the message, report, category or checker with the given id(s). You can 28 | # either give multiple identifier separated by comma (,) or put this option 29 | # multiple time. 30 | #enable= 31 | 32 | # Disable the message, report, category or checker with the given id(s). You 33 | # can either give multiple identifier separated by comma (,) or put this option 34 | # multiple time (only on the command line, not in the configuration file where 35 | # it should appear only once). 36 | #disable= 37 | 38 | [REPORTS] 39 | 40 | # Set the output format. Available formats are text, parseable, colorized, msvs 41 | # (visual studio) and html 42 | output-format=parseable 43 | 44 | # Include message's id in output 45 | include-ids=no 46 | 47 | # Put messages in a separate file for each module / package specified on the 48 | # command line instead of printing them on stdout. Reports (if any) will be 49 | # written in a file name "pylint_global.[txt|html]". 50 | files-output=no 51 | 52 | # Tells whether to display a full report or only the messages 53 | reports=yes 54 | 55 | # Python expression which should return a note less than 10 (10 is the highest 56 | # note). You have access to the variables errors warning, statement which 57 | # respectively contain the number of errors / warnings messages and the total 58 | # number of statements analyzed. This is used by the global evaluation report 59 | # (RP0004). 60 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 61 | 62 | # Add a comment according to your evaluation note. This is used by the global 63 | # evaluation report (RP0004). 64 | comment=no 65 | 66 | 67 | [TYPECHECK] 68 | 69 | # Tells whether missing members accessed in mixin class should be ignored. A 70 | # mixin class is detected if its name ends with "mixin" (case insensitive). 71 | ignore-mixin-members=yes 72 | 73 | # List of classes names for which member attributes should not be checked 74 | # (useful for classes with attributes dynamically set). 75 | ignored-classes=SQLObject 76 | 77 | # When zope mode is activated, add a predefined set of Zope acquired attributes 78 | # to generated-members. 79 | zope=no 80 | 81 | # List of members which are set dynamically and missed by pylint inference 82 | # system, and so shouldn't trigger E0201 when accessed. Python regular 83 | # expressions are accepted. 84 | generated-members=REQUEST,acl_users,aq_parent 85 | 86 | 87 | [BASIC] 88 | 89 | # Required attributes for module, separated by a comma 90 | required-attributes= 91 | 92 | # List of builtins function names that should not be used, separated by a comma 93 | bad-functions=map,filter,apply,input 94 | 95 | # Regular expression which should only match correct module names 96 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 97 | 98 | # Regular expression which should only match correct module level names 99 | const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$ 100 | 101 | # Regular expression which should only match correct class names 102 | class-rgx=[A-Z_][a-zA-Z0-9]+$ 103 | 104 | # Regular expression which should only match correct function names 105 | function-rgx=[a-z_][a-z0-9_]{2,30}$ 106 | 107 | # Regular expression which should only match correct method names 108 | method-rgx=[a-z_][a-z0-9_]{2,30}$ 109 | 110 | # Regular expression which should only match correct instance attribute names 111 | attr-rgx=[a-z_][a-z0-9_]{2,30}$ 112 | 113 | # Regular expression which should only match correct argument names 114 | argument-rgx=[a-z_][a-z0-9_]{2,30}$ 115 | 116 | # Regular expression which should only match correct variable names 117 | variable-rgx=[a-z_][a-z0-9_]{2,30}$ 118 | 119 | # Regular expression which should only match correct list comprehension / 120 | # generator expression variable names 121 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 122 | 123 | # Good variable names which should always be accepted, separated by a comma 124 | good-names=i,j,k,ex,Run,_ 125 | 126 | # Bad variable names which should always be refused, separated by a comma 127 | bad-names=foo,bar,baz,toto,tutu,tata 128 | 129 | # Regular expression which should only match functions or classes name which do 130 | # not require a docstring 131 | no-docstring-rgx=__.*__ 132 | 133 | 134 | [MISCELLANEOUS] 135 | 136 | # List of note tags to take in consideration, separated by a comma. 137 | notes=FIXME,XXX,TODO 138 | 139 | 140 | [VARIABLES] 141 | 142 | # Tells whether we should check for unused import in __init__ files. 143 | init-import=no 144 | 145 | # A regular expression matching the beginning of the name of dummy variables 146 | # (i.e. not used). 147 | dummy-variables-rgx=_|dummy 148 | 149 | # List of additional names supposed to be defined in builtins. Remember that 150 | # you should avoid to define new builtins when possible. 151 | additional-builtins= 152 | 153 | 154 | [SIMILARITIES] 155 | 156 | # Minimum lines number of a similarity. 157 | min-similarity-lines=4 158 | 159 | # Ignore comments when computing similarities. 160 | ignore-comments=yes 161 | 162 | # Ignore docstrings when computing similarities. 163 | ignore-docstrings=yes 164 | 165 | 166 | [FORMAT] 167 | 168 | # Maximum number of characters on a single line. 169 | max-line-length=800 170 | 171 | # Maximum number of lines in a module 172 | max-module-lines=1000 173 | 174 | 175 | [CLASSES] 176 | 177 | # List of interface methods to ignore, separated by a comma. This is used for 178 | # instance to not check methods defines in Zope's Interface base class. 179 | ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by 180 | 181 | # List of method names used to declare (i.e. assign) instance attributes. 182 | defining-attr-methods=__init__,__new__,setUp 183 | 184 | 185 | [IMPORTS] 186 | 187 | # Deprecated modules which should not be used, separated by a comma 188 | deprecated-modules=regsub,string,TERMIOS,Bastion,rexec 189 | 190 | # Create a graph of every (i.e. internal and external) dependencies in the 191 | # given file (report RP0402 must not be disabled) 192 | import-graph= 193 | 194 | # Create a graph of external dependencies in the given file (report RP0402 must 195 | # not be disabled) 196 | ext-import-graph= 197 | 198 | # Create a graph of internal dependencies in the given file (report RP0402 must 199 | # not be disabled) 200 | int-import-graph= 201 | 202 | 203 | [DESIGN] 204 | 205 | # Maximum number of arguments for function / method 206 | max-args=5 207 | 208 | # Argument names that match this expression will be ignored. Default to name 209 | # with leading underscore 210 | ignored-argument-names=_.* 211 | 212 | # Maximum number of locals for function / method body 213 | max-locals=15 214 | 215 | # Maximum number of return / yield for function / method body 216 | max-returns=6 217 | 218 | # Maximum number of branch for function / method body 219 | max-branchs=12 220 | 221 | # Maximum number of statements in function / method body 222 | max-statements=50 223 | 224 | # Maximum number of parents for a class (see R0901). 225 | max-parents=7 226 | 227 | # Maximum number of attributes for a class (see R0902). 228 | max-attributes=7 229 | 230 | # Minimum number of public methods for a class (see R0903). 231 | min-public-methods=2 232 | 233 | # Maximum number of public methods for a class (see R0904). 234 | max-public-methods=20 235 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | before_install: 4 | - sudo apt-get update && sudo apt-get --reinstall install -qq language-pack-pt 5 | 6 | python: 7 | - "2.7" 8 | - "3.4" 9 | - "3.5" 10 | - "3.6" 11 | - "3.7" 12 | - "3.8" 13 | - "3.9" 14 | - "3.10" 15 | - "3.11" 16 | - "3.12" 17 | 18 | install: 19 | - pip install coverage 20 | - pip install codecov 21 | 22 | script: 23 | - cd tests 24 | - nosetests --with-coverage . 25 | 26 | after_success: 27 | - codecov 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------- 2 | All source code is licensed under the terms of the following license: 3 | --------------------------------------------------------------------- 4 | 5 | Copyright (C) 2010,2011 Jan Christoph Ebersbach 6 | 7 | http://www.e-jc.de/ 8 | 9 | All rights reserved. 10 | 11 | The source code of this program is made available under the terms of the 12 | GNU Affero General Public License version 3 (GNU AGPL V3) as published 13 | by the Free Software Foundation. 14 | 15 | Binary versions of this program provided by Univention to you as well as 16 | other copyrighted, protected or trademarked materials like Logos, 17 | graphics, fonts, specific documentations and configurations, 18 | cryptographic keys etc. are subject to a license agreement between you 19 | and Univention and not subject to the GNU AGPL V3. 20 | 21 | In the case you use this program under the terms of the GNU AGPL V3, the 22 | program is provided in the hope that it will be useful, but WITHOUT ANY 23 | WARRANTY; without even the implied warranty of MERCHANTABILITY or 24 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public 25 | License for more details. 26 | 27 | You should have received a copy of the GNU Affero General Public License 28 | with the Debian GNU/Linux or Univention distribution in file 29 | /usr/share/common-licenses/AGPL-3; if not, see 30 | . 31 | 32 | 33 | -------------------------------------------------------------------- 34 | All documentation found in the directories doc and documentation are 35 | licensed under the terms of the following license: 36 | -------------------------------------------------------------------- 37 | 38 | doc/org.txt 39 | Copyright (C) 2010,2011 Jan Christoph Ebersbach 40 | 41 | doc/orgguide.txt 42 | documentation/emacs_orgguide.org 43 | documentation/emacs_orgguide.texi 44 | Copyright (C) 2010 Free Software Foundation 45 | 46 | Permission is granted to copy, distribute and/or modify this document 47 | under the terms of the GNU Free Documentation License, Version 1.3 or 48 | any later version published by the Free Software Foundation; with no 49 | Invariant Sections, with the Front-Cover texts being “A GNU Manual,” and 50 | with the Back-Cover Texts as in (a) below. A copy of the license is 51 | included in the section entitled “GNU Free Documentation License.” 52 | 53 | (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and 54 | modify this GNU manual. Buying copies from the FSF supports it in 55 | developing GNU and promoting software freedom.” 56 | 57 | This document is part of a collection distributed under the GNU Free 58 | Documentation License. If you want to distribute this document 59 | separately from the collection, you can do so by adding a copy of the 60 | license to the document, as described in section 6 of the license. 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PLUGIN = orgmode 2 | PREFIX = /usr/local 3 | VIMDIR = $(PREFIX)/share/vim 4 | 5 | all: build 6 | 7 | build: 8 | 9 | # install plugin at destination 10 | install: doc indent ftdetect ftplugin syntax 11 | for i in doc indent ftdetect ftplugin syntax; do \ 12 | find $$i -type f -name \*.txt -o -type f -name \*.cnf -o -type f -name \*.py -o -type f -name \*.vim | while read f; do \ 13 | install -m 0755 -d $(DESTDIR)$(VIMDIR)/$$(dirname "$$f"); \ 14 | install -m 0644 $$f $(DESTDIR)$(VIMDIR)/$$f; \ 15 | done; \ 16 | done 17 | 18 | # cleanup 19 | clean: documentation 20 | @find . -name \*.pyc -o -name \*.py,cover -exec rm {} \; 21 | @rm -rf ${PLUGIN}.vmb ${PLUGIN}.vmb.gz tmp files 22 | cd $< && $(MAKE) $@ 23 | 24 | # generate the vim ball package 25 | ${PLUGIN}.vmb: check build_vmb.vim clean 26 | $(MAKE) DESTDIR=$(PWD)/tmp VIMDIR= install 27 | find tmp -type f | sed -e 's/^tmp\///' > files 28 | cp build_vmb.vim tmp 29 | cd tmp && vim --cmd 'let g:plugin_name="${PLUGIN}"' -s build_vmb.vim 30 | [ -e tmp/${PLUGIN}.vba ] && mv tmp/${PLUGIN}.vba tmp/$@ || true 31 | mv tmp/$@ . 32 | 33 | ${PLUGIN}.vmb.gz: ${PLUGIN}.vmb 34 | @rm -f ${PLUGIN}.vmb.gz 35 | gzip $< 36 | 37 | vmb: ${PLUGIN}.vmb 38 | 39 | vmb.gz: ${PLUGIN}.vmb.gz 40 | 41 | ${PLUGIN}.vba: ${PLUGIN}.vmb 42 | mv $< $@ 43 | 44 | ${PLUGIN}.vba.gz: ${PLUGIN}.vba 45 | @rm -f ${PLUGIN}.vba.gz 46 | gzip $< 47 | 48 | vba: ${PLUGIN}.vba 49 | 50 | vba.gz: ${PLUGIN}.vba.gz 51 | 52 | # run unit tests 53 | test: check 54 | 55 | check: tests/run_tests.py 56 | cd tests && python2 run_tests.py 57 | 58 | # generate documentation 59 | docs: documentation 60 | cd $< && $(MAKE) 61 | 62 | # generate a test coverage report for all python files 63 | coverage: 64 | @echo ">>> Coverage depends on the package python-nose and python-coverage, make sure they are installed!" 65 | cd tests && nosetests2 --with-coverage --cover-html . 66 | 67 | # run a static code checker 68 | lint: 69 | @echo ">>> Lint depends on the package pylint make sure it's installed!" 70 | pylint --rcfile .pylintrc --disable=C0301,C0103,C0111,C0322,C0323,C0324,W0703,W0612,W0603 orgmode 71 | 72 | lintall: 73 | @echo ">>> Lint depends on the package pylint make sure it's installed!" 74 | pylint --rcfile .pylintrc orgmode 75 | 76 | # install vim-orgmode in the .vim/bundle directory for test purposes 77 | VIMPLUGINDIR = $(HOME)/.vim/bundle/orgmode 78 | 79 | installvmb: ${PLUGIN}.vmb install_vmb.vim 80 | rm -rvf ${VIMPLUGINDIR} 81 | mkdir -p "${VIMPLUGINDIR}" 82 | vim --cmd "let g:installdir='${VIMPLUGINDIR}'" -s install_vmb.vim $< 83 | @echo "Plugin was installed in ${VIMPLUGINDIR}. Make sure you are using a plugin loader like pathegon, otherwise the ${PLUGIN} might not work properly." 84 | 85 | installvba: ${PLUGIN}.vba install_vba.vim 86 | rm -rvf ${VIMPLUGINDIR} 87 | mkdir -p "${VIMPLUGINDIR}" 88 | vim --cmd "let g:installdir='${VIMPLUGINDIR}'" -s install_vba.vim $< 89 | @echo "Plugin was installed in ${VIMPLUGINDIR}. Make sure you are using a plugin loader like pathegon, otherwise the ${PLUGIN} might not work properly." 90 | 91 | .PHONY: all build test check install clean vmb vmb.gz docs installvmb 92 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * Vim-OrgMode 2 | 3 | #+ATTR_HTML: title="Join the chat at https://gitter.im/jceb/vim-orgmode" 4 | [[https://gitter.im/jceb/vim-orgmode?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge][file:https://badges.gitter.im/jceb/vim-orgmode.svg]] 5 | [[https://travis-ci.org/jceb/vim-orgmode][file:https://travis-ci.org/jceb/vim-orgmode.svg]] 6 | [[https://codecov.io/gh/jceb/vim-orgmode][file:https://codecov.io/gh/jceb/vim-orgmode/branch/master/graph/badge.svg]] 7 | 8 | Text outlining and task management for Vim based on [[http://orgmode.org/][Emacs' Org-Mode]]. 9 | 10 | The idea for this plugin was born by listening to the 11 | [[http://twit.tv/floss136][Floss Weekly podcast]] introducing Emacs Org-Mode. 12 | Org-Mode has a lot of strong features like folding, views (sparse tree) and 13 | scheduling of tasks. These are completed by hyperlinks, tags, todo states, 14 | priorities aso. 15 | 16 | vim-orgmode aims at providing the same functionality for Vim. 17 | 18 | [[https://github.com/jceb/vim-orgmode/blob/master/examples/mylife.org][file:examples/mylife.gif]] 19 | 20 | ** Features 21 | Currently vim-orgmode does not support all orgmode features but is quite 22 | usable. Short list of the already supported features: 23 | 24 | - Syntax highlighting 25 | - Cycle visibility of headings (folding) 26 | - Navigate between headings 27 | - Edit the structure of the document: add, move, promote, denote headings 28 | and more 29 | - Hyperlinks within vim-orgmode and outside (files, webpages, etc.) 30 | - TODO list management 31 | - Tags for headings 32 | - Lists in alphanumeric and bullet item notation and checkbox support 33 | - Basic date handling 34 | - Export to other formats (via Emacs' Org-Mode) 35 | 36 | * Installation and Usage 37 | Installation and usage instructions are found in the file [[doc/orgguide.txt][doc/orgguide.txt]]. 38 | 39 | * License 40 | Information about the license is found in file [[LICENSE]]. 41 | 42 | * Changelog 43 | All changes are found in file [[https://github.com/jceb/vim-orgmode/blob/master/CHANGELOG.org][CHANGELOG.org]] 44 | -------------------------------------------------------------------------------- /examples/mylife.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jceb/vim-orgmode/83982349e45e6d27d186ad82050f86c3233a16f0/examples/mylife.gif -------------------------------------------------------------------------------- /examples/mylife.org: -------------------------------------------------------------------------------- 1 | * My Life in plain text 2 | - [X] birth 3 | - [-] life [50%] 4 | - [X] use vim 5 | - [ ] get everything else done 6 | * Write minutes of last meeting <2014-08-08 Fri> :work: 7 | ** DONE John said 8 | this 9 | ** TODO Mary said 10 | that 11 | ** WAITING What did Mark say? 12 | [[http://example.com/here/is/the/recording][1st recording]] 13 | [[http://example.com/here/is/the/recording][2nd recording]] 14 | * Some folding headline 1 :one: 15 | ** Folded 16 | *** Even more folded 17 | * Some folding headline 2 18 | ** Folded :two: 19 | *** Even more folded 20 | * Some folding headline 3 21 | ** Folded 22 | *** Even more folded :three: 23 | * Some folding headline 4 24 | ** Folded 25 | *** Even more folded 26 | completely unfolded 27 | -------------------------------------------------------------------------------- /examples/mylife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jceb/vim-orgmode/83982349e45e6d27d186ad82050f86c3233a16f0/examples/mylife.png -------------------------------------------------------------------------------- /examples/plugins/PluginExample.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from orgmode import echo, echom, echoe, ORGMODE, apply_count, repeat 4 | from orgmode.menu import Submenu, Separator, ActionEntry 5 | from orgmode.keybinding import Keybinding, Plug, Command 6 | 7 | import vim 8 | 9 | 10 | class Example(object): 11 | u""" 12 | Example plugin. 13 | 14 | TODO: Extend this doc! 15 | """ 16 | 17 | def __init__(self): 18 | u""" Initialize plugin """ 19 | object.__init__(self) 20 | # menu entries this plugin should create 21 | self.menu = ORGMODE.orgmenu + Submenu(u'Example') 22 | 23 | # key bindings for this plugin 24 | # key bindings are also registered through the menu so only additional 25 | # bindings should be put in this variable 26 | self.keybindings = [] 27 | 28 | # commands for this plugin 29 | self.commands = [] 30 | 31 | @classmethod 32 | def action(cls): 33 | u""" 34 | Some kind of action. 35 | 36 | :returns: TODO 37 | """ 38 | pass 39 | 40 | def register(self): 41 | u""" 42 | Registration of the plugin. 43 | 44 | Key bindings and other initialization should be done here. 45 | """ 46 | # an Action menu entry which binds "keybinding" to action ":action" 47 | self.commands.append(Command(u'OrgActionCommand', 48 | u':py ORGMODE.plugins["Example"].action()')) 49 | self.keybindings.append(Keybinding(u'keybinding', 50 | Plug(u'OrgAction', self.commands[-1]))) 51 | self.menu + ActionEntry(u'&Action', self.keybindings[-1]) 52 | -------------------------------------------------------------------------------- /ftdetect/org.vim: -------------------------------------------------------------------------------- 1 | autocmd BufNewFile,BufRead *.org setfiletype org 2 | "autocmd BufNewFile,BufReadPost org:todo* setfiletype orgtodo 3 | -------------------------------------------------------------------------------- /ftplugin/org.cnf: -------------------------------------------------------------------------------- 1 | --langdef=org 2 | --langmap=org:.org 3 | --regex-org=/^(\*+)[[:space:]]+(.*)([[:space:]]+:[^\t ]*:)?$/\1 \2/s,sections/ 4 | --regex-org=/\[\[([^][]+)\]\]/\1/h,hyperlinks/ 5 | --regex-org=/\[\[[^][]+\]\[([^][]+)\]\]/\1/h,hyperlinks/ 6 | -------------------------------------------------------------------------------- /ftplugin/org.vim: -------------------------------------------------------------------------------- 1 | " org.vim -- Text outlining and task management for Vim based on Emacs' Org-Mode 2 | " @Author : Jan Christoph Ebersbach (jceb@e-jc.de) 3 | " @License : AGPL3 (see http://www.gnu.org/licenses/agpl.txt) 4 | " @Created : 2010-10-03 5 | " @Last Modified: Tue 13. Sep 2011 20:52:57 +0200 CEST 6 | " @Revision : 0.4 7 | " vi: ft=vim:tw=80:sw=4:ts=4:fdm=marker 8 | 9 | if v:version > 702 10 | if has('python3') 11 | let s:py_version = 'python3 ' 12 | let s:py_env = 'python3 << EOF' 13 | elseif has('python') 14 | let s:py_version = 'python ' 15 | let s:py_env = 'python << EOF' 16 | else 17 | echoerr "Unable to start orgmode. Orgmode depends on Vim >= 7.3 with Python support complied in." 18 | finish 19 | endif 20 | else 21 | echoerr "Unable to start orgmode. Orgmode depends on Vim >= 7.3 with Python support complied in." 22 | finish 23 | endif 24 | 25 | " Init buffer for file {{{1 26 | if ! exists('b:did_ftplugin') 27 | " default emacs settings 28 | setlocal comments=fb:*,b:#,fb:- 29 | setlocal commentstring=#\ %s 30 | setlocal conceallevel=2 concealcursor=nc 31 | " original emacs settings are: setlocal tabstop=6 shiftwidth=6, but because 32 | " of checkbox indentation the following settings are used: 33 | setlocal tabstop=6 shiftwidth=6 34 | if exists('g:org_tag_column') 35 | exe 'setlocal textwidth='.g:org_tag_column 36 | else 37 | setlocal textwidth=77 38 | endif 39 | 40 | " expand tab for counting level of checkbox 41 | setlocal expandtab 42 | 43 | " enable % for angle brackets < > 44 | setlocal matchpairs+=<:> 45 | 46 | " register keybindings if they don't have been registered before 47 | if exists("g:loaded_org") 48 | exe s:py_version . 'ORGMODE.register_keybindings()' 49 | endif 50 | endif 51 | 52 | " Load orgmode just once {{{1 53 | if &cp || exists("g:loaded_org") 54 | finish 55 | endif 56 | let g:loaded_org = 1 57 | 58 | " Default org plugins that will be loaded (in the given order) {{{2 59 | if ! exists('g:org_plugins') && ! exists('b:org_plugins') 60 | let g:org_plugins = ['ShowHide', '|', 'Navigator', 'EditStructure', 'EditCheckbox', '|', 'Hyperlinks', '|', 'Todo', 'TagsProperties', 'Date', 'Agenda', 'Misc', '|', 'Export'] 61 | endif 62 | 63 | " Default org plugin settings {{{2 64 | " What does this do? 65 | if ! exists('g:org_syntax_highlight_leading_stars') && ! exists('b:org_syntax_highlight_leading_stars') 66 | let g:org_syntax_highlight_leading_stars = 1 67 | endif 68 | 69 | " setting to conceal aggresively 70 | if ! exists('g:org_aggressive_conceal') && ! exists('b:org_aggressive_conceal') 71 | let g:org_aggressive_conceal = 0 72 | endif 73 | 74 | " Defined in separate plugins 75 | " Adding Behavior preference: 76 | " 1: go into insert-mode when new heading/checkbox/plainlist added 77 | " 0: retain original mode when new heading/checkbox/plainlist added 78 | if ! exists('g:org_prefer_insert_mode') && ! exists('b:org_prefer_insert_mode') 79 | let g:org_prefer_insert_mode = 1 80 | endif 81 | 82 | " Menu and document handling {{{1 83 | function! OrgRegisterMenu() 84 | exe s:py_version . 'ORGMODE.register_menu()' 85 | endfunction 86 | 87 | function! OrgUnregisterMenu() 88 | exe s:py_version . 'ORGMODE.unregister_menu()' 89 | endfunction 90 | 91 | function! OrgDeleteUnusedDocument(bufnr) 92 | exe s:py_env 93 | b = int(vim.eval('a:bufnr')) 94 | if b in ORGMODE._documents: 95 | del ORGMODE._documents[b] 96 | EOF 97 | endfunction 98 | 99 | " show and hide Org menu depending on the filetype 100 | augroup orgmode 101 | au BufEnter * :if &filetype == "org" | call OrgRegisterMenu() | endif 102 | au BufLeave * :if &filetype == "org" | call OrgUnregisterMenu() | endif 103 | au BufDelete * :call OrgDeleteUnusedDocument(expand('')) 104 | augroup END 105 | 106 | " Start orgmode {{{1 107 | " Expand our path 108 | exec s:py_env 109 | import glob, vim, os, sys 110 | 111 | for p in vim.eval("&runtimepath").split(','): 112 | dname = os.path.join(p, "ftplugin") 113 | matches = glob.glob(dname) 114 | for match in matches: 115 | if os.path.exists(os.path.join(match, "orgmode")): 116 | if match not in sys.path: 117 | sys.path.append(match) 118 | break 119 | 120 | from orgmode._vim import ORGMODE, insert_at_cursor, get_user_input, date_to_str 121 | ORGMODE.start() 122 | 123 | import datetime 124 | EOF 125 | 126 | " 3rd Party Plugin Integration {{{1 127 | " * Repeat {{{2 128 | try 129 | call repeat#set() 130 | catch 131 | endtry 132 | 133 | " * Tagbar {{{2 134 | let g:tagbar_type_org = { 135 | \ 'ctagstype' : 'org', 136 | \ 'kinds' : [ 137 | \ 's:sections', 138 | \ 'h:hyperlinks', 139 | \ ], 140 | \ 'sort' : 0, 141 | \ 'deffile' : expand(':p:h') . '/org.cnf' 142 | \ } 143 | 144 | " * Taglist {{{2 145 | if exists('g:Tlist_Ctags_Cmd') 146 | " Pass parameters to taglist 147 | let g:tlist_org_settings = 'org;s:section;h:hyperlinks' 148 | let g:Tlist_Ctags_Cmd .= ' --options=' . expand(':p:h') . '/org.cnf ' 149 | endif 150 | 151 | " * Calendar.vim {{{2 152 | fun CalendarAction(day, month, year, week, dir) 153 | exe s:py_version . "selected_date = " . printf("datetime.date(%d, %d, %d)", a:year, a:month, a:day) 154 | exe s:py_version . "org_timestamp = '" . g:org_timestamp_template . "' % date_to_str(selected_date)" 155 | 156 | " get_user_input 157 | exe s:py_version . "modifier = get_user_input(org_timestamp)" 158 | " change date according to user input 159 | exe s:py_version . "newdate = Date._modify_time(selected_date, modifier)" 160 | exe s:py_version . "newdate = date_to_str(newdate)" 161 | " close Calendar 162 | exe "q" 163 | " goto previous window 164 | exe "wincmd p" 165 | exe s:py_version . "timestamp = '" . g:org_timestamp_template . "' % newdate" 166 | exe s:py_version . "if modifier != None: insert_at_cursor(timestamp)" 167 | " restore calendar_action 168 | let g:calendar_action = g:org_calendar_action_backup 169 | endf 170 | -------------------------------------------------------------------------------- /ftplugin/orgmode/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " epub3 to make an epub3" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | @echo " dummy to check syntax errors of document sources" 51 | 52 | .PHONY: clean 53 | clean: 54 | rm -rf $(BUILDDIR)/* 55 | 56 | .PHONY: html 57 | html: 58 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 61 | 62 | .PHONY: dirhtml 63 | dirhtml: 64 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 65 | @echo 66 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 67 | 68 | .PHONY: singlehtml 69 | singlehtml: 70 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 71 | @echo 72 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 73 | 74 | .PHONY: pickle 75 | pickle: 76 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 77 | @echo 78 | @echo "Build finished; now you can process the pickle files." 79 | 80 | .PHONY: json 81 | json: 82 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 83 | @echo 84 | @echo "Build finished; now you can process the JSON files." 85 | 86 | .PHONY: htmlhelp 87 | htmlhelp: 88 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 89 | @echo 90 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 91 | ".hhp project file in $(BUILDDIR)/htmlhelp." 92 | 93 | .PHONY: qthelp 94 | qthelp: 95 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 96 | @echo 97 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 98 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 99 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/orgmode.qhcp" 100 | @echo "To view the help file:" 101 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/orgmode.qhc" 102 | 103 | .PHONY: applehelp 104 | applehelp: 105 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 106 | @echo 107 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 108 | @echo "N.B. You won't be able to view it unless you put it in" \ 109 | "~/Library/Documentation/Help or install it in your application" \ 110 | "bundle." 111 | 112 | .PHONY: devhelp 113 | devhelp: 114 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 115 | @echo 116 | @echo "Build finished." 117 | @echo "To view the help file:" 118 | @echo "# mkdir -p $$HOME/.local/share/devhelp/orgmode" 119 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/orgmode" 120 | @echo "# devhelp" 121 | 122 | .PHONY: epub 123 | epub: 124 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 125 | @echo 126 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 127 | 128 | .PHONY: epub3 129 | epub3: 130 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 131 | @echo 132 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 133 | 134 | .PHONY: latex 135 | latex: 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo 138 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 139 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 140 | "(use \`make latexpdf' here to do that automatically)." 141 | 142 | .PHONY: latexpdf 143 | latexpdf: 144 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 145 | @echo "Running LaTeX files through pdflatex..." 146 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 147 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 148 | 149 | .PHONY: latexpdfja 150 | latexpdfja: 151 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 152 | @echo "Running LaTeX files through platex and dvipdfmx..." 153 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 154 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 155 | 156 | .PHONY: text 157 | text: 158 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 159 | @echo 160 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 161 | 162 | .PHONY: man 163 | man: 164 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 165 | @echo 166 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 167 | 168 | .PHONY: texinfo 169 | texinfo: 170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 | @echo 172 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 173 | @echo "Run \`make' in that directory to run these through makeinfo" \ 174 | "(use \`make info' here to do that automatically)." 175 | 176 | .PHONY: info 177 | info: 178 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 179 | @echo "Running Texinfo files through makeinfo..." 180 | make -C $(BUILDDIR)/texinfo info 181 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 182 | 183 | .PHONY: gettext 184 | gettext: 185 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 186 | @echo 187 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 188 | 189 | .PHONY: changes 190 | changes: 191 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 192 | @echo 193 | @echo "The overview file is in $(BUILDDIR)/changes." 194 | 195 | .PHONY: linkcheck 196 | linkcheck: 197 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 198 | @echo 199 | @echo "Link check complete; look for any errors in the above output " \ 200 | "or in $(BUILDDIR)/linkcheck/output.txt." 201 | 202 | .PHONY: doctest 203 | doctest: 204 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 205 | @echo "Testing of doctests in the sources finished, look at the " \ 206 | "results in $(BUILDDIR)/doctest/output.txt." 207 | 208 | .PHONY: coverage 209 | coverage: 210 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 211 | @echo "Testing of coverage in the sources finished, look at the " \ 212 | "results in $(BUILDDIR)/coverage/python.txt." 213 | 214 | .PHONY: xml 215 | xml: 216 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 217 | @echo 218 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 219 | 220 | .PHONY: pseudoxml 221 | pseudoxml: 222 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 223 | @echo 224 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 225 | 226 | .PHONY: dummy 227 | dummy: 228 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 229 | @echo 230 | @echo "Build finished. Dummy builder generates no files." 231 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/index.rst: -------------------------------------------------------------------------------- 1 | .. orgmode documentation master file, created by 2 | sphinx-quickstart on Sat May 21 16:35:00 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to orgmode's documentation! 7 | =================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 4 13 | 14 | orgmode 15 | 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` 23 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\orgmode.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\orgmode.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/orgmode.liborgmode.rst: -------------------------------------------------------------------------------- 1 | orgmode.liborgmode package 2 | ========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | orgmode.liborgmode.agenda module 8 | -------------------------------- 9 | 10 | .. automodule:: orgmode.liborgmode.agenda 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | orgmode.liborgmode.agendafilter module 16 | -------------------------------------- 17 | 18 | .. automodule:: orgmode.liborgmode.agendafilter 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | orgmode.liborgmode.base module 24 | ------------------------------ 25 | 26 | .. automodule:: orgmode.liborgmode.base 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | orgmode.liborgmode.checkboxes module 32 | ------------------------------------ 33 | 34 | .. automodule:: orgmode.liborgmode.checkboxes 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | orgmode.liborgmode.documents module 40 | ----------------------------------- 41 | 42 | .. automodule:: orgmode.liborgmode.documents 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | orgmode.liborgmode.dom_obj module 48 | --------------------------------- 49 | 50 | .. automodule:: orgmode.liborgmode.dom_obj 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | orgmode.liborgmode.headings module 56 | ---------------------------------- 57 | 58 | .. automodule:: orgmode.liborgmode.headings 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | orgmode.liborgmode.orgdate module 64 | --------------------------------- 65 | 66 | .. automodule:: orgmode.liborgmode.orgdate 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | 72 | Module contents 73 | --------------- 74 | 75 | .. automodule:: orgmode.liborgmode 76 | :members: 77 | :undoc-members: 78 | :show-inheritance: 79 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/orgmode.plugins.rst: -------------------------------------------------------------------------------- 1 | orgmode.plugins package 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | orgmode.plugins.Agenda module 8 | ----------------------------- 9 | 10 | .. automodule:: orgmode.plugins.Agenda 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | orgmode.plugins.Date module 16 | --------------------------- 17 | 18 | .. automodule:: orgmode.plugins.Date 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | orgmode.plugins.EditCheckbox module 24 | ----------------------------------- 25 | 26 | .. automodule:: orgmode.plugins.EditCheckbox 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | orgmode.plugins.EditStructure module 32 | ------------------------------------ 33 | 34 | .. automodule:: orgmode.plugins.EditStructure 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | orgmode.plugins.Export module 40 | ----------------------------- 41 | 42 | .. automodule:: orgmode.plugins.Export 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | orgmode.plugins.Hyperlinks module 48 | --------------------------------- 49 | 50 | .. automodule:: orgmode.plugins.Hyperlinks 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | orgmode.plugins.LoggingWork module 56 | ---------------------------------- 57 | 58 | .. automodule:: orgmode.plugins.LoggingWork 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | orgmode.plugins.Misc module 64 | --------------------------- 65 | 66 | .. automodule:: orgmode.plugins.Misc 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | orgmode.plugins.Navigator module 72 | -------------------------------- 73 | 74 | .. automodule:: orgmode.plugins.Navigator 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | orgmode.plugins.ShowHide module 80 | ------------------------------- 81 | 82 | .. automodule:: orgmode.plugins.ShowHide 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | orgmode.plugins.TagsProperties module 88 | ------------------------------------- 89 | 90 | .. automodule:: orgmode.plugins.TagsProperties 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | 95 | orgmode.plugins.Todo module 96 | --------------------------- 97 | 98 | .. automodule:: orgmode.plugins.Todo 99 | :members: 100 | :undoc-members: 101 | :show-inheritance: 102 | 103 | 104 | Module contents 105 | --------------- 106 | 107 | .. automodule:: orgmode.plugins 108 | :members: 109 | :undoc-members: 110 | :show-inheritance: 111 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/orgmode.py3compat.rst: -------------------------------------------------------------------------------- 1 | orgmode.py3compat package 2 | ========================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | orgmode.py3compat.encode_compatibility module 8 | --------------------------------------------- 9 | 10 | .. automodule:: orgmode.py3compat.encode_compatibility 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | orgmode.py3compat.py_py3_string module 16 | -------------------------------------- 17 | 18 | .. automodule:: orgmode.py3compat.py_py3_string 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | orgmode.py3compat.unicode_compatibility module 24 | ---------------------------------------------- 25 | 26 | .. automodule:: orgmode.py3compat.unicode_compatibility 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | orgmode.py3compat.xrange_compatibility module 32 | --------------------------------------------- 33 | 34 | .. automodule:: orgmode.py3compat.xrange_compatibility 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | 40 | Module contents 41 | --------------- 42 | 43 | .. automodule:: orgmode.py3compat 44 | :members: 45 | :undoc-members: 46 | :show-inheritance: 47 | -------------------------------------------------------------------------------- /ftplugin/orgmode/docs/orgmode.rst: -------------------------------------------------------------------------------- 1 | orgmode package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | orgmode.liborgmode 10 | orgmode.plugins 11 | orgmode.py3compat 12 | 13 | Submodules 14 | ---------- 15 | 16 | orgmode._vim module 17 | ------------------- 18 | 19 | .. automodule:: orgmode._vim 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | orgmode.exceptions module 25 | ------------------------- 26 | 27 | .. automodule:: orgmode.exceptions 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | 32 | orgmode.keybinding module 33 | ------------------------- 34 | 35 | .. automodule:: orgmode.keybinding 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | 40 | orgmode.menu module 41 | ------------------- 42 | 43 | .. automodule:: orgmode.menu 44 | :members: 45 | :undoc-members: 46 | :show-inheritance: 47 | 48 | orgmode.settings module 49 | ----------------------- 50 | 51 | .. automodule:: orgmode.settings 52 | :members: 53 | :undoc-members: 54 | :show-inheritance: 55 | 56 | orgmode.vimbuffer module 57 | ------------------------ 58 | 59 | .. automodule:: orgmode.vimbuffer 60 | :members: 61 | :undoc-members: 62 | :show-inheritance: 63 | 64 | 65 | Module contents 66 | --------------- 67 | 68 | .. automodule:: orgmode 69 | :members: 70 | :undoc-members: 71 | :show-inheritance: 72 | -------------------------------------------------------------------------------- /ftplugin/orgmode/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class PluginError(BaseException): 5 | def __init__(self, message): 6 | BaseException.__init__(self, message) 7 | 8 | 9 | class BufferNotFound(BaseException): 10 | def __init__(self, message): 11 | BaseException.__init__(self, message) 12 | 13 | 14 | class BufferNotInSync(BaseException): 15 | def __init__(self, message): 16 | BaseException.__init__(self, message) 17 | 18 | 19 | class HeadingDomError(BaseException): 20 | def __init__(self, message): 21 | BaseException.__init__(self, message) 22 | -------------------------------------------------------------------------------- /ftplugin/orgmode/keybinding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | MODE_ALL = u'a' 6 | MODE_NORMAL = u'n' 7 | MODE_VISUAL = u'v' 8 | MODE_INSERT = u'i' 9 | MODE_OPERATOR = u'o' 10 | 11 | OPTION_BUFFER_ONLY = u'' 12 | OPTION_SLIENT = u'' 13 | 14 | from orgmode.py3compat.encode_compatibility import * 15 | 16 | def _register(f, name): 17 | def r(*args, **kwargs): 18 | p = f(*args, **kwargs) 19 | if hasattr(p, name) and isinstance(getattr(p, name), list): 20 | for i in getattr(p, name): 21 | i.create() 22 | return p 23 | return r 24 | 25 | 26 | def register_keybindings(f): 27 | return _register(f, u'keybindings') 28 | 29 | 30 | def register_commands(f): 31 | return _register(f, u'commands') 32 | 33 | 34 | class Command(object): 35 | u""" A vim command """ 36 | 37 | def __init__(self, name, command, arguments=u'0', complete=None, overwrite_exisiting=False): 38 | u""" 39 | :name: The name of command, first character must be uppercase 40 | :command: The actual command that is executed 41 | :arguments: See :h :command-nargs, only the arguments need to be specified 42 | :complete: See :h :command-completion, only the completion arguments need to be specified 43 | """ 44 | object.__init__(self) 45 | 46 | self._name = name 47 | self._command = command 48 | self._arguments = arguments 49 | self._complete = complete 50 | self._overwrite_exisiting = overwrite_exisiting 51 | 52 | def __unicode__(self): 53 | return u':%s' % self.name 54 | 55 | def __str__(self): 56 | return u_encode(self.__unicode__()) 57 | 58 | @property 59 | def name(self): 60 | return self._name 61 | 62 | @property 63 | def command(self): 64 | return self._command 65 | 66 | @property 67 | def arguments(self): 68 | return self._arguments 69 | 70 | @property 71 | def complete(self): 72 | return self._complete 73 | 74 | @property 75 | def overwrite_exisiting(self): 76 | return self._overwrite_exisiting 77 | 78 | def create(self): 79 | u""" Register/create the command 80 | """ 81 | vim.command(u_encode(':command%(overwrite)s -nargs=%(arguments)s %(complete)s %(name)s %(command)s' % 82 | {u'overwrite': '!' if self.overwrite_exisiting else '', 83 | u'arguments': u_encode(self.arguments), 84 | u'complete': '-complete=%s' % u_encode(self.complete) if self.complete else '', 85 | u'name': self.name, 86 | u'command': self.command} 87 | )) 88 | 89 | 90 | class Plug(object): 91 | u""" Represents a to an abitrary command """ 92 | 93 | def __init__(self, name, command, mode=MODE_NORMAL): 94 | u""" 95 | :name: the name of the should be ScriptnameCommandname 96 | :command: the actual command 97 | """ 98 | object.__init__(self) 99 | 100 | if mode not in (MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT, MODE_OPERATOR): 101 | raise ValueError(u'Parameter mode not in MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT, MODE_OPERATOR') 102 | self._mode = mode 103 | 104 | self.name = name 105 | self.command = command 106 | self.created = False 107 | 108 | def __unicode__(self): 109 | return u'%s' % self.name 110 | 111 | def __str__(self): 112 | return u_encode(self.__unicode__()) 113 | 114 | def create(self): 115 | if not self.created: 116 | self.created = True 117 | cmd = self._mode 118 | if cmd == MODE_ALL: 119 | cmd = u'' 120 | vim.command(u_encode(u':%snoremap %s %s' % (cmd, str(self), self.command))) 121 | 122 | @property 123 | def mode(self): 124 | return self._mode 125 | 126 | 127 | class Keybinding(object): 128 | u""" Representation of a single key binding """ 129 | 130 | def __init__(self, key, action, mode=None, options=None, remap=True, buffer_only=True, silent=True): 131 | u""" 132 | :key: the key(s) action is bound to 133 | :action: the action triggered by key(s) 134 | :mode: definition in which vim modes the key binding is valid. Should be one of MODE_* 135 | :option: list of other options like , ... 136 | :repmap: allow or disallow nested mapping 137 | :buffer_only: define the key binding only for the current buffer 138 | """ 139 | object.__init__(self) 140 | self._key = key 141 | self._action = action 142 | 143 | # grab mode from plug if not set otherwise 144 | if isinstance(self._action, Plug) and not mode: 145 | mode = self._action.mode 146 | 147 | if mode not in (MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT, MODE_OPERATOR): 148 | raise ValueError(u'Parameter mode not in MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT, MODE_OPERATOR') 149 | self._mode = mode 150 | self._options = options 151 | if self._options is None: 152 | self._options = [] 153 | self._remap = remap 154 | self._buffer_only = buffer_only 155 | self._silent = silent 156 | 157 | if self._buffer_only and OPTION_BUFFER_ONLY not in self._options: 158 | self._options.append(OPTION_BUFFER_ONLY) 159 | 160 | if self._silent and OPTION_SLIENT not in self._options: 161 | self._options.append(OPTION_SLIENT) 162 | 163 | @property 164 | def key(self): 165 | return self._key 166 | 167 | @property 168 | def action(self): 169 | return str(self._action) 170 | 171 | @property 172 | def mode(self): 173 | return self._mode 174 | 175 | @property 176 | def options(self): 177 | return self._options[:] 178 | 179 | @property 180 | def remap(self): 181 | return self._remap 182 | 183 | @property 184 | def buffer_only(self): 185 | return self._buffer_only 186 | 187 | @property 188 | def silent(self): 189 | return self._silent 190 | 191 | def create(self): 192 | from orgmode._vim import ORGMODE, echom 193 | 194 | cmd = self._mode 195 | if cmd == MODE_ALL: 196 | cmd = u'' 197 | if not self._remap: 198 | cmd += u'nore' 199 | try: 200 | create_mapping = True 201 | if isinstance(self._action, Plug): 202 | # create plug 203 | self._action.create() 204 | if int(vim.eval(u_encode(u'hasmapto("%s")' % (self._action, )))): 205 | create_mapping = False 206 | if isinstance(self._action, Command): 207 | # create command 208 | self._action.create() 209 | 210 | if create_mapping: 211 | vim.command(u_encode(u':%smap %s %s %s' % (cmd, u' '.join(self._options), self._key, self._action))) 212 | except BaseException as e: 213 | if ORGMODE.debug: 214 | echom(u'Failed to register key binding %s %s' % (self._key, self._action)) 215 | -------------------------------------------------------------------------------- /ftplugin/orgmode/liborgmode/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /ftplugin/orgmode/liborgmode/agenda.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | u""" 4 | Agenda 5 | ~~~~~~~~~~~~~~~~~~ 6 | 7 | The agenda is one of the main concepts of orgmode. It allows to 8 | collect TODO items from multiple org documents in an agenda view. 9 | 10 | Features: 11 | * filtering 12 | * sorting 13 | """ 14 | 15 | from orgmode.liborgmode.agendafilter import filter_items 16 | from orgmode.liborgmode.agendafilter import is_within_week_and_active_todo 17 | from orgmode.liborgmode.agendafilter import contains_active_todo 18 | from orgmode.liborgmode.agendafilter import contains_active_date 19 | 20 | 21 | class AgendaManager(object): 22 | u"""Simple parsing of Documents to create an agenda.""" 23 | # TODO Move filters in this file, they do the same thing 24 | 25 | def __init__(self): 26 | super(AgendaManager, self).__init__() 27 | 28 | def get_todo(self, documents): 29 | u""" 30 | Get the todo agenda for the given documents (list of document). 31 | """ 32 | filtered = [] 33 | for document in iter(documents): 34 | # filter and return headings 35 | filtered.extend(filter_items(document.all_headings(), 36 | [contains_active_todo])) 37 | return sorted(filtered) 38 | 39 | def get_next_week_and_active_todo(self, documents): 40 | u""" 41 | Get the agenda for next week for the given documents (list of 42 | document). 43 | """ 44 | filtered = [] 45 | for document in iter(documents): 46 | # filter and return headings 47 | filtered.extend(filter_items(document.all_headings(), 48 | [is_within_week_and_active_todo])) 49 | return sorted(filtered) 50 | 51 | def get_timestamped_items(self, documents): 52 | u""" 53 | Get all time-stamped items in a time-sorted way for the given 54 | documents (list of document). 55 | """ 56 | filtered = [] 57 | for document in iter(documents): 58 | # filter and return headings 59 | filtered.extend(filter_items(document.all_headings(), 60 | [contains_active_date])) 61 | return sorted(filtered) 62 | -------------------------------------------------------------------------------- /ftplugin/orgmode/liborgmode/agendafilter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | u""" 4 | agendafilter 5 | ~~~~~~~~~~~~~~~~ 6 | 7 | AgendaFilter contains all the filters that can be applied to create the 8 | agenda. 9 | 10 | 11 | All functions except filter_items() in the module are filters. Given a 12 | heading they return if the heading meets the criteria of the filter. 13 | 14 | The function filter_items() can combine different filters and only returns 15 | the filtered headings. 16 | """ 17 | from datetime import datetime 18 | from datetime import timedelta 19 | 20 | try: 21 | from itertools import ifilter as filter 22 | except: 23 | pass 24 | 25 | 26 | def filter_items(headings, filters): 27 | u""" Filter the given headings. 28 | 29 | Args: 30 | headings (list): Contains headings 31 | filters (list): Filters that will be applied. All functions in 32 | this module (except this function) are filters. 33 | 34 | Returns: 35 | filter iterator: Headings which were not filtered. 36 | 37 | Examples: 38 | >>> filtered = filter_items(headings, [contains_active_date, 39 | contains_active_todo]) 40 | """ 41 | filtered = headings 42 | for f in filters: 43 | filtered = filter(f, filtered) 44 | return filtered 45 | 46 | 47 | def is_within_week(heading): 48 | u""" Test if headings date is within a week 49 | 50 | Returns: 51 | bool: True if the date in the deading is within a week in the future (or 52 | older False otherwise. 53 | """ 54 | if contains_active_date(heading): 55 | next_week = datetime.today() + timedelta(days=7) 56 | if heading.active_date < next_week: 57 | return True 58 | 59 | 60 | def is_within_week_and_active_todo(heading): 61 | u""" 62 | Returns: 63 | bool: True if heading contains an active TODO and the date is within a 64 | week. 65 | """ 66 | return is_within_week(heading) and contains_active_todo(heading) 67 | 68 | 69 | def contains_active_todo(heading): 70 | u""" 71 | 72 | Returns: 73 | bool: True if heading contains an active TODO. 74 | """ 75 | # TODO make this more efficient by checking some val and not calling the 76 | # function 77 | # TODO why is this import failing at top level? circular dependency... 78 | from orgmode._vim import ORGMODE 79 | active = [] 80 | for act in ORGMODE.get_document().get_todo_states(): 81 | active.extend(act[0]) 82 | return heading.todo in active 83 | 84 | 85 | def contains_active_date(heading): 86 | u""" 87 | 88 | Returns: 89 | bool: True if heading contains an active date. 90 | """ 91 | return not(heading.active_date is None) 92 | -------------------------------------------------------------------------------- /ftplugin/orgmode/liborgmode/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | base 5 | ~~~~~~~~~~ 6 | 7 | Here are some really basic data structures that are used throughout 8 | the liborgmode. 9 | """ 10 | 11 | try: 12 | from collections import UserList 13 | except: 14 | from UserList import UserList 15 | 16 | try: 17 | from collections.abc import Iterable 18 | except ImportError: 19 | # preserve compatibility with python < 3.10 20 | from collections import Iterable 21 | 22 | import sys 23 | from orgmode.py3compat.unicode_compatibility import * 24 | 25 | 26 | def flatten_list(lst): 27 | """ Flattens a list 28 | 29 | Args: 30 | lst (iterable): An iterable that will is non-flat 31 | 32 | Returns: 33 | list: Flat list 34 | """ 35 | # TODO write tests 36 | def gen_lst(item): 37 | if isinstance(item, basestring) or isinstance(item, bytes): 38 | yield item 39 | elif isinstance(item, Iterable): 40 | # yield from would be so nice... but c'est la vie 41 | for val in item: 42 | for final in gen_lst(val): 43 | yield final 44 | else: 45 | yield item 46 | return [i for i in gen_lst(lst)] 47 | 48 | 49 | class Direction(): 50 | u""" 51 | Direction is used to indicate the direction of certain actions. 52 | 53 | Example: it defines the direction headings get parted in. 54 | """ 55 | FORWARD = 1 56 | BACKWARD = 2 57 | 58 | 59 | class MultiPurposeList(UserList): 60 | u""" 61 | A Multi Purpose List is a list that calls a user defined hook on 62 | change. The implementation is very basic - the hook is called without any 63 | parameters. Otherwise the Multi Purpose List can be used like any other 64 | list. 65 | 66 | The member element "data" can be used to fill the list without causing the 67 | list to be marked dirty. This should only be used during initialization! 68 | """ 69 | 70 | def __init__(self, initlist=None, on_change=None): 71 | UserList.__init__(self, initlist) 72 | self._on_change = on_change 73 | 74 | def _changed(self): 75 | u""" Call hook """ 76 | if callable(self._on_change): 77 | self._on_change() 78 | 79 | def __setitem__(self, i, item): 80 | if sys.version_info < (3, ) and isinstance(i, slice): 81 | start, stop, _ = i.indices(len(self)) 82 | UserList.__setslice__(self, start, stop, item) 83 | else: 84 | UserList.__setitem__(self, i, item) 85 | self._changed() 86 | 87 | def __delitem__(self, i): 88 | if sys.version_info < (3, ) and isinstance(i, slice): 89 | start, stop, _ = i.indices(len(self)) 90 | UserList.__delslice__(self, start, stop) 91 | else: 92 | UserList.__delitem__(self, i) 93 | self._changed() 94 | 95 | def __getitem__(self, i): 96 | if sys.version_info < (3, ): 97 | if isinstance(i, slice): 98 | # TODO Return just a list. Why? 99 | return [self[i] for i in range(*i.indices(len(self)))] 100 | # return UserList([self[i] for i in range(*i.indices(len(self)))]) 101 | return UserList.__getitem__(self, i) 102 | 103 | # NOTE: These wrappers are necessary because of python 2 104 | def __setslice__(self, i, j, other): 105 | self.__setitem__(slice(i, j), other) 106 | 107 | def __delslice__(self, i, j): 108 | self.__delitem__(slice(i, j)) 109 | 110 | def __getslice__(self, i, j): 111 | return self.__getitem__(slice(i, j)) 112 | 113 | def __iadd__(self, other): 114 | res = UserList.__iadd__(self, other) 115 | self._changed() 116 | return res 117 | 118 | def __imul__(self, n): 119 | res = UserList.__imul__(self, n) 120 | self._changed() 121 | return res 122 | 123 | def append(self, item): 124 | UserList.append(self, item) 125 | self._changed() 126 | 127 | def insert(self, i, item): 128 | UserList.insert(self, i, item) 129 | self._changed() 130 | 131 | def pop(self, i=-1): 132 | item = self[i] 133 | del self[i] 134 | return item 135 | 136 | def remove(self, item): 137 | self.__delitem__(self.index(item)) 138 | 139 | def reverse(self): 140 | UserList.reverse(self) 141 | self._changed() 142 | 143 | def sort(self, *args, **kwds): 144 | UserList.sort(self, *args, **kwds) 145 | self._changed() 146 | 147 | def extend(self, other): 148 | UserList.extend(self, other) 149 | self._changed() 150 | 151 | 152 | def get_domobj_range(content=[], position=0, direction=Direction.FORWARD, identify_fun=None): 153 | u""" 154 | Get the start and end line number of the dom obj lines from content. 155 | 156 | :content: String to be recognized dom obj 157 | :position: Line number in content 158 | :direction: Search direction 159 | :identify_fun: A identify function to recognize dom obj(Heading, Checkbox) title string. 160 | 161 | :return: Start and end line number for the recognized dom obj. 162 | """ 163 | len_cb = len(content) 164 | 165 | if position < 0 or position > len_cb: 166 | return (None, None) 167 | 168 | tmp_line = position 169 | start = None 170 | end = None 171 | 172 | if direction == Direction.FORWARD: 173 | while tmp_line < len_cb: 174 | if identify_fun(content[tmp_line]) is not None: 175 | if start is None: 176 | start = tmp_line 177 | elif end is None: 178 | end = tmp_line - 1 179 | if start is not None and end is not None: 180 | break 181 | tmp_line += 1 182 | else: 183 | while tmp_line >= 0 and tmp_line < len_cb: 184 | if identify_fun(content[tmp_line]) is not None: 185 | if start is None: 186 | start = tmp_line 187 | elif end is None: 188 | end = tmp_line - 1 189 | if start is not None and end is not None: 190 | break 191 | tmp_line -= 1 if start is None else -1 192 | 193 | return (start, end) 194 | -------------------------------------------------------------------------------- /ftplugin/orgmode/liborgmode/orgdate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | u""" 3 | OrgDate 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | This module contains all date/time/timerange representations that exist in 7 | orgmode. 8 | 9 | There exist three different kinds: 10 | 11 | * OrgDate: is similar to a date object in python and it looks like 12 | '2011-09-07 Wed'. 13 | 14 | * OrgDateTime: is similar to a datetime object in python and looks like 15 | '2011-09-07 Wed 10:30' 16 | 17 | * OrgTimeRange: indicates a range of time. It has a start and and end date: 18 | * <2011-09-07 Wed>--<2011-09-08 Fri> 19 | * <2011-09-07 Wed 10:00-13:00> 20 | 21 | All OrgTime oblects can be active or inactive. 22 | """ 23 | 24 | import datetime 25 | import re 26 | 27 | from orgmode.py3compat.encode_compatibility import * 28 | 29 | # <2011-09-12 Mon> 30 | _DATE_REGEX = re.compile(r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w>", re.UNICODE) 31 | # [2011-09-12 Mon] 32 | _DATE_PASSIVE_REGEX = re.compile(r"\[(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w\]", re.UNICODE) 33 | 34 | # <2011-09-12 Mon 10:20> 35 | _DATETIME_REGEX = re.compile( 36 | r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w (\d{1,2}):(\d\d)>", re.UNICODE) 37 | # [2011-09-12 Mon 10:20] 38 | _DATETIME_PASSIVE_REGEX = re.compile( 39 | r"\[(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w (\d{1,2}):(\d\d)\]", re.UNICODE) 40 | 41 | # <2011-09-12 Mon>--<2011-09-13 Tue> 42 | _DATERANGE_REGEX = re.compile( 43 | # <2011-09-12 Mon>-- 44 | r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w>--" 45 | # <2011-09-13 Tue> 46 | r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w>", re.UNICODE) 47 | # <2011-09-12 Mon 10:00>--<2011-09-12 Mon 11:00> 48 | _DATETIMERANGE_REGEX = re.compile( 49 | # <2011-09-12 Mon 10:00>-- 50 | r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w (\d\d):(\d\d)>--" 51 | # <2011-09-12 Mon 11:00> 52 | r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w (\d\d):(\d\d)>", re.UNICODE) 53 | # <2011-09-12 Mon 10:00--12:00> 54 | _DATETIMERANGE_SAME_DAY_REGEX = re.compile( 55 | r"<(\d\d\d\d)-(\d\d)-(\d\d) [A-Z]\w\w (\d\d):(\d\d)-(\d\d):(\d\d)>", re.UNICODE) 56 | 57 | 58 | def get_orgdate(data): 59 | u""" 60 | Parse the given data (can be a string or list). Return an OrgDate if data 61 | contains a string representation of an OrgDate; otherwise return None. 62 | 63 | data can be a string or a list containing strings. 64 | """ 65 | # TODO maybe it should be checked just for iterable? Does it affect here if 66 | # in base __getitem__(slice(i,j)) doesn't return a list but userlist... 67 | if isinstance(data, list): 68 | return _findfirst(_text2orgdate, data) 69 | else: 70 | return _text2orgdate(data) 71 | # if no dates found 72 | return None 73 | 74 | 75 | def _findfirst(f, seq): 76 | u""" 77 | Return first item in sequence seq where f(item) == True. 78 | 79 | TODO: this is a general help function and it should be moved somewhere 80 | else; preferably into the standard lib :) 81 | """ 82 | for found in (f(item) for item in seq if f(item)): 83 | return found 84 | 85 | 86 | def _text2orgdate(string): 87 | u""" 88 | Transform the given string into an OrgDate. 89 | Return an OrgDate if data contains a string representation of an OrgDate; 90 | otherwise return None. 91 | """ 92 | # handle active datetime with same day 93 | result = _DATETIMERANGE_SAME_DAY_REGEX.search(string) 94 | if result: 95 | try: 96 | (syear, smonth, sday, shour, smin, ehour, emin) = \ 97 | [int(m) for m in result.groups()] 98 | start = datetime.datetime(syear, smonth, sday, shour, smin) 99 | end = datetime.datetime(syear, smonth, sday, ehour, emin) 100 | return OrgTimeRange(True, start, end) 101 | except BaseException: 102 | return None 103 | 104 | # handle active datetime 105 | result = _DATETIMERANGE_REGEX.search(string) 106 | if result: 107 | try: 108 | tmp = [int(m) for m in result.groups()] 109 | (syear, smonth, sday, shour, smin, eyear, emonth, eday, ehour, emin) = tmp 110 | start = datetime.datetime(syear, smonth, sday, shour, smin) 111 | end = datetime.datetime(eyear, emonth, eday, ehour, emin) 112 | return OrgTimeRange(True, start, end) 113 | except BaseException: 114 | return None 115 | 116 | # handle active datetime 117 | result = _DATERANGE_REGEX.search(string) 118 | if result: 119 | try: 120 | tmp = [int(m) for m in result.groups()] 121 | syear, smonth, sday, eyear, emonth, ehour = tmp 122 | start = datetime.date(syear, smonth, sday) 123 | end = datetime.date(eyear, emonth, ehour) 124 | return OrgTimeRange(True, start, end) 125 | except BaseException: 126 | return None 127 | 128 | # handle active datetime 129 | result = _DATETIME_REGEX.search(string) 130 | if result: 131 | try: 132 | year, month, day, hour, minutes = [int(m) for m in result.groups()] 133 | return OrgDateTime(True, year, month, day, hour, minutes) 134 | except BaseException: 135 | return None 136 | 137 | # handle passive datetime 138 | result = _DATETIME_PASSIVE_REGEX.search(string) 139 | if result: 140 | try: 141 | year, month, day, hour, minutes = [int(m) for m in result.groups()] 142 | return OrgDateTime(False, year, month, day, hour, minutes) 143 | except BaseException: 144 | return None 145 | 146 | # handle passive dates 147 | result = _DATE_PASSIVE_REGEX.search(string) 148 | if result: 149 | try: 150 | year, month, day = [int(m) for m in result.groups()] 151 | return OrgDate(False, year, month, day) 152 | except BaseException: 153 | return None 154 | 155 | # handle active dates 156 | result = _DATE_REGEX.search(string) 157 | if result: 158 | try: 159 | year, month, day = [int(m) for m in result.groups()] 160 | return OrgDate(True, year, month, day) 161 | except BaseException: 162 | return None 163 | 164 | 165 | class OrgDate(datetime.date): 166 | u""" 167 | OrgDate represents a normal date like '2011-08-29 Mon'. 168 | 169 | OrgDates can be active or inactive. 170 | 171 | NOTE: date is immutable. That's why there needs to be __new__(). 172 | See: http://docs.python.org/reference/datamodel.html#object.__new__ 173 | """ 174 | def __init__(self, active, year, month, day): 175 | self.active = active 176 | pass 177 | 178 | def __new__(cls, active, year, month, day): 179 | return datetime.date.__new__(cls, year, month, day) 180 | 181 | def __unicode__(self): 182 | u""" 183 | Return a string representation. 184 | """ 185 | if self.active: 186 | return self.strftime(u'<%Y-%m-%d %a>') 187 | else: 188 | return self.strftime(u'[%Y-%m-%d %a]') 189 | 190 | def __str__(self): 191 | return u_encode(self.__unicode__()) 192 | 193 | def strftime(self, fmt): 194 | return u_decode(datetime.date.strftime(self, u_encode(fmt))) 195 | 196 | 197 | class OrgDateTime(datetime.datetime): 198 | u""" 199 | OrgDateTime represents a normal date like '2011-08-29 Mon'. 200 | 201 | OrgDateTime can be active or inactive. 202 | 203 | NOTE: date is immutable. That's why there needs to be __new__(). 204 | See: http://docs.python.org/reference/datamodel.html#object.__new__ 205 | """ 206 | 207 | def __init__(self, active, year, month, day, hour, mins): 208 | self.active = active 209 | 210 | def __new__(cls, active, year, month, day, hour, minute): 211 | return datetime.datetime.__new__(cls, year, month, day, hour, minute) 212 | 213 | def __unicode__(self): 214 | u""" 215 | Return a string representation. 216 | """ 217 | if self.active: 218 | return self.strftime(u'<%Y-%m-%d %a %H:%M>') 219 | else: 220 | return self.strftime(u'[%Y-%m-%d %a %H:%M]') 221 | 222 | def __str__(self): 223 | return u_encode(self.__unicode__()) 224 | 225 | def strftime(self, fmt): 226 | return u_decode(datetime.datetime.strftime(self, u_encode(fmt))) 227 | 228 | 229 | class OrgTimeRange(object): 230 | u""" 231 | OrgTimeRange objects have a start and an end. Start and ent can be date 232 | or datetime. Start and end have to be the same type. 233 | 234 | OrgTimeRange objects look like this: 235 | * <2011-09-07 Wed>--<2011-09-08 Fri> 236 | * <2011-09-07 Wed 20:00>--<2011-09-08 Fri 10:00> 237 | * <2011-09-07 Wed 10:00-13:00> 238 | """ 239 | 240 | def __init__(self, active, start, end): 241 | u""" 242 | stat and end must be datetime.date or datetime.datetime (both of the 243 | same type). 244 | """ 245 | super(OrgTimeRange, self).__init__() 246 | self.start = start 247 | self.end = end 248 | self.active = active 249 | 250 | def __unicode__(self): 251 | u""" 252 | Return a string representation. 253 | """ 254 | # active 255 | if self.active: 256 | # datetime 257 | if isinstance(self.start, datetime.datetime): 258 | # if start and end are on same the day 259 | if self.start.year == self.end.year and\ 260 | self.start.month == self.end.month and\ 261 | self.start.day == self.end.day: 262 | return u"<%s-%s>" % ( 263 | self.start.strftime(u'%Y-%m-%d %a %H:%M'), 264 | self.end.strftime(u'%H:%M')) 265 | else: 266 | return u"<%s>--<%s>" % ( 267 | self.start.strftime(u'%Y-%m-%d %a %H:%M'), 268 | self.end.strftime(u'%Y-%m-%d %a %H:%M')) 269 | # date 270 | if isinstance(self.start, datetime.date): 271 | return u"<%s>--<%s>" % ( 272 | self.start.strftime(u'%Y-%m-%d %a'), 273 | self.end.strftime(u'%Y-%m-%d %a')) 274 | # inactive 275 | else: 276 | if isinstance(self.start, datetime.datetime): 277 | # if start and end are on same the day 278 | if self.start.year == self.end.year and\ 279 | self.start.month == self.end.month and\ 280 | self.start.day == self.end.day: 281 | return u"[%s-%s]" % ( 282 | self.start.strftime(u'%Y-%m-%d %a %H:%M'), 283 | self.end.strftime(u'%H:%M')) 284 | else: 285 | return u"[%s]--[%s]" % ( 286 | self.start.strftime(u'%Y-%m-%d %a %H:%M'), 287 | self.end.strftime(u'%Y-%m-%d %a %H:%M')) 288 | if isinstance(self.start, datetime.date): 289 | return u"[%s]--[%s]" % ( 290 | self.start.strftime(u'%Y-%m-%d %a'), 291 | self.end.strftime(u'%Y-%m-%d %a')) 292 | 293 | def __str__(self): 294 | return u_encode(self.__unicode__()) 295 | -------------------------------------------------------------------------------- /ftplugin/orgmode/menu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | from orgmode.keybinding import Command, Plug, Keybinding 6 | from orgmode.keybinding import MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT 7 | 8 | from orgmode.py3compat.encode_compatibility import * 9 | 10 | def register_menu(f): 11 | def r(*args, **kwargs): 12 | p = f(*args, **kwargs) 13 | def create(entry): 14 | if isinstance(entry, Submenu) or isinstance(entry, Separator) \ 15 | or isinstance(entry, ActionEntry): 16 | entry.create() 17 | 18 | if hasattr(p, u'menu'): 19 | if isinstance(p.menu, list) or isinstance(p.menu, tuple): 20 | for e in p.menu: 21 | create(e) 22 | else: 23 | create(p.menu) 24 | return p 25 | return r 26 | 27 | 28 | def add_cmd_mapping_menu(plugin, name, function, key_mapping, menu_desrc): 29 | u"""A helper function to create a vim command and keybinding and add these 30 | to the menu for a given plugin. 31 | 32 | :plugin: the plugin to operate on. 33 | :name: the name of the vim command (and the name of the Plug) 34 | :function: the actual python function which is called when executing the 35 | vim command. 36 | :key_mapping: the keymapping to execute the command. 37 | :menu_desrc: the text which appears in the menu. 38 | """ 39 | cmd = Command(name, function) 40 | keybinding = Keybinding(key_mapping, Plug(name, cmd)) 41 | 42 | plugin.commands.append(cmd) 43 | plugin.keybindings.append(keybinding) 44 | plugin.menu + ActionEntry(menu_desrc, keybinding) 45 | 46 | 47 | class Submenu(object): 48 | u""" Submenu entry """ 49 | 50 | def __init__(self, name, parent=None): 51 | object.__init__(self) 52 | self.name = name 53 | self.parent = parent 54 | self._children = [] 55 | 56 | def __add__(self, entry): 57 | if entry not in self._children: 58 | self._children.append(entry) 59 | entry.parent = self 60 | return entry 61 | 62 | def __sub__(self, entry): 63 | if entry in self._children: 64 | idx = self._children.index(entry) 65 | del self._children[idx] 66 | 67 | @property 68 | def children(self): 69 | return self._children[:] 70 | 71 | def get_menu(self): 72 | n = self.name.replace(u' ', u'\\ ') 73 | if self.parent: 74 | return u'%s.%s' % (self.parent.get_menu(), n) 75 | return n 76 | 77 | def create(self): 78 | for c in self.children: 79 | c.create() 80 | 81 | def __str__(self): 82 | res = self.name 83 | for c in self.children: 84 | res += str(c) 85 | return res 86 | 87 | class Separator(object): 88 | u""" Menu entry for a Separator """ 89 | 90 | def __init__(self, parent=None): 91 | object.__init__(self) 92 | self.parent = parent 93 | 94 | def __unicode__(self): 95 | return u'-----' 96 | 97 | def __str__(self): 98 | return u_encode(self.__unicode__()) 99 | 100 | def create(self): 101 | if self.parent: 102 | menu = self.parent.get_menu() 103 | vim.command(u_encode(u'menu %s.-%s- :' % (menu, id(self)))) 104 | 105 | class ActionEntry(object): 106 | u""" ActionEntry entry """ 107 | 108 | def __init__(self, lname, action, rname=None, mode=MODE_NORMAL, parent=None): 109 | u""" 110 | :lname: menu title on the left hand side of the menu entry 111 | :action: could be a vim command sequence or an actual Keybinding 112 | :rname: menu title that appears on the right hand side of the menu 113 | entry. If action is a Keybinding this value ignored and is 114 | taken from the Keybinding 115 | :mode: defines when the menu entry/action is executable 116 | :parent: the parent instance of this object. The only valid parent is Submenu 117 | """ 118 | object.__init__(self) 119 | self._lname = lname 120 | self._action = action 121 | self._rname = rname 122 | if mode not in (MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT): 123 | raise ValueError(u'Parameter mode not in MODE_ALL, MODE_NORMAL, MODE_VISUAL, MODE_INSERT') 124 | self._mode = mode 125 | self.parent = parent 126 | 127 | def __str__(self): 128 | return u'%s\t%s' % (self.lname, self.rname) 129 | 130 | @property 131 | def lname(self): 132 | return self._lname.replace(u' ', u'\\ ') 133 | 134 | @property 135 | def action(self): 136 | if isinstance(self._action, Keybinding): 137 | return self._action.action 138 | return self._action 139 | 140 | @property 141 | def rname(self): 142 | if isinstance(self._action, Keybinding): 143 | return self._action.key.replace(u'', u'Tab') 144 | return self._rname 145 | 146 | @property 147 | def mode(self): 148 | if isinstance(self._action, Keybinding): 149 | return self._action.mode 150 | return self._mode 151 | 152 | def create(self): 153 | menucmd = u':%smenu ' % self.mode 154 | menu = u'' 155 | cmd = u'' 156 | 157 | if self.parent: 158 | menu = self.parent.get_menu() 159 | menu += u'.%s' % self.lname 160 | 161 | if self.rname: 162 | cmd = u'%s %s%s %s' % (menucmd, menu, self.rname, self.action) 163 | else: 164 | cmd = u'%s %s %s' % (menucmd, menu, self.action) 165 | 166 | vim.command(u_encode(cmd)) 167 | 168 | # keybindings should be stored in the plugin.keybindings property and be registered by the appropriate keybinding registrar 169 | #if isinstance(self._action, Keybinding): 170 | # self._action.create() 171 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/Export.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import subprocess 5 | 6 | import vim 7 | 8 | from orgmode._vim import ORGMODE, echoe, echom 9 | from orgmode.menu import Submenu, ActionEntry, add_cmd_mapping_menu 10 | from orgmode.keybinding import Keybinding, Plug, Command 11 | from orgmode import settings 12 | 13 | from orgmode.py3compat.py_py3_string import * 14 | 15 | class Export(object): 16 | u""" 17 | Export a orgmode file using emacs orgmode. 18 | 19 | This is a *very simple* wrapper of the emacs/orgmode export. emacs and 20 | orgmode need to be installed. We simply call emacs with some options to 21 | export the .org. 22 | 23 | TODO: Offer export options in vim. Don't use the menu. 24 | TODO: Maybe use a native implementation. 25 | """ 26 | 27 | def __init__(self): 28 | u""" Initialize plugin """ 29 | object.__init__(self) 30 | # menu entries this plugin should create 31 | self.menu = ORGMODE.orgmenu + Submenu(u'Export') 32 | 33 | # key bindings for this plugin 34 | # key bindings are also registered through the menu so only additional 35 | # bindings should be put in this variable 36 | self.keybindings = [] 37 | 38 | # commands for this plugin 39 | self.commands = [] 40 | 41 | @classmethod 42 | def _get_init_script(cls): 43 | init_script = settings.get(u'org_export_init_script', u'') 44 | if init_script: 45 | init_script = os.path.expandvars(os.path.expanduser(init_script)) 46 | if os.path.exists(init_script): 47 | return init_script 48 | else: 49 | echoe(u'Unable to find init script %s' % init_script) 50 | 51 | @classmethod 52 | def _export(cls, format_): 53 | """Export current file to format. 54 | 55 | Args: 56 | format_: pdf or html 57 | 58 | Returns: 59 | return code 60 | """ 61 | emacsbin = os.path.expandvars(os.path.expanduser( 62 | settings.get(u'org_export_emacs', u'/usr/bin/emacs'))) 63 | if not os.path.exists(emacsbin): 64 | echoe(u'Unable to find emacs binary %s' % emacsbin) 65 | 66 | # build the export command 67 | cmd = [ 68 | emacsbin, 69 | u'-nw', 70 | u'--batch', 71 | u'--visit=%s' % vim.eval(u'expand("%:p")'), 72 | u'--funcall=%s' % format_ 73 | ] 74 | # source init script as well 75 | init_script = cls._get_init_script() 76 | if init_script: 77 | cmd.extend(['--script', init_script]) 78 | 79 | # export 80 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 81 | p.wait() 82 | 83 | if p.returncode != 0 or settings.get(u'org_export_verbose') == 1: 84 | echom('\n'.join(map(lambda x: x.decode(), p.communicate()))) 85 | return p.returncode 86 | 87 | @classmethod 88 | def topdf(cls): 89 | u"""Export the current buffer as pdf using emacs orgmode.""" 90 | ret = cls._export(u'org-latex-export-to-pdf') 91 | if ret != 0: 92 | echoe(u'PDF export failed.') 93 | else: 94 | echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'pdf')) 95 | 96 | @classmethod 97 | def tobeamer(cls): 98 | u"""Export the current buffer as beamer pdf using emacs orgmode.""" 99 | ret = cls._export(u'org-beamer-export-to-pdf') 100 | if ret != 0: 101 | echoe(u'PDF export failed.') 102 | else: 103 | echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'pdf')) 104 | 105 | @classmethod 106 | def tohtml(cls): 107 | u"""Export the current buffer as html using emacs orgmode.""" 108 | ret = cls._export(u'org-html-export-to-html') 109 | if ret != 0: 110 | echoe(u'HTML export failed.') 111 | else: 112 | echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'html')) 113 | 114 | @classmethod 115 | def tolatex(cls): 116 | u"""Export the current buffer as latex using emacs orgmode.""" 117 | ret = cls._export(u'org-latex-export-to-latex') 118 | if ret != 0: 119 | echoe(u'latex export failed.') 120 | else: 121 | echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'tex')) 122 | 123 | @classmethod 124 | def tomarkdown(cls): 125 | u"""Export the current buffer as markdown using emacs orgmode.""" 126 | ret = cls._export(u'org-md-export-to-markdown') 127 | if ret != 0: 128 | echoe('Markdown export failed. Make sure org-md-export-to-markdown is loaded in emacs, see the manual for details.') 129 | else: 130 | echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'md')) 131 | 132 | def register(self): 133 | u"""Registration and keybindings.""" 134 | 135 | # path to emacs executable 136 | settings.set(u'org_export_emacs', u'/usr/bin/emacs') 137 | # verbose output for export 138 | settings.set(u'org_export_verbose', 0) 139 | # allow the user to define an initialization script 140 | settings.set(u'org_export_init_script', u'') 141 | 142 | # to PDF 143 | add_cmd_mapping_menu( 144 | self, 145 | name=u'OrgExportToPDF', 146 | function=u':%s ORGMODE.plugins[u"Export"].topdf()' % VIM_PY_CALL, 147 | key_mapping=u'ep', 148 | menu_desrc=u'To PDF (via Emacs)' 149 | ) 150 | # to Beamer PDF 151 | add_cmd_mapping_menu( 152 | self, 153 | name=u'OrgExportToBeamerPDF', 154 | function=u':%s ORGMODE.plugins[u"Export"].tobeamer()' % VIM_PY_CALL, 155 | key_mapping=u'eb', 156 | menu_desrc=u'To Beamer PDF (via Emacs)' 157 | ) 158 | # to latex 159 | add_cmd_mapping_menu( 160 | self, 161 | name=u'OrgExportToLaTeX', 162 | function=u':%s ORGMODE.plugins[u"Export"].tolatex()' % VIM_PY_CALL, 163 | key_mapping=u'el', 164 | menu_desrc=u'To LaTeX (via Emacs)' 165 | ) 166 | # to HTML 167 | add_cmd_mapping_menu( 168 | self, 169 | name=u'OrgExportToHTML', 170 | function=u':%s ORGMODE.plugins[u"Export"].tohtml()' % VIM_PY_CALL, 171 | key_mapping=u'eh', 172 | menu_desrc=u'To HTML (via Emacs)' 173 | ) 174 | # to Markdown 175 | add_cmd_mapping_menu( 176 | self, 177 | name=u'OrgExportToMarkdown', 178 | function=u':%s ORGMODE.plugins[u"Export"].tomarkdown()' % VIM_PY_CALL, 179 | key_mapping=u'em', 180 | menu_desrc=u'To Markdown (via Emacs)' 181 | ) 182 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/Hyperlinks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | import vim 6 | 7 | from orgmode._vim import echom, ORGMODE, realign_tags 8 | from orgmode.menu import Submenu, Separator, ActionEntry 9 | from orgmode.keybinding import Keybinding, Plug, Command 10 | 11 | from orgmode.py3compat.encode_compatibility import * 12 | from orgmode.py3compat.py_py3_string import * 13 | 14 | class Hyperlinks(object): 15 | u""" Hyperlinks plugin """ 16 | 17 | def __init__(self): 18 | u""" Initialize plugin """ 19 | object.__init__(self) 20 | # menu entries this plugin should create 21 | self.menu = ORGMODE.orgmenu + Submenu(u'Hyperlinks') 22 | 23 | # key bindings for this plugin 24 | # key bindings are also registered through the menu so only additional 25 | # bindings should be put in this variable 26 | self.keybindings = [] 27 | 28 | # commands for this plugin 29 | self.commands = [] 30 | 31 | uri_match = re.compile( 32 | r'^\[{2}(?P[^][]*)(\]\[(?P[^][]*))?\]{2}') 33 | 34 | @classmethod 35 | def _get_link(cls, cursor=None): 36 | u""" 37 | Get the link the cursor is on and return it's URI and description 38 | 39 | :cursor: None or (Line, Column) 40 | :returns: None if no link was found, otherwise {uri:URI, 41 | description:DESCRIPTION, line:LINE, start:START, end:END} 42 | or uri and description could be None if not set 43 | """ 44 | cursor = cursor if cursor else vim.current.window.cursor 45 | line = u_decode(vim.current.buffer[cursor[0] - 1]) 46 | 47 | # if the cursor is on the last bracket, it's not recognized as a hyperlink 48 | start = line.rfind(u'[[', 0, cursor[1]) 49 | if start == -1: 50 | start = line.rfind(u'[[', 0, cursor[1] + 2) 51 | end = line.find(u']]', cursor[1]) 52 | if end == -1: 53 | end = line.find(u']]', cursor[1] - 1) 54 | 55 | # extract link 56 | if start != -1 and end != -1: 57 | end += 2 58 | match = Hyperlinks.uri_match.match(line[start:end]) 59 | 60 | res = { 61 | u'line': line, 62 | u'start': start, 63 | u'end': end, 64 | u'uri': None, 65 | u'description': None} 66 | if match: 67 | res.update(match.groupdict()) 68 | # reverse character escaping(partly done due to matching) 69 | res[u'uri'] = res[u'uri'].replace(u'\\\\', u'\\') 70 | return res 71 | 72 | @classmethod 73 | def follow(cls, action=u'openLink', visual=u''): 74 | u""" Follow hyperlink. If called on a regular string UTL determines the 75 | outcome. Normally a file with that name will be opened. 76 | 77 | :action: "copy" if the link should be copied to clipboard, otherwise 78 | the link will be opened 79 | :visual: "visual" if Universal Text Linking should be triggered in 80 | visual mode 81 | 82 | :returns: URI or None 83 | """ 84 | if not int(vim.eval(u'exists(":Utl")')): 85 | echom(u'Universal Text Linking plugin not installed, unable to proceed.') 86 | return 87 | 88 | action = u'copyLink' \ 89 | if (action and action.startswith(u'copy')) \ 90 | else u'openLink' 91 | visual = u'visual' if visual and visual.startswith(u'visual') else u'' 92 | 93 | link = Hyperlinks._get_link() 94 | 95 | if link and link[u'uri'] is not None: 96 | # call UTL with the URI 97 | vim.command(u_encode(u'Utl %s %s %s' % (action, visual, link[u'uri']))) 98 | return link[u'uri'] 99 | else: 100 | # call UTL and let it decide what to do 101 | vim.command(u_encode(u'Utl %s %s' % (action, visual))) 102 | 103 | @classmethod 104 | @realign_tags 105 | def insert(cls, uri=None, description=None): 106 | u""" Inserts a hyperlink. If no arguments are provided, an interactive 107 | query will be started. 108 | 109 | :uri: The URI that will be opened 110 | :description: An optional description that will be displayed instead of 111 | the URI 112 | 113 | :returns: (URI, description) 114 | """ 115 | link = Hyperlinks._get_link() 116 | if link: 117 | if uri is None and link[u'uri'] is not None: 118 | uri = link[u'uri'] 119 | if description is None and link[u'description'] is not None: 120 | description = link[u'description'] 121 | 122 | if uri is None: 123 | uri = vim.eval(u'input("Link: ", "", "file")') 124 | elif link: 125 | uri = vim.eval(u'input("Link: ", "%s", "file")' % link[u'uri']) 126 | if uri is None: 127 | return 128 | else: 129 | uri = u_decode(uri) 130 | 131 | # character escaping 132 | uri = uri.replace(u'\\', u'\\\\\\\\') 133 | uri = uri.replace(u' ', u'\\ ') 134 | 135 | if description is None: 136 | description = u_decode(vim.eval(u'input("Description: ")')) 137 | elif link: 138 | description = vim.eval( 139 | u'input("Description: ", "%s")' % 140 | u_decode(link[u'description'])) 141 | if description is None: 142 | return 143 | 144 | cursor = vim.current.window.cursor 145 | cl = u_decode(vim.current.buffer[cursor[0] - 1]) 146 | head = cl[:cursor[1] + 1] if not link else cl[:link[u'start']] 147 | tail = cl[cursor[1] + 1:] if not link else cl[link[u'end']:] 148 | 149 | separator = u'' 150 | if description: 151 | separator = u'][' 152 | 153 | if uri or description: 154 | vim.current.buffer[cursor[0] - 1] = \ 155 | u_encode(u''.join((head, u'[[%s%s%s]]' % (uri, separator, description), tail))) 156 | elif link: 157 | vim.current.buffer[cursor[0] - 1] = \ 158 | u_encode(u''.join((head, tail))) 159 | 160 | def register(self): 161 | u""" 162 | Registration of plugin. Key bindings and other initialization should be done. 163 | """ 164 | cmd = Command( 165 | u'OrgHyperlinkFollow', 166 | u'%s ORGMODE.plugins[u"Hyperlinks"].follow()' % VIM_PY_CALL) 167 | self.commands.append(cmd) 168 | self.keybindings.append( 169 | Keybinding(u'gl', Plug(u'OrgHyperlinkFollow', self.commands[-1]))) 170 | self.menu + ActionEntry(u'&Follow Link', self.keybindings[-1]) 171 | 172 | cmd = Command( 173 | u'OrgHyperlinkCopy', 174 | u'%s ORGMODE.plugins[u"Hyperlinks"].follow(action=u"copy")' % VIM_PY_CALL) 175 | self.commands.append(cmd) 176 | self.keybindings.append( 177 | Keybinding(u'gyl', Plug(u'OrgHyperlinkCopy', self.commands[-1]))) 178 | self.menu + ActionEntry(u'&Copy Link', self.keybindings[-1]) 179 | 180 | cmd = Command( 181 | u'OrgHyperlinkInsert', 182 | u'%s ORGMODE.plugins[u"Hyperlinks"].insert()' % VIM_PY_CALL, 183 | arguments=u'*') 184 | self.commands.append(cmd) 185 | self.keybindings.append( 186 | Keybinding(u'gil', Plug(u'OrgHyperlinkInsert', self.commands[-1]))) 187 | self.menu + ActionEntry(u'&Insert Link', self.keybindings[-1]) 188 | 189 | self.menu + Separator() 190 | 191 | # find next link 192 | cmd = Command( 193 | u'OrgHyperlinkNextLink', 194 | u":if search('\\[\\{2}\\zs[^][]*\\(\\]\\[[^][]*\\)\\?\\ze\\]\\{2}', 's') == 0 | echo 'No further link found.' | endif") 195 | self.commands.append(cmd) 196 | self.keybindings.append( 197 | Keybinding(u'gn', Plug(u'OrgHyperlinkNextLink', self.commands[-1]))) 198 | self.menu + ActionEntry(u'&Next Link', self.keybindings[-1]) 199 | 200 | # find previous link 201 | cmd = Command( 202 | u'OrgHyperlinkPreviousLink', 203 | u":if search('\\[\\{2}\\zs[^][]*\\(\\]\\[[^][]*\\)\\?\\ze\\]\\{2}', 'bs') == 0 | echo 'No further link found.' | endif") 204 | self.commands.append(cmd) 205 | self.keybindings.append( 206 | Keybinding(u'go', Plug(u'OrgHyperlinkPreviousLink', self.commands[-1]))) 207 | self.menu + ActionEntry(u'&Previous Link', self.keybindings[-1]) 208 | 209 | self.menu + Separator() 210 | 211 | # Descriptive Links 212 | cmd = Command(u'OrgHyperlinkDescriptiveLinks', u':setlocal cole=2') 213 | self.commands.append(cmd) 214 | self.menu + ActionEntry(u'&Descriptive Links', self.commands[-1]) 215 | 216 | # Literal Links 217 | cmd = Command(u'OrgHyperlinkLiteralLinks', u':setlocal cole=0') 218 | self.commands.append(cmd) 219 | self.menu + ActionEntry(u'&Literal Links', self.commands[-1]) 220 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/LoggingWork.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | from orgmode._vim import echo, echom, echoe, ORGMODE, apply_count, repeat 6 | from orgmode.menu import Submenu, Separator, ActionEntry 7 | from orgmode.keybinding import Keybinding, Plug, Command 8 | 9 | from orgmode.py3compat.py_py3_string import * 10 | 11 | class LoggingWork(object): 12 | u""" LoggingWork plugin """ 13 | 14 | def __init__(self): 15 | u""" Initialize plugin """ 16 | object.__init__(self) 17 | # menu entries this plugin should create 18 | self.menu = ORGMODE.orgmenu + Submenu(u'&Logging work') 19 | 20 | # key bindings for this plugin 21 | # key bindings are also registered through the menu so only additional 22 | # bindings should be put in this variable 23 | self.keybindings = [] 24 | 25 | # commands for this plugin 26 | self.commands = [] 27 | 28 | @classmethod 29 | def action(cls): 30 | u""" Some kind of action 31 | 32 | :returns: TODO 33 | """ 34 | pass 35 | 36 | def register(self): 37 | u""" 38 | Registration of plugin. Key bindings and other initialization should be done. 39 | """ 40 | # an Action menu entry which binds "keybinding" to action ":action" 41 | self.commands.append(Command(u'OrgLoggingRecordDoneTime', u'%s ORGMODE.plugins[u"LoggingWork"].action()' % VIM_PY_CALL)) 42 | self.menu + ActionEntry(u'&Record DONE time', self.commands[-1]) 43 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/Misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | from orgmode._vim import ORGMODE, apply_count 6 | from orgmode.menu import Submenu 7 | from orgmode.keybinding import Keybinding, Plug, MODE_VISUAL, MODE_OPERATOR 8 | 9 | from orgmode.py3compat.encode_compatibility import * 10 | from orgmode.py3compat.py_py3_string import * 11 | 12 | class Misc(object): 13 | u""" Miscellaneous functionality """ 14 | 15 | def __init__(self): 16 | u""" Initialize plugin """ 17 | object.__init__(self) 18 | # menu entries this plugin should create 19 | self.menu = ORGMODE.orgmenu + Submenu(u'Misc') 20 | 21 | # key bindings for this plugin 22 | # key bindings are also registered through the menu so only additional 23 | # bindings should be put in this variable 24 | self.keybindings = [] 25 | 26 | @classmethod 27 | def jump_to_first_character(cls): 28 | heading = ORGMODE.get_document().current_heading() 29 | if not heading or heading.start_vim != vim.current.window.cursor[0]: 30 | vim.eval(u_encode(u'feedkeys("^", "n")')) 31 | return 32 | 33 | vim.current.window.cursor = (vim.current.window.cursor[0], heading.level + 1) 34 | 35 | @classmethod 36 | def edit_at_first_character(cls): 37 | heading = ORGMODE.get_document().current_heading() 38 | if not heading or heading.start_vim != vim.current.window.cursor[0]: 39 | vim.eval(u_encode(u'feedkeys("I", "n")')) 40 | return 41 | 42 | vim.current.window.cursor = (vim.current.window.cursor[0], heading.level + 1) 43 | vim.command(u_encode(u'startinsert')) 44 | 45 | # @repeat 46 | @classmethod 47 | @apply_count 48 | def i_heading(cls, mode=u'visual', selection=u'inner', skip_children=False): 49 | u""" 50 | inner heading text object 51 | """ 52 | heading = ORGMODE.get_document().current_heading() 53 | if heading: 54 | if selection != u'inner': 55 | heading = heading if not heading.parent else heading.parent 56 | 57 | line_start, col_start = [int(i) for i in vim.eval(u_encode(u'getpos("\'<")'))[1:3]] 58 | line_end, col_end = [int(i) for i in vim.eval(u_encode(u'getpos("\'>")'))[1:3]] 59 | 60 | if mode != u'visual': 61 | line_start = vim.current.window.cursor[0] 62 | line_end = line_start 63 | 64 | start = line_start 65 | end = line_end 66 | move_one_character_back = u'' if mode == u'visual' else u'h' 67 | 68 | if heading.start_vim < line_start: 69 | start = heading.start_vim 70 | if heading.end_vim > line_end and not skip_children: 71 | end = heading.end_vim 72 | elif heading.end_of_last_child_vim > line_end and skip_children: 73 | end = heading.end_of_last_child_vim 74 | 75 | if mode != u'visual' and not vim.current.buffer[end - 1]: 76 | end -= 1 77 | move_one_character_back = u'' 78 | 79 | swap_cursor = u'o' if vim.current.window.cursor[0] == line_start else u'' 80 | 81 | if selection == u'inner' and vim.current.window.cursor[0] != line_start: 82 | h = ORGMODE.get_document().current_heading() 83 | if h: 84 | heading = h 85 | 86 | visualmode = u_decode(vim.eval(u'visualmode()')) if mode == u'visual' else u'v' 87 | 88 | if line_start == start and line_start != heading.start_vim: 89 | if col_start in (0, 1): 90 | vim.command(u_encode(u'normal! %dgg0%s%dgg$%s%s' % (start, visualmode, end, move_one_character_back, swap_cursor))) 91 | else: 92 | vim.command(u_encode(u'normal! %dgg0%dl%s%dgg$%s%s' % (start, col_start - 1, visualmode, end, move_one_character_back, swap_cursor))) 93 | else: 94 | vim.command(u_encode(u'normal! %dgg0%dl%s%dgg$%s%s' % (start, heading.level + 1, visualmode, end, move_one_character_back, swap_cursor))) 95 | 96 | if selection == u'inner': 97 | if mode == u'visual': 98 | return u'OrgInnerHeadingVisual' if not skip_children else u'OrgInnerTreeVisual' 99 | else: 100 | return u'OrgInnerHeadingOperator' if not skip_children else u'OrgInnerTreeOperator' 101 | else: 102 | if mode == u'visual': 103 | return u'OrgOuterHeadingVisual' if not skip_children else u'OrgOuterTreeVisual' 104 | else: 105 | return u'OrgOuterHeadingOperator' if not skip_children else u'OrgOuterTreeOperator' 106 | elif mode == u'visual': 107 | vim.command(u_encode(u'normal! gv')) 108 | 109 | # @repeat 110 | @classmethod 111 | @apply_count 112 | def a_heading(cls, selection=u'inner', skip_children=False): 113 | u""" 114 | a heading text object 115 | """ 116 | heading = ORGMODE.get_document().current_heading() 117 | if heading: 118 | if selection != u'inner': 119 | heading = heading if not heading.parent else heading.parent 120 | 121 | line_start, col_start = [int(i) for i in vim.eval(u_encode(u'getpos("\'<")'))[1:3]] 122 | line_end, col_end = [int(i) for i in vim.eval(u_encode(u'getpos("\'>")'))[1:3]] 123 | 124 | start = line_start 125 | end = line_end 126 | 127 | if heading.start_vim < line_start: 128 | start = heading.start_vim 129 | if heading.end_vim > line_end and not skip_children: 130 | end = heading.end_vim 131 | elif heading.end_of_last_child_vim > line_end and skip_children: 132 | end = heading.end_of_last_child_vim 133 | 134 | swap_cursor = u'o' if vim.current.window.cursor[0] == line_start else u'' 135 | 136 | vim.command(u_encode(u'normal! %dgg%s%dgg$%s' % (start, vim.eval(u_encode(u'visualmode()')), end, swap_cursor))) 137 | if selection == u'inner': 138 | return u'OrgAInnerHeadingVisual' if not skip_children else u'OrgAInnerTreeVisual' 139 | else: 140 | return u'OrgAOuterHeadingVisual' if not skip_children else u'OrgAOuterTreeVisual' 141 | else: 142 | vim.command(u_encode(u'normal! gv')) 143 | 144 | def register(self): 145 | u""" 146 | Registration of plugin. Key bindings and other initialization should be done. 147 | """ 148 | self.keybindings.append(Keybinding(u'^', 149 | Plug(u'OrgJumpToFirstCharacter', u'%s ORGMODE.plugins[u"Misc"].jump_to_first_character()' % VIM_PY_CALL))) 150 | self.keybindings.append(Keybinding(u'I', 151 | Plug(u'OrgEditAtFirstCharacter', u'%s ORGMODE.plugins[u"Misc"].edit_at_first_character()' % VIM_PY_CALL))) 152 | 153 | self.keybindings.append(Keybinding(u'ih', Plug(u'OrgInnerHeadingVisual', u':%s ORGMODE.plugins[u"Misc"].i_heading()' % VIM_PY_CALL, mode=MODE_VISUAL))) 154 | self.keybindings.append(Keybinding(u'ah', Plug(u'OrgAInnerHeadingVisual', u':%s ORGMODE.plugins[u"Misc"].a_heading()' % VIM_PY_CALL, mode=MODE_VISUAL))) 155 | self.keybindings.append(Keybinding(u'Oh', Plug(u'OrgOuterHeadingVisual', u':%s ORGMODE.plugins[u"Misc"].i_heading(selection=u"outer")' % VIM_PY_CALL, mode=MODE_VISUAL))) 156 | self.keybindings.append(Keybinding(u'OH', Plug(u'OrgAOuterHeadingVisual', u':%s ORGMODE.plugins[u"Misc"].a_heading(selection=u"outer")' % VIM_PY_CALL, mode=MODE_VISUAL))) 157 | 158 | self.keybindings.append(Keybinding(u'ih', Plug(u'OrgInnerHeadingOperator', u':%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator")' % VIM_PY_CALL, mode=MODE_OPERATOR))) 159 | self.keybindings.append(Keybinding(u'ah', u':normal Vah', mode=MODE_OPERATOR)) 160 | self.keybindings.append(Keybinding(u'Oh', Plug(u'OrgOuterHeadingOperator', ':%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator", selection=u"outer")' % VIM_PY_CALL, mode=MODE_OPERATOR))) 161 | self.keybindings.append(Keybinding(u'OH', u':normal VOH', mode=MODE_OPERATOR)) 162 | 163 | self.keybindings.append(Keybinding(u'ir', Plug(u'OrgInnerTreeVisual', u':%s ORGMODE.plugins[u"Misc"].i_heading(skip_children=True)' % VIM_PY_CALL, mode=MODE_VISUAL))) 164 | self.keybindings.append(Keybinding(u'ar', Plug(u'OrgAInnerTreeVisual', u':%s ORGMODE.plugins[u"Misc"].a_heading(skip_children=True)' % VIM_PY_CALL, mode=MODE_VISUAL))) 165 | self.keybindings.append(Keybinding(u'Or', Plug(u'OrgOuterTreeVisual', u'<:%s ORGMODE.plugins[u"Misc"].i_heading(selection=u"outer", skip_children=True)' % VIM_PY_CALL, mode=MODE_VISUAL))) 166 | self.keybindings.append(Keybinding(u'OR', Plug(u'OrgAOuterTreeVisual', u':%s ORGMODE.plugins[u"Misc"].a_heading(selection=u"outer", skip_children=True)' % VIM_PY_CALL, mode=MODE_VISUAL))) 167 | 168 | self.keybindings.append(Keybinding(u'ir', Plug(u'OrgInnerTreeOperator', u':%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator", skip_children=True)' % VIM_PY_CALL, mode=MODE_OPERATOR))) 169 | self.keybindings.append(Keybinding(u'ar', u':normal Var', mode=MODE_OPERATOR)) 170 | self.keybindings.append(Keybinding(u'Or', Plug(u'OrgOuterTreeOperator', u':%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator", selection=u"outer", skip_children=True)' % VIM_PY_CALL, mode=MODE_OPERATOR))) 171 | self.keybindings.append(Keybinding(u'OR', u':normal VOR', mode=MODE_OPERATOR)) 172 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/ShowHide.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | from orgmode.liborgmode.headings import Heading 6 | from orgmode._vim import ORGMODE, apply_count 7 | from orgmode import settings 8 | from orgmode.menu import Submenu, ActionEntry 9 | from orgmode.keybinding import Keybinding, Plug, MODE_NORMAL 10 | 11 | from orgmode.py3compat.encode_compatibility import * 12 | from orgmode.py3compat.xrange_compatibility import * 13 | from orgmode.py3compat.py_py3_string import * 14 | 15 | class ShowHide(object): 16 | u""" Show Hide plugin """ 17 | 18 | def __init__(self): 19 | u""" Initialize plugin """ 20 | object.__init__(self) 21 | # menu entries this plugin should create 22 | self.menu = ORGMODE.orgmenu + Submenu(u'&Show Hide') 23 | 24 | # key bindings for this plugin 25 | # key bindings are also registered through the menu so only additional 26 | # bindings should be put in this variable 27 | self.keybindings = [] 28 | 29 | @classmethod 30 | def _fold_depth(cls, h): 31 | """ Find the deepest level of open folds 32 | 33 | :h: Heading 34 | :returns: Tuple (int - level of open folds, boolean - found fold) or None if h is not a Heading 35 | """ 36 | if not isinstance(h, Heading): 37 | return 38 | 39 | if int(vim.eval(u_encode(u'foldclosed(%d)' % h.start_vim))) != -1: 40 | return (h.number_of_parents, True) 41 | 42 | res = [h.number_of_parents + 1] 43 | found = False 44 | for c in h.children: 45 | d, f = cls._fold_depth(c) 46 | res.append(d) 47 | found |= f 48 | 49 | return (max(res), found) 50 | 51 | @classmethod 52 | @apply_count 53 | def toggle_folding(cls, reverse=False): 54 | u""" Toggle folding similar to the way orgmode does 55 | 56 | This is just a convenience function, don't hesitate to use the z* 57 | keybindings vim offers to deal with folding! 58 | 59 | :reverse: If False open folding by one level otherwise close it by one. 60 | """ 61 | d = ORGMODE.get_document() 62 | heading = d.current_heading() 63 | if not heading: 64 | vim.eval(u_encode(u'feedkeys("", "n")')) 65 | return 66 | 67 | cursor = vim.current.window.cursor[:] 68 | 69 | if int(vim.eval(u_encode(u'foldclosed(%d)' % heading.start_vim))) != -1: 70 | if not reverse: 71 | # open closed fold 72 | p = heading.number_of_parents 73 | if not p: 74 | p = heading.level 75 | vim.command(u_encode(u'normal! %dzo' % p)) 76 | else: 77 | # reverse folding opens all folds under the cursor 78 | vim.command(u_encode(u'%d,%dfoldopen!' % (heading.start_vim, heading.end_of_last_child_vim))) 79 | vim.current.window.cursor = cursor 80 | return heading 81 | 82 | def open_fold(h): 83 | if h.number_of_parents <= open_depth: 84 | vim.command(u_encode(u'normal! %dgg%dzo' % (h.start_vim, open_depth))) 85 | for c in h.children: 86 | open_fold(c) 87 | 88 | def close_fold(h): 89 | for c in h.children: 90 | close_fold(c) 91 | if h.number_of_parents >= open_depth - 1 and \ 92 | int(vim.eval(u_encode(u'foldclosed(%d)' % h.start_vim))) == -1: 93 | vim.command(u_encode(u'normal! %dggzc' % (h.start_vim, ))) 94 | 95 | # find deepest fold 96 | open_depth, found_fold = cls._fold_depth(heading) 97 | 98 | if not reverse: 99 | # recursively open folds 100 | if found_fold: 101 | for child in heading.children: 102 | open_fold(child) 103 | else: 104 | vim.command(u_encode(u'%d,%dfoldclose!' % (heading.start_vim, heading.end_of_last_child_vim))) 105 | 106 | if heading.number_of_parents: 107 | # restore cursor position, it might have been changed by open_fold 108 | vim.current.window.cursor = cursor 109 | 110 | p = heading.number_of_parents 111 | if not p: 112 | p = heading.level 113 | # reopen fold again because the former closing of the fold closed all levels, including parents! 114 | vim.command(u_encode(u'normal! %dzo' % (p, ))) 115 | else: 116 | # close the last level of folds 117 | close_fold(heading) 118 | 119 | # restore cursor position 120 | vim.current.window.cursor = cursor 121 | return heading 122 | 123 | @classmethod 124 | @apply_count 125 | def global_toggle_folding(cls, reverse=False): 126 | """ Toggle folding globally 127 | 128 | :reverse: If False open folding by one level otherwise close it by one. 129 | """ 130 | d = ORGMODE.get_document() 131 | if reverse: 132 | foldlevel = int(vim.eval(u_encode(u'&foldlevel'))) 133 | if foldlevel == 0: 134 | # open all folds because the user tries to close folds beyond 0 135 | vim.eval(u_encode(u'feedkeys("zR", "n")')) 136 | else: 137 | # vim can reduce the foldlevel on its own 138 | vim.eval(u_encode(u'feedkeys("zm", "n")')) 139 | else: 140 | found = False 141 | for h in d.headings: 142 | res = cls._fold_depth(h) 143 | if res: 144 | found = res[1] 145 | if found: 146 | break 147 | if not found: 148 | # no fold found and the user tries to advance the fold level 149 | # beyond maximum so close everything 150 | vim.eval(u_encode(u'feedkeys("zM", "n")')) 151 | else: 152 | # fold found, vim can increase the foldlevel on its own 153 | vim.eval(u_encode(u'feedkeys("zr", "n")')) 154 | 155 | return d 156 | 157 | def register(self): 158 | u""" 159 | Registration of plugin. Key bindings and other initialization should be done. 160 | """ 161 | # register plug 162 | 163 | self.keybindings.append(Keybinding(u'', 164 | Plug(u'OrgToggleFoldingNormal', u'%s ORGMODE.plugins[u"ShowHide"].toggle_folding()' % VIM_PY_CALL))) 165 | self.menu + ActionEntry(u'&Cycle Visibility', self.keybindings[-1]) 166 | 167 | self.keybindings.append(Keybinding(u'', 168 | Plug(u'OrgToggleFoldingReverse', u'%s ORGMODE.plugins[u"ShowHide"].toggle_folding(reverse=True)' % VIM_PY_CALL))) 169 | self.menu + ActionEntry(u'Cycle Visibility &Reverse', self.keybindings[-1]) 170 | 171 | self.keybindings.append(Keybinding(u'.', 172 | Plug(u'OrgGlobalToggleFoldingNormal', u'%s ORGMODE.plugins[u"ShowHide"].global_toggle_folding()' % VIM_PY_CALL))) 173 | self.menu + ActionEntry(u'Cycle Visibility &Globally', self.keybindings[-1]) 174 | 175 | self.keybindings.append(Keybinding(u',', 176 | Plug(u'OrgGlobalToggleFoldingReverse', 177 | u'%s ORGMODE.plugins[u"ShowHide"].global_toggle_folding(reverse=True)' % VIM_PY_CALL))) 178 | self.menu + ActionEntry(u'Cycle Visibility Reverse G&lobally', self.keybindings[-1]) 179 | 180 | for i in range(0, 10): 181 | self.keybindings.append(Keybinding(u'%d' % (i, ), u'zM:set fdl=%d' % i, mode=MODE_NORMAL)) 182 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/TagsProperties.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | from orgmode._vim import ORGMODE, repeat 6 | from orgmode.menu import Submenu, ActionEntry 7 | from orgmode.keybinding import Keybinding, Plug, Command 8 | from orgmode import settings 9 | 10 | from orgmode.py3compat.encode_compatibility import * 11 | from orgmode.py3compat.py_py3_string import * 12 | 13 | class TagsProperties(object): 14 | u""" TagsProperties plugin """ 15 | 16 | def __init__(self): 17 | u""" Initialize plugin """ 18 | object.__init__(self) 19 | # menu entries this plugin should create 20 | self.menu = ORGMODE.orgmenu + Submenu(u'&TAGS and Properties') 21 | 22 | # key bindings for this plugin 23 | # key bindings are also registered through the menu so only additional 24 | # bindings should be put in this variable 25 | self.keybindings = [] 26 | 27 | # commands for this plugin 28 | self.commands = [] 29 | 30 | @classmethod 31 | def complete_tags(cls): 32 | u""" build a list of tags and store it in variable b:org_tag_completion 33 | """ 34 | d = ORGMODE.get_document() 35 | heading = d.current_heading() 36 | if not heading: 37 | return 38 | 39 | leading_portion = u_decode(vim.eval(u'a:ArgLead')) 40 | cursor = int(vim.eval(u'a:CursorPos')) 41 | 42 | # extract currently completed tag 43 | idx_orig = leading_portion.rfind(u':', 0, cursor) 44 | if idx_orig == -1: 45 | idx = 0 46 | else: 47 | idx = idx_orig 48 | 49 | current_tag = leading_portion[idx: cursor].lstrip(u':') 50 | head = leading_portion[:idx + 1] 51 | if idx_orig == -1: 52 | head = u'' 53 | tail = leading_portion[cursor:] 54 | 55 | # extract all tags of the current file 56 | all_tags = set() 57 | for h in d.all_headings(): 58 | for t in h.tags: 59 | all_tags.add(t) 60 | 61 | ignorecase = bool(int(settings.get(u'org_tag_completion_ignorecase', int(vim.eval(u'&ignorecase'))))) 62 | possible_tags = [] 63 | # TODO current tags never used... 64 | current_tags = heading.tags 65 | for t in all_tags: 66 | if ignorecase: 67 | if t.lower().startswith(current_tag.lower()): 68 | possible_tags.append(t) 69 | elif t.startswith(current_tag): 70 | possible_tags.append(t) 71 | 72 | vim.command(u_encode(u'let b:org_complete_tags = [%s]' % u', '.join([u'"%s%s:%s"' % (head, i, tail) for i in possible_tags]))) 73 | 74 | @classmethod 75 | @repeat 76 | def set_tags(cls): 77 | u""" Set tags for current heading 78 | """ 79 | d = ORGMODE.get_document() 80 | heading = d.current_heading() 81 | if not heading: 82 | return 83 | 84 | # retrieve tags 85 | res = None 86 | if heading.tags: 87 | res = vim.eval(u'input("Tags: ", ":%s:", "customlist,Org_complete_tags")' % u':'.join(heading.tags)) 88 | else: 89 | res = vim.eval(u'input("Tags: ", "", "customlist,Org_complete_tags")') 90 | 91 | if res is None: 92 | # user pressed abort any further processing 93 | return 94 | 95 | # remove empty tags 96 | heading.tags = [x for x in u_decode(res).strip().strip(u':').split(u':') if x.strip() != u''] 97 | 98 | d.write() 99 | 100 | return u'OrgSetTags' 101 | 102 | @classmethod 103 | def find_tags(cls): 104 | """ Find tags in current file 105 | """ 106 | tags = vim.eval(u'input("Find Tags: ", "", "customlist,Org_complete_tags")') 107 | if tags is None: 108 | # user pressed abort any further processing 109 | return 110 | 111 | tags = [x for x in u_decode(tags).strip().strip(u':').split(u':') if x.strip() != u''] 112 | if tags: 113 | searchstring = u'\\(' 114 | first = True 115 | for t1 in tags: 116 | if first: 117 | first = False 118 | searchstring += u'%s' % t1 119 | else: 120 | searchstring += u'\\|%s' % t1 121 | 122 | for t2 in tags: 123 | if t1 == t2: 124 | continue 125 | searchstring += u'\\(:[a-zA-Z:]*\\)\\?:%s' % t2 126 | searchstring += u'\\)' 127 | 128 | vim.command(u'/\\zs:%s:\\ze' % searchstring) 129 | return u'OrgFindTags' 130 | 131 | @classmethod 132 | def realign_tags(cls): 133 | u""" 134 | Updates tags when user finished editing a heading 135 | """ 136 | d = ORGMODE.get_document(allow_dirty=True) 137 | heading = d.find_current_heading() 138 | if not heading: 139 | return 140 | 141 | if vim.current.window.cursor[0] == heading.start_vim: 142 | heading.set_dirty_heading() 143 | d.write_heading(heading, including_children=False) 144 | 145 | @classmethod 146 | def realign_all_tags(cls): 147 | u""" 148 | Updates tags when user finishes editing a heading 149 | """ 150 | d = ORGMODE.get_document() 151 | for heading in d.all_headings(): 152 | heading.set_dirty_heading() 153 | 154 | d.write() 155 | 156 | def register(self): 157 | u""" 158 | Registration of plugin. Key bindings and other initialization should be done. 159 | """ 160 | # an Action menu entry which binds "keybinding" to action ":action" 161 | settings.set(u'org_tag_column', vim.eval(u'&textwidth')) 162 | settings.set(u'org_tag_completion_ignorecase', int(vim.eval(u'&ignorecase'))) 163 | 164 | cmd = Command( 165 | u'OrgSetTags', 166 | u'%s ORGMODE.plugins[u"TagsProperties"].set_tags()' % VIM_PY_CALL) 167 | self.commands.append(cmd) 168 | keybinding = Keybinding( 169 | u'st', 170 | Plug(u'OrgSetTags', cmd)) 171 | self.keybindings.append(keybinding) 172 | self.menu + ActionEntry(u'Set &Tags', keybinding) 173 | 174 | cmd = Command( 175 | u'OrgFindTags', 176 | u'%s ORGMODE.plugins[u"TagsProperties"].find_tags()' % VIM_PY_CALL) 177 | self.commands.append(cmd) 178 | keybinding = Keybinding( 179 | u'ft', 180 | Plug(u'OrgFindTags', cmd)) 181 | self.keybindings.append(keybinding) 182 | self.menu + ActionEntry(u'&Find Tags', keybinding) 183 | 184 | cmd = Command( 185 | u'OrgTagsRealign', 186 | u"%s ORGMODE.plugins[u'TagsProperties'].realign_all_tags()" % VIM_PY_CALL) 187 | self.commands.append(cmd) 188 | 189 | # workaround to align tags when user is leaving insert mode 190 | vim.command(u_encode(u"function Org_complete_tags(ArgLead, CmdLine, CursorPos)\n" 191 | + sys.executable.split('/')[-1] + u""" << EOF 192 | ORGMODE.plugins[u'TagsProperties'].complete_tags() 193 | EOF 194 | if exists('b:org_complete_tags') 195 | let tmp = b:org_complete_tags 196 | unlet b:org_complete_tags 197 | return tmp 198 | else 199 | return [] 200 | endif 201 | endfunction""")) 202 | 203 | vim.command(u_encode(u"""function Org_realign_tags_on_insert_leave() 204 | if !exists('b:org_complete_tag_on_insertleave_au') 205 | :au orgmode InsertLeave %s ORGMODE.plugins[u'TagsProperties'].realign_tags() 206 | let b:org_complete_tag_on_insertleave_au = 1 207 | endif 208 | endfunction""" % VIM_PY_CALL)) 209 | 210 | # this is for all org files opened after this file 211 | vim.command(u_encode(u"au orgmode FileType org call Org_realign_tags_on_insert_leave()")) 212 | # this is for the current file 213 | vim.command(u_encode(u"call Org_realign_tags_on_insert_leave()")) 214 | -------------------------------------------------------------------------------- /ftplugin/orgmode/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /ftplugin/orgmode/py3compat/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /ftplugin/orgmode/py3compat/encode_compatibility.py: -------------------------------------------------------------------------------- 1 | import sys 2 | if sys.version_info < (3,): 3 | def u_encode(string): 4 | return string.encode('utf8') 5 | def u_decode(string): 6 | return string.decode('utf8') 7 | else: 8 | def u_encode(string): 9 | return string 10 | def u_decode(string): 11 | return string 12 | -------------------------------------------------------------------------------- /ftplugin/orgmode/py3compat/py_py3_string.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from string import Formatter 3 | 4 | 5 | if sys.version_info < (3,): 6 | VIM_PY_CALL = u':py' 7 | else: 8 | VIM_PY_CALL = u':py3' 9 | 10 | 11 | class NoneAsEmptyFormatter(Formatter): 12 | def get_value(self, key, args, kwargs): 13 | v = super().get_value(key, args, kwargs) 14 | return '' if v is None else v 15 | 16 | 17 | fmt = NoneAsEmptyFormatter() 18 | -------------------------------------------------------------------------------- /ftplugin/orgmode/py3compat/unicode_compatibility.py: -------------------------------------------------------------------------------- 1 | try: 2 | unicode 3 | except NameError: 4 | basestring = unicode = str 5 | -------------------------------------------------------------------------------- /ftplugin/orgmode/py3compat/xrange_compatibility.py: -------------------------------------------------------------------------------- 1 | try: 2 | from __builtin__ import xrange as range 3 | except: 4 | pass 5 | -------------------------------------------------------------------------------- /ftplugin/orgmode/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import vim 4 | 5 | import sys 6 | from orgmode.py3compat.encode_compatibility import * 7 | from orgmode.py3compat.unicode_compatibility import * 8 | 9 | SCOPE_ALL = 1 10 | 11 | # for all vim-orgmode buffers 12 | SCOPE_GLOBAL = 2 13 | 14 | # just for the current buffer - has priority before the global settings 15 | SCOPE_BUFFER = 4 16 | 17 | VARIABLE_LEADER = {SCOPE_GLOBAL: u'g', SCOPE_BUFFER: u'b'} 18 | 19 | u""" Evaluate and store settings """ 20 | 21 | 22 | def get(setting, default=None, scope=SCOPE_ALL): 23 | u""" Evaluate setting in scope of the current buffer, 24 | globally and also from the contents of the current buffer 25 | 26 | WARNING: Only string values are converted to unicode. If a different value 27 | is received, e.g. a list or dict, no conversion is done. 28 | 29 | :setting: name of the variable to evaluate 30 | :default: default value in case the variable is empty 31 | 32 | :returns: variable value 33 | """ 34 | # TODO first read setting from org file which take precedence over vim 35 | # variable settings 36 | if (scope & SCOPE_ALL | SCOPE_BUFFER) and \ 37 | int(vim.eval(u_encode(u'exists("b:%s")' % setting))): 38 | res = vim.eval(u_encode(u"b:%s" % setting)) 39 | if type(res) in (unicode, str): 40 | return u_decode(res) 41 | return res 42 | 43 | elif (scope & SCOPE_ALL | SCOPE_GLOBAL) and \ 44 | int(vim.eval(u_encode(u'exists("g:%s")' % setting))): 45 | res = vim.eval(u_encode(u"g:%s" % setting)) 46 | if type(res) in (unicode, str): 47 | return u_decode(res) 48 | return res 49 | return default 50 | 51 | 52 | def set(setting, value, scope=SCOPE_GLOBAL, overwrite=False): 53 | u""" Store setting in the defined scope 54 | 55 | WARNING: For the return value, only string are converted to unicode. If a 56 | different value is received by vim.eval, e.g. a list or dict, no conversion 57 | is done. 58 | 59 | :setting: name of the setting 60 | :value: the actual value, repr is called on the value to create a string 61 | representation 62 | :scope: the scope o the setting/variable 63 | :overwrite: overwrite existing settings (probably user defined settings) 64 | 65 | :returns: the new value in case of overwrite==False the current value 66 | """ 67 | if (not overwrite) and ( 68 | int(vim.eval(u_encode(u'exists("%s:%s")' % \ 69 | (VARIABLE_LEADER[scope], setting))))): 70 | res = vim.eval( 71 | u_encode(u'%s:%s' % (VARIABLE_LEADER[scope], setting))) 72 | if type(res) in (unicode, str): 73 | return u_decode(res) 74 | return res 75 | v = repr(value) 76 | if type(value) == unicode and sys.version_info < (3,): 77 | # strip leading u of unicode string representations 78 | v = v[1:] 79 | 80 | cmd = u'let %s:%s = %s' % (VARIABLE_LEADER[scope], setting, v) 81 | vim.command(u_encode(cmd)) 82 | return value 83 | 84 | 85 | def unset(setting, scope=SCOPE_GLOBAL): 86 | u""" Unset setting in the defined scope 87 | :setting: name of the setting 88 | :scope: the scope o the setting/variable 89 | 90 | :returns: last value of setting 91 | """ 92 | value = get(setting, scope=scope) 93 | cmd = u'unlet! %s:%s' % (VARIABLE_LEADER[scope], setting) 94 | vim.command(u_encode(cmd)) 95 | return value 96 | -------------------------------------------------------------------------------- /indent/org.vim: -------------------------------------------------------------------------------- 1 | " Delete the next line to avoid the special indention of items 2 | if !exists("g:org_indent") 3 | let g:org_indent = 0 4 | endif 5 | 6 | setlocal foldtext=GetOrgFoldtext() 7 | setlocal fillchars-=fold:- 8 | setlocal fillchars+=fold:\ 9 | setlocal foldexpr=GetOrgFolding() 10 | setlocal foldmethod=expr 11 | setlocal indentexpr=GetOrgIndent() 12 | setlocal nolisp 13 | setlocal nosmartindent 14 | setlocal autoindent 15 | 16 | if has('python3') 17 | let s:py_env = 'python3 << EOF' 18 | else 19 | let s:py_env = 'python << EOF' 20 | endif 21 | 22 | function! GetOrgIndent() 23 | if g:org_indent == 0 24 | return -1 25 | endif 26 | 27 | exe s:py_env 28 | from orgmode._vim import indent_orgmode 29 | indent_orgmode() 30 | EOF 31 | 32 | if exists('b:indent_level') 33 | let l:tmp = b:indent_level 34 | unlet b:indent_level 35 | return l:tmp 36 | else 37 | return -1 38 | endif 39 | endfunction 40 | 41 | function! GetOrgFolding() 42 | let l:mode = mode() 43 | if l:mode == 'i' 44 | " the cache size is limited to 3, because vim queries the current and 45 | " both surrounding lines when the user is typing in insert mode. The 46 | " cache is shared between GetOrgFolding and GetOrgFoldtext 47 | if ! exists('b:org_folding_cache') 48 | let b:org_folding_cache = {} 49 | endif 50 | 51 | if has_key(b:org_folding_cache, v:lnum) 52 | if match(b:org_folding_cache[v:lnum], '^>') == 0 && 53 | \ match(getline(v:lnum), '^\*\+\s') != 0 54 | " when the user pastes text or presses enter, it happens that 55 | " the cache starts to confuse vim's folding abilities 56 | " these entries can safely be removed 57 | unlet b:org_folding_cache[v:lnum] 58 | 59 | " the fold text cache is probably also damaged, delete it as 60 | " well 61 | unlet! b:org_foldtext_cache 62 | else 63 | return b:org_folding_cache[v:lnum] 64 | endif 65 | endif 66 | 67 | exe s:py_env 68 | from orgmode._vim import fold_orgmode 69 | fold_orgmode(allow_dirty=True) 70 | EOF 71 | else 72 | 73 | exe s:py_env 74 | from orgmode._vim import fold_orgmode 75 | fold_orgmode() 76 | EOF 77 | endif 78 | 79 | if exists('b:fold_expr') 80 | let l:tmp = b:fold_expr 81 | unlet b:fold_expr 82 | if l:mode == 'i' 83 | if ! has_key(b:org_folding_cache, v:lnum) 84 | if len(b:org_folding_cache) > 3 85 | let b:org_folding_cache = {} 86 | endif 87 | let b:org_folding_cache[v:lnum] = l:tmp 88 | endif 89 | endif 90 | return l:tmp 91 | else 92 | return -1 93 | endif 94 | endfunction 95 | 96 | function! SetOrgFoldtext(text) 97 | let b:foldtext = a:text 98 | endfunction 99 | 100 | function! GetOrgFoldtext() 101 | let l:mode = mode() 102 | if l:mode == 'i' 103 | " add a separate cache for fold text 104 | if ! exists('b:org_foldtext_cache') || 105 | \ ! has_key(b:org_foldtext_cache, 'timestamp') || 106 | \ b:org_foldtext_cache['timestamp'] > (localtime() + 10) 107 | let b:org_foldtext_cache = {'timestamp': localtime()} 108 | endif 109 | 110 | if has_key(b:org_foldtext_cache, v:foldstart) 111 | return b:org_foldtext_cache[v:foldstart] 112 | endif 113 | exe s:py_env 114 | from orgmode._vim import fold_text 115 | fold_text(allow_dirty=True) 116 | EOF 117 | else 118 | unlet! b:org_foldtext_cache 119 | exec s:py_env 120 | from orgmode._vim import fold_text 121 | fold_text() 122 | EOF 123 | endif 124 | 125 | if exists('b:foldtext') 126 | let l:tmp = b:foldtext 127 | unlet b:foldtext 128 | if l:mode == 'i' 129 | let b:org_foldtext_cache[v:foldstart] = l:tmp 130 | endif 131 | return l:tmp 132 | endif 133 | endfunction 134 | -------------------------------------------------------------------------------- /syntax/orgagenda.vim: -------------------------------------------------------------------------------- 1 | " TODO do we really need a separate syntax file for the agenda? 2 | " - Most of the stuff here is also in syntax.org 3 | " - DRY! 4 | 5 | syn match org_todo_key /\[\zs[^]]*\ze\]/ 6 | hi def link org_todo_key Identifier 7 | 8 | let s:todo_headings = '' 9 | let s:i = 1 10 | while s:i <= g:org_heading_highlight_levels 11 | if s:todo_headings == '' 12 | let s:todo_headings = 'containedin=org_heading' . s:i 13 | else 14 | let s:todo_headings = s:todo_headings . ',org_heading' . s:i 15 | endif 16 | let s:i += 1 17 | endwhile 18 | unlet! s:i 19 | 20 | if !exists('g:loaded_orgagenda_syntax') 21 | let g:loaded_orgagenda_syntax = 1 22 | function! s:ReadTodoKeywords(keywords, todo_headings) 23 | let l:default_group = 'Todo' 24 | for l:i in a:keywords 25 | if type(l:i) == 3 26 | call s:ReadTodoKeywords(l:i, a:todo_headings) 27 | continue 28 | endif 29 | if l:i == '|' 30 | let l:default_group = 'Question' 31 | continue 32 | endif 33 | " strip access key 34 | let l:_i = substitute(l:i, "\(.*$", "", "") 35 | 36 | let l:group = l:default_group 37 | for l:j in g:org_todo_keyword_faces 38 | if l:j[0] == l:_i 39 | let l:group = 'orgtodo_todo_keyword_face_' . l:_i 40 | call OrgExtendHighlightingGroup(l:default_group, l:group, OrgInterpretFaces(l:j[1])) 41 | break 42 | endif 43 | endfor 44 | silent! exec 'syntax match orgtodo_todo_keyword_' . l:_i . ' /' . l:_i .'/ ' . a:todo_headings 45 | silent! exec 'hi def link orgtodo_todo_keyword_' . l:_i . ' ' . l:group 46 | endfor 47 | endfunction 48 | endif 49 | 50 | call s:ReadTodoKeywords(g:org_todo_keywords, s:todo_headings) 51 | unlet! s:todo_headings 52 | 53 | " Timestamps 54 | "<2003-09-16 Tue> 55 | syn match org_timestamp /\(<\d\d\d\d-\d\d-\d\d \k\k\k>\)/ 56 | "<2003-09-16 Tue 12:00> 57 | syn match org_timestamp /\(<\d\d\d\d-\d\d-\d\d \k\k\k \d\d:\d\d>\)/ 58 | "<2003-09-16 Tue 12:00-12:30> 59 | syn match org_timestamp /\(<\d\d\d\d-\d\d-\d\d \k\k\k \d\d:\d\d-\d\d:\d\d>\)/ 60 | "<2003-09-16 Tue>--<2003-09-16 Tue> 61 | syn match org_timestamp /\(<\d\d\d\d-\d\d-\d\d \k\k\k>--<\d\d\d\d-\d\d-\d\d \k\k\k>\)/ 62 | "<2003-09-16 Tue 12:00>--<2003-09-16 Tue 12:00> 63 | syn match org_timestamp /\(<\d\d\d\d-\d\d-\d\d \k\k\k \d\d:\d\d>--<\d\d\d\d-\d\d-\d\d \k\k\k \d\d:\d\d>\)/ 64 | syn match org_timestamp /\(<%%(diary-float.\+>\)/ 65 | hi def link org_timestamp PreProc 66 | 67 | " special words 68 | syn match today /TODAY$/ 69 | hi def link today PreProc 70 | 71 | syn match week_agenda /^Week Agenda:$/ 72 | hi def link week_agenda PreProc 73 | 74 | " Hyperlinks 75 | syntax match hyperlink "\[\{2}[^][]*\(\]\[[^][]*\)\?\]\{2}" contains=hyperlinkBracketsLeft,hyperlinkURL,hyperlinkBracketsRight containedin=ALL 76 | syntax match hyperlinkBracketsLeft contained "\[\{2}" conceal 77 | syntax match hyperlinkURL contained "[^][]*\]\[" conceal 78 | syntax match hyperlinkBracketsRight contained "\]\{2}" conceal 79 | hi def link hyperlink Underlined 80 | -------------------------------------------------------------------------------- /syntax/orgtodo.vim: -------------------------------------------------------------------------------- 1 | syn match org_todo_key /\[\zs[^]]*\ze\]/ 2 | hi def link org_todo_key Identifier 3 | 4 | let s:todo_headings = '' 5 | let s:i = 1 6 | while s:i <= g:org_heading_highlight_levels 7 | if s:todo_headings == '' 8 | let s:todo_headings = 'containedin=org_heading' . s:i 9 | else 10 | let s:todo_headings = s:todo_headings . ',org_heading' . s:i 11 | endif 12 | let s:i += 1 13 | endwhile 14 | unlet! s:i 15 | 16 | if !exists('g:loaded_orgtodo_syntax') 17 | let g:loaded_orgtodo_syntax = 1 18 | function! s:ReadTodoKeywords(keywords, todo_headings) 19 | let l:default_group = 'Todo' 20 | for l:i in a:keywords 21 | if type(l:i) == 3 22 | call s:ReadTodoKeywords(l:i, a:todo_headings) 23 | continue 24 | endif 25 | if l:i == '|' 26 | let l:default_group = 'Question' 27 | continue 28 | endif 29 | " strip access key 30 | let l:_i = substitute(l:i, "\(.*$", "", "") 31 | 32 | let l:group = l:default_group 33 | for l:j in g:org_todo_keyword_faces 34 | if l:j[0] == l:_i 35 | let l:group = 'orgtodo_todo_keyword_face_' . l:_i 36 | call OrgExtendHighlightingGroup(l:default_group, l:group, OrgInterpretFaces(l:j[1])) 37 | break 38 | endif 39 | endfor 40 | silent! exec 'syntax match orgtodo_todo_keyword_' . l:_i . ' /' . l:_i .'/ ' . a:todo_headings . ' contains=@NoSpell' 41 | silent! exec 'hi def link orgtodo_todo_keyword_' . l:_i . ' ' . l:group 42 | endfor 43 | endfunction 44 | endif 45 | 46 | call s:ReadTodoKeywords(g:org_todo_keywords, s:todo_headings) 47 | unlet! s:todo_headings 48 | -------------------------------------------------------------------------------- /tests/orgmode_testfile.org: -------------------------------------------------------------------------------- 1 | 2 | * bold, italics and underline syntax matching 3 | ** Should match: 4 | 5 | *foo* *foo* 6 | *Really, quite long sentence*. 7 | _foo_ _foo_ 8 | _really, quite long sentence._. 9 | 10 | *Übermensch á* *eä* *ý€* 11 | _Ÿ ï_ 12 | 13 | *sdf l.* 14 | *sdfsdf ,.* 15 | *foo_ sdf /* 16 | /sdf sdf sdf ./ 17 | 18 | /google.com/ 19 | 20 | *[sdf]* 21 | *a* /a/ =b= ~b~ `d` 22 | 23 | *abc* /abc/ =bde= ~bde~ `def` 24 | *=*a*=* 25 | ** Should not match 26 | http://google.com/ 27 | //google.com/ 28 | * sdf* _ sdf_ 29 | *sdfsdf sdf,* 30 | *foo * 31 | foo_not underlined_bar 32 | 33 | *.sdf*[ 34 | [*.sdf* 35 | [*sdf*] 36 | *=*a*= 37 | 38 | -------------------------------------------------------------------------------- /tests/run_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | 6 | import test_vimbuffer 7 | 8 | import test_libagendafilter 9 | import test_libcheckbox 10 | import test_libbase 11 | import test_libheading 12 | import test_liborgdate 13 | import test_liborgdate_utf8 14 | import test_liborgdate_parsing 15 | import test_liborgdatetime 16 | import test_liborgtimerange 17 | 18 | import test_plugin_date 19 | import test_plugin_edit_structure 20 | import test_plugin_edit_checkbox 21 | import test_plugin_misc 22 | import test_plugin_navigator 23 | import test_plugin_show_hide 24 | import test_plugin_tags_properties 25 | import test_plugin_todo 26 | import test_plugin_mappings 27 | 28 | if __name__ == '__main__': 29 | tests = unittest.TestSuite() 30 | 31 | tests.addTests(test_vimbuffer.suite()) 32 | 33 | # lib 34 | tests.addTests(test_libbase.suite()) 35 | tests.addTests(test_libcheckbox.suite()) 36 | tests.addTests(test_libagendafilter.suite()) 37 | tests.addTests(test_libheading.suite()) 38 | tests.addTests(test_liborgdate.suite()) 39 | tests.addTests(test_liborgdate_utf8.suite()) 40 | tests.addTests(test_liborgdate_parsing.suite()) 41 | tests.addTests(test_liborgdatetime.suite()) 42 | tests.addTests(test_liborgtimerange.suite()) 43 | 44 | # plugins 45 | tests.addTests(test_plugin_date.suite()) 46 | tests.addTests(test_plugin_edit_structure.suite()) 47 | tests.addTests(test_plugin_edit_checkbox.suite()) 48 | tests.addTests(test_plugin_misc.suite()) 49 | tests.addTests(test_plugin_navigator.suite()) 50 | tests.addTests(test_plugin_show_hide.suite()) 51 | tests.addTests(test_plugin_tags_properties.suite()) 52 | tests.addTests(test_plugin_todo.suite()) 53 | tests.addTests(test_plugin_mappings.suite()) 54 | 55 | runner = unittest.TextTestRunner() 56 | runner.run(tests) 57 | -------------------------------------------------------------------------------- /tests/test_libagendafilter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | import sys 5 | sys.path.append(u'../ftplugin') 6 | 7 | import unittest 8 | from datetime import date 9 | from datetime import timedelta 10 | 11 | from orgmode.liborgmode.headings import Heading 12 | from orgmode.liborgmode.orgdate import OrgDate 13 | from orgmode.liborgmode.agendafilter import contains_active_todo 14 | from orgmode.liborgmode.agendafilter import contains_active_date 15 | from orgmode.liborgmode.orgdate import OrgDateTime 16 | from orgmode.liborgmode.agendafilter import is_within_week 17 | from orgmode.liborgmode.agendafilter import is_within_week_and_active_todo 18 | from orgmode.liborgmode.agendafilter import filter_items 19 | 20 | import vim 21 | 22 | from orgmode.py3compat.encode_compatibility import * 23 | 24 | counter = 0 25 | 26 | class AgendaFilterTestCase(unittest.TestCase): 27 | u"""Tests all the functionality of the Agenda filter module.""" 28 | 29 | def setUp(self): 30 | global counter 31 | counter += 1 32 | 33 | vim.EVALHISTORY = [] 34 | vim.EVALRESULTS = { 35 | # no org_todo_keywords for b 36 | u_encode(u'exists("b:org_todo_keywords")'): u_encode('0'), 37 | # global values for org_todo_keywords 38 | u_encode(u'exists("g:org_todo_keywords")'): u_encode('1'), 39 | u_encode(u'g:org_todo_keywords'): [u_encode(u'TODO'), u_encode(u'|'), u_encode(u'DONE')], 40 | u_encode(u'exists("g:org_debug")'): u_encode(u'0'), 41 | u_encode(u'exists("b:org_debug")'): u_encode(u'0'), 42 | u_encode(u'exists("*repeat#set()")'): u_encode(u'0'), 43 | u_encode(u'b:changedtick'): u_encode(u'%d' % counter), 44 | u_encode(u"v:count"): u_encode(u'0') 45 | } 46 | vim.current.buffer[:] = [u_encode(i) for i in u""" 47 | * TODO Heading 1 48 | some text 49 | """.split(u'\n')] 50 | 51 | def test_contains_active_todo(self): 52 | heading = Heading(title=u'Refactor the code', todo='TODO') 53 | self.assertTrue(contains_active_todo(heading)) 54 | 55 | heading = Heading(title=u'Refactor the code', todo='DONE') 56 | self.assertFalse(contains_active_todo(heading)) 57 | 58 | heading = Heading(title=u'Refactor the code', todo=None) 59 | self.assertFalse(contains_active_todo(heading)) 60 | 61 | def test_contains_active_date(self): 62 | heading = Heading(title=u'Refactor the code', active_date=None) 63 | self.assertFalse(contains_active_date(heading)) 64 | 65 | odate = OrgDate(True, 2011, 11, 1) 66 | heading = Heading(title=u'Refactor the code', active_date=odate) 67 | self.assertTrue(contains_active_date(heading)) 68 | 69 | def test_is_within_week_with_orgdate(self): 70 | # to far in the future 71 | tmpdate = date.today() + timedelta(days=8) 72 | odate = OrgDate(True, tmpdate.year, tmpdate.month, tmpdate.day) 73 | heading = Heading(title=u'Refactor the code', active_date=odate) 74 | self.assertFalse(is_within_week(heading)) 75 | 76 | # within a week 77 | tmpdate = date.today() + timedelta(days=5) 78 | odate = OrgDate(True, tmpdate.year, tmpdate.month, tmpdate.day) 79 | heading = Heading(title=u'Refactor the code', active_date=odate) 80 | self.assertTrue(is_within_week(heading)) 81 | 82 | # in the past 83 | tmpdate = date.today() - timedelta(days=105) 84 | odate = OrgDate(True, tmpdate.year, tmpdate.month, tmpdate.day) 85 | heading = Heading(title=u'Refactor the code', active_date=odate) 86 | self.assertTrue(is_within_week(heading)) 87 | 88 | def test_is_within_week_with_orgdatetime(self): 89 | # to far in the future 90 | tmp = date.today() + timedelta(days=1000) 91 | odate = OrgDateTime(True, tmp.year, tmp.month, tmp.day, 10, 10) 92 | heading = Heading(title=u'Refactor the code', active_date=odate) 93 | self.assertFalse(is_within_week(heading)) 94 | 95 | # within a week 96 | tmpdate = date.today() + timedelta(days=5) 97 | odate = OrgDateTime(True, tmpdate.year, tmpdate.month, tmpdate.day, 1, 0) 98 | heading = Heading(title=u'Refactor the code', active_date=odate) 99 | self.assertTrue(is_within_week(heading)) 100 | 101 | # in the past 102 | tmpdate = date.today() - timedelta(days=5) 103 | odate = OrgDateTime(True, tmpdate.year, tmpdate.month, tmpdate.day, 1, 0) 104 | heading = Heading(title=u'Refactor the code', active_date=odate) 105 | self.assertTrue(is_within_week(heading)) 106 | 107 | def test_filter_items(self): 108 | # only headings with date and todo should be returned 109 | vim.EVALRESULTS[u_encode(u'g:org_todo_keywords')] = \ 110 | [u_encode(u'TODO'), u_encode(u'STARTED'), u_encode(u'|'), u_encode(u'DONE')] 111 | tmpdate = date.today() 112 | odate = OrgDate(True, tmpdate.year, tmpdate.month, tmpdate.day) 113 | tmp_head = Heading(title=u'Refactor the code', todo=u'TODO', active_date=odate) 114 | tmp_head_01 = Heading(title=u'Refactor the code', todo=u'STARTED', active_date=odate) 115 | # TODO add more tests 116 | headings = [tmp_head, tmp_head_01] 117 | filtered = list(filter_items(headings, 118 | [contains_active_date, contains_active_todo])) 119 | 120 | self.assertEqual(len(filtered), 2) 121 | self.assertEqual(filtered, headings) 122 | 123 | # try a longer list 124 | headings = headings * 3 125 | filtered = list(filter_items(headings, 126 | [contains_active_date, contains_active_todo])) 127 | 128 | self.assertEqual(len(filtered), 6) 129 | self.assertEqual(filtered, headings) 130 | 131 | # date does not contain all needed fields thus gets ignored 132 | tmpdate = date.today() 133 | odate = OrgDate(True, tmpdate.year, tmpdate.month, tmpdate.day) 134 | tmp_head = Heading(title=u'Refactor the code', active_date=odate) 135 | headings = [tmp_head] 136 | filtered = list(filter_items(headings, [contains_active_date, 137 | contains_active_todo])) 138 | self.assertEqual([], filtered) 139 | 140 | def test_filter_items_with_some_todos_and_dates(self): 141 | u""" 142 | Only the headings with todo and dates should be returned. 143 | """ 144 | tmp = [u"* TODO OrgMode Demo und Tests" 145 | u"<2011-08-22 Mon>"] 146 | headings = [Heading.parse_heading_from_data(tmp, [u'TODO'])] 147 | filtered = list(filter_items(headings, 148 | [is_within_week_and_active_todo])) 149 | self.assertEqual(len(filtered), 1) 150 | self.assertEqual(headings, filtered) 151 | 152 | tmp = [Heading.parse_heading_from_data([u"** DONE something <2011-08-10 Wed>"], [u'TODO']), 153 | Heading.parse_heading_from_data([u"*** TODO rsitenaoritns more <2011-08-25 Thu>"], [u'TODO']), 154 | Heading.parse_heading_from_data([u"*** DONE some more <2011-08-25 Thu>"], [u'TODO']), 155 | Heading.parse_heading_from_data([u"*** TODO some more <2011-08-25 Thu>"], [u'TODO']), 156 | Heading.parse_heading_from_data([u"** DONE something2 <2011-08-10 Wed>"], [u'TODO']) 157 | ] 158 | for h in tmp: 159 | headings.append(h) 160 | 161 | filtered = list(filter_items(headings, 162 | [is_within_week_and_active_todo])) 163 | self.assertEqual(len(filtered), 3) 164 | self.assertEqual(filtered, [headings[0], headings[2], headings[4]]) 165 | 166 | 167 | def suite(): 168 | return unittest.TestLoader().loadTestsFromTestCase(AgendaFilterTestCase) 169 | -------------------------------------------------------------------------------- /tests/test_libbase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | import sys 5 | sys.path.append(u'../ftplugin') 6 | 7 | from orgmode.liborgmode.base import Direction, get_domobj_range 8 | from orgmode.liborgmode.headings import Heading 9 | 10 | 11 | class LibBaseTestCase(unittest.TestCase): 12 | 13 | def setUp(self): 14 | self.case1 = """ 15 | * head1 16 | heading body 17 | for testing 18 | * head2 19 | ** head3 20 | """.split("\n") 21 | 22 | def test_base_functions(self): 23 | # direction FORWARD 24 | (start, end) = get_domobj_range(content=self.case1, position=1, identify_fun=Heading.identify_heading) 25 | self.assertEqual((start, end), (1, 3)) 26 | (start, end) = get_domobj_range(content=self.case1, position=3, direction=Direction.BACKWARD, \ 27 | identify_fun=Heading.identify_heading) 28 | self.assertEqual((start, end), (1, 3)) 29 | 30 | def suite(): 31 | return unittest.TestLoader() \ 32 | .loadTestsFromTestCase( 33 | LibBaseTestCase) 34 | -------------------------------------------------------------------------------- /tests/test_libcheckbox.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | import sys 5 | sys.path.append(u'../ftplugin') 6 | 7 | import vim 8 | from orgmode.liborgmode.checkboxes import Checkbox 9 | from orgmode._vim import ORGMODE 10 | 11 | from orgmode.py3compat.encode_compatibility import * 12 | 13 | def set_vim_buffer(buf=None, cursor=(2, 0), bufnr=0): 14 | if buf is None: 15 | buf = [] 16 | vim.current.buffer[:] = buf 17 | vim.current.window.cursor = cursor 18 | vim.current.buffer.number = bufnr 19 | 20 | 21 | class CheckboxTestCase(unittest.TestCase): 22 | 23 | def setUp(self): 24 | counter = 0 25 | vim.CMDHISTORY = [] 26 | vim.CMDRESULTS = {} 27 | vim.EVALHISTORY = [] 28 | vim.EVALRESULTS = { 29 | # no org_todo_keywords for b 30 | u_encode(u'exists("b:org_todo_keywords")'): u_encode('0'), 31 | # global values for org_todo_keywords 32 | u_encode(u'exists("g:org_todo_keywords")'): u_encode('1'), 33 | u_encode(u'g:org_todo_keywords'): [u_encode(u'TODO'), u_encode(u'|'), u_encode(u'DONE')], 34 | u_encode(u'exists("g:org_improve_split_heading")'): u_encode(u'0'), 35 | u_encode(u'exists("b:org_improve_split_heading")'): u_encode(u'0'), 36 | u_encode(u'exists("g:org_debug")'): u_encode(u'0'), 37 | u_encode(u'exists("b:org_debug")'): u_encode(u'0'), 38 | u_encode(u'exists("*repeat#set()")'): u_encode(u'0'), 39 | u_encode(u'b:changedtick'): u_encode(u'%d' % counter), 40 | u_encode(u'&ts'): u_encode(u'8'), 41 | u_encode(u'exists("g:org_tag_column")'): u_encode(u'0'), 42 | u_encode(u'exists("b:org_tag_column")'): u_encode(u'0'), 43 | u_encode(u"v:count"): u_encode(u'0')} 44 | 45 | self.c1 = """ 46 | * heading1 [/] 47 | - [-] checkbox1 [%] 48 | - [X] checkbox2 49 | - [ ] checkbox3 50 | - [X] checkbox4 51 | """.split("\n") 52 | 53 | self.c2 = """ 54 | * heading1 55 | - [ ] checkbox1 56 | - [ ] checkbox2 57 | - [ ] checkbox3 58 | - [ ] checkbox4 59 | - [ ] checkbox5 60 | - [ ] checkbox6 61 | """.split("\n") 62 | 63 | def test_init(self): 64 | # test initialize Checkbox 65 | c = Checkbox(level=1, title="checkbox1") 66 | self.assertEqual(str(c), " - [ ] checkbox1") 67 | c = Checkbox(level=3, title="checkbox2", status="[X]") 68 | self.assertEqual(str(c), " - [X] checkbox2") 69 | 70 | def test_basic(self): 71 | bufnr = 1 72 | set_vim_buffer(buf=self.c1, bufnr=bufnr) 73 | h = ORGMODE.get_document(bufnr=bufnr).current_heading() 74 | h.init_checkboxes() 75 | 76 | c = h.current_checkbox(position=2) 77 | self.assertEqual(str(c), self.c1[2]) 78 | self.assertFalse(c.are_children_all(Checkbox.STATUS_ON)) 79 | self.assertTrue(c.is_child_one(Checkbox.STATUS_OFF)) 80 | self.assertFalse(c.are_siblings_all(Checkbox.STATUS_ON)) 81 | 82 | for child in c.all_children(): 83 | pass 84 | for sibling in c.all_siblings(): 85 | pass 86 | c = h.current_checkbox(position=3) 87 | new_checkbox = c.copy() 88 | self.assertEqual(str(c), self.c1[3]) 89 | c.get_parent_list() 90 | c.get_index_in_parent_list() 91 | 92 | def test_identify(self): 93 | # test identify_checkbox 94 | self.assertEqual(Checkbox.identify_checkbox(self.c1[2]), 2) 95 | self.assertEqual(Checkbox.identify_checkbox(self.c1[3]), 8) 96 | # check for corner case 97 | self.assertEqual(Checkbox.identify_checkbox(" - [ ]"), 1) 98 | 99 | def test_toggle(self): 100 | bufnr = 2 101 | # test init_checkboxes 102 | set_vim_buffer(buf=self.c1, bufnr=bufnr) 103 | h = ORGMODE.get_document(bufnr=bufnr).current_heading() 104 | h.init_checkboxes() 105 | 106 | # toggle checkbox 107 | c = h.current_checkbox(position=4) 108 | c.toggle() 109 | self.assertEqual(str(c), " - [X] checkbox3") 110 | c.toggle() 111 | self.assertEqual(str(c), " - [ ] checkbox3") 112 | 113 | (total, on) = c.all_siblings_status() 114 | self.assertEqual((total, on), (2, 1)) 115 | 116 | def test_subtasks(self): 117 | bufnr = 3 118 | set_vim_buffer(buf=self.c1, bufnr=bufnr) 119 | h = ORGMODE.get_document(bufnr=bufnr).current_heading() 120 | h.init_checkboxes() 121 | c = h.current_checkbox(position=3) 122 | c.toggle() 123 | c = h.current_checkbox(position=2) 124 | (total, on) = c.all_siblings_status() 125 | c.update_subtasks(total=total, on=on) 126 | self.assertEqual(str(c), " - [-] checkbox1 [50%]") 127 | 128 | 129 | def suite(): 130 | return unittest.TestLoader().loadTestsFromTestCase(CheckboxTestCase) 131 | -------------------------------------------------------------------------------- /tests/test_libheading.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | import sys 5 | sys.path.append(u'../ftplugin') 6 | 7 | from orgmode.liborgmode.headings import Heading 8 | from orgmode.liborgmode.orgdate import OrgDate 9 | from orgmode.liborgmode.orgdate import OrgDateTime 10 | 11 | 12 | class TestHeadingRecognizeDatesInHeading(unittest.TestCase): 13 | 14 | def setUp(self): 15 | self.allowed_todo_states = ["TODO"] 16 | 17 | tmp = ["* This heading is earlier <2011-08-24 Wed>"] 18 | self.h1 = Heading.parse_heading_from_data(tmp, self.allowed_todo_states) 19 | 20 | tmp = ["* This heading is later <2011-08-25 Thu>"] 21 | self.h2 = Heading.parse_heading_from_data(tmp, self.allowed_todo_states) 22 | 23 | tmp = ["* This heading is later <2011-08-25 Thu 10:20>"] 24 | self.h2_datetime = Heading.parse_heading_from_data(tmp, self.allowed_todo_states) 25 | 26 | tmp = ["* This heading is later <2011-08-26 Fri 10:20>"] 27 | self.h3 = Heading.parse_heading_from_data(tmp, self.allowed_todo_states) 28 | 29 | tmp = ["* This heading has no date and should be later than the rest"] 30 | self.h_no_date = Heading.parse_heading_from_data(tmp, 31 | self.allowed_todo_states) 32 | 33 | def test_heading_parsing_no_date(self): 34 | """"" 35 | 'text' doesn't contain any valid date. 36 | """ 37 | text = ["* TODO This is a test :hallo:"] 38 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 39 | self.assertEqual(None, h.active_date) 40 | 41 | text = ["* TODO This is a test <2011-08-25>"] 42 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 43 | self.assertEqual(None, h.active_date) 44 | 45 | text = ["* TODO This is a test <2011-08-25 Wednesday>"] 46 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 47 | self.assertEqual(None, h.active_date) 48 | 49 | text = ["* TODO This is a test <20110825>"] 50 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 51 | self.assertEqual(None, h.active_date) 52 | 53 | def test_heading_parsing_with_date(self): 54 | """"" 55 | 'text' does contain valid dates. 56 | """ 57 | # orgdate 58 | text = ["* TODO This is a test <2011-08-24 Wed> :hallo:"] 59 | odate = OrgDate(True, 2011, 8, 24) 60 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 61 | self.assertEqual(odate, h.active_date) 62 | 63 | # orgdatetime 64 | text = ["* TODO This is a test <2011-08-25 Thu 10:10> :hallo:"] 65 | odate = OrgDateTime(True, 2011, 8, 25, 10, 10) 66 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 67 | self.assertEqual(odate, h.active_date) 68 | 69 | def test_heading_parsing_with_date_and_body(self): 70 | """"" 71 | 'text' contains valid dates (in the body). 72 | """ 73 | # orgdatetime 74 | text = ["* TODO This is a test <2011-08-25 Thu 10:10> :hallo:", 75 | "some body text", 76 | "some body text"] 77 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 78 | self.assertTrue(isinstance(h.active_date, OrgDateTime)) 79 | self.assertEqual("<2011-08-25 Thu 10:10>", str(h.active_date)) 80 | 81 | text = ["* TODO This is a test :hallo:", 82 | "some body text", 83 | "some body text<2011-08-25 Thu 10:10>"] 84 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 85 | self.assertTrue(isinstance(h.active_date, OrgDateTime)) 86 | self.assertEqual("<2011-08-25 Thu 10:10>", str(h.active_date)) 87 | 88 | text = ["* TODO This is a test :hallo:", 89 | "some body text <2011-08-24 Wed>", 90 | "some body text<2011-08-25 Thu 10:10>"] 91 | h = Heading.parse_heading_from_data(text, self.allowed_todo_states) 92 | odate = OrgDate(True, 2011, 8, 24) 93 | self.assertEqual(odate, h.active_date) 94 | 95 | def test_less_than_for_dates_in_heading(self): 96 | self.assertTrue(self.h1 < self.h2) 97 | self.assertTrue(self.h1 < self.h3) 98 | self.assertTrue(self.h1 < self.h_no_date) 99 | self.assertTrue(self.h2 < self.h_no_date) 100 | self.assertTrue(self.h2 < self.h3) 101 | self.assertTrue(self.h3 < self.h_no_date) 102 | 103 | self.assertFalse(self.h2 < self.h1) 104 | self.assertFalse(self.h3 < self.h2) 105 | 106 | def test_less_equal_for_dates_in_heading(self): 107 | self.assertTrue(self.h1 <= self.h2) 108 | self.assertTrue(self.h1 <= self.h_no_date) 109 | self.assertTrue(self.h2 <= self.h_no_date) 110 | self.assertTrue(self.h2 <= self.h2_datetime) 111 | self.assertTrue(self.h2 <= self.h3) 112 | 113 | def test_greate_than_for_dates_in_heading(self): 114 | self.assertTrue(self.h2 > self.h1) 115 | self.assertTrue(self.h_no_date > self.h1) 116 | self.assertTrue(self.h_no_date > self.h2) 117 | 118 | self.assertFalse(self.h2 > self.h2_datetime) 119 | 120 | def test_greate_equal_for_dates_in_heading(self): 121 | self.assertTrue(self.h2 >= self.h1) 122 | self.assertTrue(self.h_no_date >= self.h1) 123 | self.assertTrue(self.h_no_date >= self.h2) 124 | self.assertTrue(self.h2 >= self.h2_datetime) 125 | 126 | def test_sorting_of_headings(self): 127 | """Headings should be sortable.""" 128 | self.assertEqual([self.h1, self.h2], sorted([self.h2, self.h1])) 129 | 130 | self.assertEqual([self.h1, self.h2_datetime], 131 | sorted([self.h2_datetime, self.h1])) 132 | 133 | self.assertEqual([self.h2_datetime, self.h2], 134 | sorted([self.h2_datetime, self.h2])) 135 | 136 | self.assertEqual([self.h1, self.h2], sorted([self.h1, self.h2])) 137 | 138 | self.assertEqual([self.h1, self.h_no_date], 139 | sorted([self.h1, self.h_no_date])) 140 | 141 | self.assertEqual([self.h1, self.h_no_date], 142 | sorted([self.h_no_date, self.h1])) 143 | 144 | self.assertEqual([self.h1, self.h2, self.h_no_date], 145 | sorted([self.h2, self.h_no_date, self.h1])) 146 | 147 | self.assertEqual( 148 | [self.h1, self.h2_datetime, self.h2, self.h3, self.h_no_date], 149 | sorted([self.h2_datetime, self.h3, self.h2, self.h_no_date, self.h1])) 150 | 151 | 152 | def suite(): 153 | return unittest.TestLoader().loadTestsFromTestCase( 154 | TestHeadingRecognizeDatesInHeading) 155 | -------------------------------------------------------------------------------- /tests/test_liborgdate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | import sys 5 | import unittest 6 | from datetime import date 7 | 8 | sys.path.append(u'../ftplugin') 9 | from orgmode.liborgmode.orgdate import OrgDate 10 | 11 | from orgmode.py3compat.unicode_compatibility import * 12 | 13 | class OrgDateTestCase(unittest.TestCase): 14 | u""" 15 | Tests all the functionality of the OrgDate 16 | """ 17 | 18 | def setUp(self): 19 | self.date = date(2011, 8, 29) 20 | self.year = 2011 21 | self.month = 8 22 | self.day = 29 23 | self.text = u'<2011-08-29 Mon>' 24 | self.textinactive = u'[2011-08-29 Mon]' 25 | 26 | def test_OrgDate_ctor_active(self): 27 | u"""OrdDate should be created.""" 28 | today = date.today() 29 | od = OrgDate(True, today.year, today.month, today.day) 30 | self.assertTrue(isinstance(od, OrgDate)) 31 | self.assertTrue(od.active) 32 | 33 | def test_OrgDate_ctor_inactive(self): 34 | u"""OrdDate should be created.""" 35 | today = date.today() 36 | od = OrgDate(False, today.year, today.month, today.day) 37 | self.assertTrue(isinstance(od, OrgDate)) 38 | self.assertFalse(od.active) 39 | 40 | def test_OrdDate_str_active(self): 41 | u"""Representation of OrgDates""" 42 | od = OrgDate(True, self.year, self.month, self.day) 43 | self.assertEqual(self.text, unicode(od)) 44 | 45 | def test_OrdDate_str_inactive(self): 46 | od = OrgDate(False, self.year, self.month, self.day) 47 | self.assertEqual(self.textinactive, unicode(od)) 48 | 49 | 50 | def suite(): 51 | return unittest.TestLoader().loadTestsFromTestCase(OrgDateTestCase) 52 | -------------------------------------------------------------------------------- /tests/test_liborgdate_parsing.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | import sys 5 | import unittest 6 | 7 | sys.path.append(u'../ftplugin') 8 | from orgmode.liborgmode.orgdate import get_orgdate 9 | from orgmode.liborgmode.orgdate import OrgDate 10 | from orgmode.liborgmode.orgdate import OrgDateTime 11 | from orgmode.liborgmode.orgdate import OrgTimeRange 12 | 13 | from orgmode.py3compat.unicode_compatibility import * 14 | 15 | class OrgDateParsingTestCase(unittest.TestCase): 16 | u""" 17 | Tests the functionality of the parsing function of OrgDate. 18 | 19 | Mostly function get_orgdate(). 20 | """ 21 | 22 | def setUp(self): 23 | self.text = u'<2011-08-29 Mon>' 24 | self.textinactive = u'[2011-08-29 Mon]' 25 | 26 | def test_get_orgdate_parsing_active(self): 27 | u""" 28 | get_orgdate should recognize all orgdates in a given text 29 | """ 30 | result = get_orgdate(self.text) 31 | self.assertNotEqual(result, None) 32 | self.assertTrue(isinstance(result, OrgDate)) 33 | self.assertTrue(isinstance(get_orgdate(u"<2011-08-30 Tue>"), OrgDate)) 34 | self.assertEqual(get_orgdate(u"<2011-08-30 Tue>").year, 2011) 35 | self.assertEqual(get_orgdate(u"<2011-08-30 Tue>").month, 8) 36 | self.assertEqual(get_orgdate(u"<2011-08-30 Tue>").day, 30) 37 | self.assertTrue(get_orgdate(u"<2011-08-30 Tue>").active) 38 | 39 | datestr = u"This date <2011-08-30 Tue> is embedded" 40 | self.assertTrue(isinstance(get_orgdate(datestr), OrgDate)) 41 | 42 | 43 | def test_get_orgdatetime_parsing_active(self): 44 | u""" 45 | get_orgdate should recognize all orgdatetimes in a given text 46 | """ 47 | result = get_orgdate(u"<2011-09-12 Mon 10:20>") 48 | self.assertNotEqual(result, None) 49 | self.assertTrue(isinstance(result, OrgDateTime)) 50 | self.assertEqual(result.year, 2011) 51 | self.assertEqual(result.month, 9) 52 | self.assertEqual(result.day, 12) 53 | self.assertEqual(result.hour, 10) 54 | self.assertEqual(result.minute, 20) 55 | self.assertTrue(result.active) 56 | 57 | result = get_orgdate(u"some datetime <2011-09-12 Mon 10:20> stuff") 58 | self.assertTrue(isinstance(result, OrgDateTime)) 59 | 60 | 61 | def test_get_orgtimerange_parsing_active(self): 62 | u""" 63 | get_orgdate should recognize all orgtimeranges in a given text 64 | """ 65 | daterangestr = u"<2011-09-12 Mon>--<2011-09-13 Tue>" 66 | result = get_orgdate(daterangestr) 67 | self.assertNotEqual(result, None) 68 | self.assertTrue(isinstance(result, OrgTimeRange)) 69 | self.assertEqual(unicode(result), daterangestr) 70 | self.assertTrue(result.active) 71 | 72 | daterangestr = u"<2011-09-12 Mon 10:20>--<2011-09-13 Tue 13:20>" 73 | result = get_orgdate(daterangestr) 74 | self.assertNotEqual(result, None) 75 | self.assertTrue(isinstance(result, OrgTimeRange)) 76 | self.assertEqual(unicode(result), daterangestr) 77 | self.assertTrue(result.active) 78 | 79 | daterangestr = u"<2011-09-12 Mon 10:20-13:20>" 80 | result = get_orgdate(daterangestr) 81 | self.assertNotEqual(result, None) 82 | self.assertTrue(isinstance(result, OrgTimeRange)) 83 | self.assertEqual(unicode(result), daterangestr) 84 | self.assertTrue(result.active) 85 | 86 | def test_get_orgdate_parsing_inactive(self): 87 | u""" 88 | get_orgdate should recognize all inactive orgdates in a given text 89 | """ 90 | result = get_orgdate(self.textinactive) 91 | self.assertNotEqual(result, None) 92 | self.assertTrue(isinstance(result, OrgDate)) 93 | self.assertTrue(isinstance(get_orgdate(u"[2011-08-30 Tue]"), OrgDate)) 94 | self.assertEqual(get_orgdate(u"[2011-08-30 Tue]").year, 2011) 95 | self.assertEqual(get_orgdate(u"[2011-08-30 Tue]").month, 8) 96 | self.assertEqual(get_orgdate(u"[2011-08-30 Tue]").day, 30) 97 | self.assertFalse(get_orgdate(u"[2011-08-30 Tue]").active) 98 | 99 | datestr = u"This date [2011-08-30 Tue] is embedded" 100 | self.assertTrue(isinstance(get_orgdate(datestr), OrgDate)) 101 | 102 | def test_get_orgdatetime_parsing_passive(self): 103 | u""" 104 | get_orgdate should recognize all orgdatetimes in a given text 105 | """ 106 | result = get_orgdate(u"[2011-09-12 Mon 10:20]") 107 | self.assertNotEqual(result, None) 108 | self.assertTrue(isinstance(result, OrgDateTime)) 109 | self.assertEqual(result.year, 2011) 110 | self.assertEqual(result.month, 9) 111 | self.assertEqual(result.day, 12) 112 | self.assertEqual(result.hour, 10) 113 | self.assertEqual(result.minute, 20) 114 | self.assertFalse(result.active) 115 | 116 | result = get_orgdate(u"some datetime [2011-09-12 Mon 10:20] stuff") 117 | self.assertTrue(isinstance(result, OrgDateTime)) 118 | 119 | def test_get_orgdate_parsing_with_list_of_texts(self): 120 | u""" 121 | get_orgdate should return the first date in the list. 122 | """ 123 | datelist = [u"<2011-08-29 Mon>"] 124 | result = get_orgdate(datelist) 125 | self.assertNotEquals(result, None) 126 | self.assertTrue(isinstance(result, OrgDate)) 127 | self.assertEqual(result.year, 2011) 128 | self.assertEqual(result.month, 8) 129 | self.assertEqual(result.day, 29) 130 | 131 | datelist = [u"<2011-08-29 Mon>", 132 | u"<2012-03-30 Fri>"] 133 | result = get_orgdate(datelist) 134 | self.assertNotEquals(result, None) 135 | self.assertTrue(isinstance(result, OrgDate)) 136 | self.assertEqual(result.year, 2011) 137 | self.assertEqual(result.month, 8) 138 | self.assertEqual(result.day, 29) 139 | 140 | datelist = [u"some <2011-08-29 Mon>text", 141 | u"<2012-03-30 Fri> is here"] 142 | result = get_orgdate(datelist) 143 | self.assertNotEquals(result, None) 144 | self.assertTrue(isinstance(result, OrgDate)) 145 | self.assertEqual(result.year, 2011) 146 | self.assertEqual(result.month, 8) 147 | self.assertEqual(result.day, 29) 148 | 149 | datelist = [u"here is no date", 150 | u"some <2011-08-29 Mon>text", 151 | u"<2012-03-30 Fri> is here"] 152 | result = get_orgdate(datelist) 153 | self.assertNotEquals(result, None) 154 | self.assertTrue(isinstance(result, OrgDate)) 155 | self.assertEqual(result.year, 2011) 156 | self.assertEqual(result.month, 8) 157 | self.assertEqual(result.day, 29) 158 | 159 | datelist = [u"here is no date", 160 | u"some <2011-08-29 Mon 20:10> text", 161 | u"<2012-03-30 Fri> is here"] 162 | result = get_orgdate(datelist) 163 | self.assertNotEquals(result, None) 164 | self.assertTrue(isinstance(result, OrgDateTime)) 165 | self.assertEqual(result.year, 2011) 166 | self.assertEqual(result.month, 8) 167 | self.assertEqual(result.day, 29) 168 | self.assertEqual(result.hour, 20) 169 | self.assertEqual(result.minute, 10) 170 | 171 | def test_get_orgdate_parsing_with_invalid_input(self): 172 | self.assertEquals(get_orgdate(u"NONSENSE"), None) 173 | self.assertEquals(get_orgdate(u"No D<2011- Date 08-29 Mon>"), None) 174 | self.assertEquals(get_orgdate(u"2011-08-r9 Mon]"), None) 175 | self.assertEquals(get_orgdate(u"<2011-08-29 Mon"), None) 176 | self.assertEquals(get_orgdate(u"<2011-08-29 Mon]"), None) 177 | self.assertEquals(get_orgdate(u"2011-08-29 Mon"), None) 178 | self.assertEquals(get_orgdate(u"2011-08-29"), None) 179 | self.assertEquals(get_orgdate(u"2011-08-29 mon"), None) 180 | self.assertEquals(get_orgdate(u"<2011-08-29 mon>"), None) 181 | 182 | self.assertEquals(get_orgdate(u"wrong date embedded <2011-08-29 mon>"), None) 183 | self.assertEquals(get_orgdate(u"wrong date <2011-08-29 mon>embedded "), None) 184 | 185 | def test_get_orgdate_parsing_with_invalid_dates(self): 186 | u""" 187 | Something like <2011-14-29 Mon> (invalid dates, they don't exist) 188 | should not be parsed 189 | """ 190 | datestr = u"<2011-14-30 Tue>" 191 | self.assertEqual(get_orgdate(datestr), None) 192 | 193 | datestr = u"<2012-03-40 Tue>" 194 | self.assertEqual(get_orgdate(datestr), None) 195 | 196 | datestr = u"<2012-03-40 Tue 24:70>" 197 | self.assertEqual(get_orgdate(datestr), None) 198 | 199 | def test_get_orgdate_parsing_with_utf8(self): 200 | u""" 201 | get_orgdate should recognize all orgdates within a given utf-8 text 202 | """ 203 | result = get_orgdate(u'<2016-05-07 Sáb>') 204 | self.assertNotEqual(result, None) 205 | self.assertTrue(isinstance(result, OrgDate)) 206 | self.assertEqual(result.year, 2016) 207 | self.assertEqual(result.month, 5) 208 | self.assertEqual(result.day, 7) 209 | self.assertTrue(result.active) 210 | 211 | datestr = u"This date <2016-05-07 Sáb> is embedded" 212 | self.assertTrue(isinstance(get_orgdate(datestr), OrgDate)) 213 | 214 | result = get_orgdate(u'[2016-05-07 Sáb]') 215 | self.assertFalse(result.active) 216 | 217 | datestr = u"This date [2016-05-07 Sáb] is embedded" 218 | self.assertTrue(isinstance(get_orgdate(datestr), OrgDate)) 219 | 220 | def test_get_orgdatetime_parsing_with_utf8(self): 221 | u""" 222 | get_orgdate should recognize all orgdatetimes in a given utf-8 text 223 | """ 224 | result = get_orgdate(u"<2016-05-07 Sáb 10:20>") 225 | self.assertNotEqual(result, None) 226 | self.assertTrue(isinstance(result, OrgDateTime)) 227 | self.assertEqual(result.year, 2016) 228 | self.assertEqual(result.month, 5) 229 | self.assertEqual(result.day, 7) 230 | self.assertEqual(result.hour, 10) 231 | self.assertEqual(result.minute, 20) 232 | self.assertTrue(result.active) 233 | 234 | result = get_orgdate(u"some datetime <2016-05-07 Sáb 10:20> stuff") 235 | self.assertTrue(isinstance(result, OrgDateTime)) 236 | 237 | result = get_orgdate(u"[2016-05-07 Sáb 10:20]") 238 | self.assertFalse(result.active) 239 | 240 | result = get_orgdate(u"some datetime [2016-05-07 Sáb 10:20] stuff") 241 | self.assertTrue(isinstance(result, OrgDateTime)) 242 | 243 | 244 | 245 | def suite(): 246 | return unittest.TestLoader().loadTestsFromTestCase(OrgDateParsingTestCase) 247 | -------------------------------------------------------------------------------- /tests/test_liborgdate_utf8.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | import unittest 5 | import locale 6 | import threading 7 | 8 | from datetime import date 9 | from contextlib import contextmanager 10 | 11 | from orgmode.py3compat.unicode_compatibility import * 12 | 13 | sys.path.append(u'../ftplugin') 14 | from orgmode.liborgmode.orgdate import OrgDate 15 | 16 | class OrgDateUtf8TestCase(unittest.TestCase): 17 | u""" 18 | Tests OrgDate with utf-8 enabled locales 19 | """ 20 | LOCALE_LOCK = threading.Lock() 21 | UTF8_LOCALE = "fr_FR.utf-8" 22 | 23 | @contextmanager 24 | def setlocale(self, name): 25 | with self.LOCALE_LOCK: 26 | saved = locale.setlocale(locale.LC_ALL) 27 | try: 28 | yield locale.setlocale(locale.LC_ALL, name) 29 | finally: 30 | locale.setlocale(locale.LC_ALL, saved) 31 | 32 | def setUp(self): 33 | self.year = 2016 34 | self.month = 5 35 | self.day = 7 36 | self.text = u'<2016-05-07 sam.>' 37 | self.textinactive = u'[2016-05-07 sam.]' 38 | 39 | def test_OrdDate_str_unicode_active(self): 40 | with self.setlocale(self.UTF8_LOCALE): 41 | od = OrgDate(True, self.year, self.month, self.day) 42 | self.assertEqual(self.text, unicode(od)) 43 | 44 | def test_OrdDate_str_unicode_inactive(self): 45 | with self.setlocale(self.UTF8_LOCALE): 46 | od = OrgDate(False, self.year, self.month, self.day) 47 | self.assertEqual(self.textinactive, unicode(od)) 48 | 49 | def suite(): 50 | return unittest.TestLoader().loadTestsFromTestCase(OrgDateUtf8TestCase) 51 | -------------------------------------------------------------------------------- /tests/test_liborgdatetime.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | import unittest 5 | from datetime import datetime 6 | 7 | sys.path.append(u'../ftplugin') 8 | from orgmode.liborgmode.orgdate import OrgDateTime 9 | 10 | from orgmode.py3compat.unicode_compatibility import * 11 | 12 | class OrgDateTimeTestCase(unittest.TestCase): 13 | u""" 14 | Tests all the functionality of the OrgDateTime 15 | """ 16 | 17 | def test_OrgDateTime_ctor_active(self): 18 | u"""OrdDateTime should be created.""" 19 | today = datetime.today() 20 | odt = OrgDateTime(True, today.year, today.month, today.day, today.hour, 21 | today.minute) 22 | self.assertTrue(isinstance(odt, OrgDateTime)) 23 | self.assertTrue(odt.active) 24 | 25 | def test_OrgDateTime_ctor_inactive(self): 26 | u"""OrdDateTime should be created.""" 27 | today = datetime.today() 28 | odt = OrgDateTime(False, today.year, today.month, today.day, today.hour, 29 | today.minute) 30 | self.assertTrue(isinstance(odt, OrgDateTime)) 31 | self.assertFalse(odt.active) 32 | 33 | def test_OrdDateTime_str_active(self): 34 | u"""Representation of OrgDateTime""" 35 | t = 2011, 9, 8, 10, 20 36 | odt = OrgDateTime(False, t[0], t[1], t[2], t[3], t[4]) 37 | self.assertEqual(u"[2011-09-08 Thu 10:20]", unicode(odt)) 38 | 39 | def test_OrdDateTime_str_inactive(self): 40 | u"""Representation of OrgDateTime""" 41 | t = 2011, 9, 8, 10, 20 42 | odt = OrgDateTime(True, t[0], t[1], t[2], t[3], t[4]) 43 | self.assertEqual(u"<2011-09-08 Thu 10:20>", unicode(odt)) 44 | 45 | 46 | def suite(): 47 | return unittest.TestLoader().loadTestsFromTestCase(OrgDateTimeTestCase) 48 | -------------------------------------------------------------------------------- /tests/test_liborgtimerange.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | import unittest 5 | from datetime import date 6 | from datetime import datetime 7 | 8 | sys.path.append(u'../ftplugin') 9 | from orgmode.liborgmode.orgdate import OrgTimeRange 10 | 11 | 12 | class OrgTimeRangeTestCase(unittest.TestCase): 13 | 14 | def setUp(self): 15 | self.date = date(2011, 8, 29) 16 | self.year = 2011 17 | self.month = 8 18 | self.day = 29 19 | self.text = '<2011-08-29 Mon>' 20 | self.textinactive = '[2011-08-29 Mon]' 21 | 22 | def test_OrgTimeRange_ctor_active(self): 23 | u""" 24 | timerange should be created. 25 | """ 26 | start = date(2011, 9 , 12) 27 | end = date(2011, 9 , 13) 28 | timerange = OrgTimeRange(True, start, end) 29 | self.assertTrue(isinstance(timerange, OrgTimeRange)) 30 | self.assertTrue(timerange.active) 31 | 32 | def test_OrgTimeRange_ctor_inactive(self): 33 | u""" 34 | timerange should be created. 35 | """ 36 | start = date(2011, 9 , 12) 37 | end = date(2011, 9 , 13) 38 | timerange = OrgTimeRange(False, start, end) 39 | self.assertTrue(isinstance(timerange, OrgTimeRange)) 40 | self.assertFalse(timerange.active) 41 | 42 | def test_OrdDate_str_active(self): 43 | u"""Representation of OrgDates""" 44 | start = date(2011, 9 , 12) 45 | end = date(2011, 9 , 13) 46 | timerange = OrgTimeRange(True, start, end) 47 | expected = "<2011-09-12 Mon>--<2011-09-13 Tue>" 48 | self.assertEqual(str(timerange), expected) 49 | 50 | start = datetime(2011, 9 , 12, 20, 00) 51 | end = datetime(2011, 9 , 13, 21, 59) 52 | timerange = OrgTimeRange(True, start, end) 53 | expected = "<2011-09-12 Mon 20:00>--<2011-09-13 Tue 21:59>" 54 | self.assertEqual(str(timerange), expected) 55 | 56 | start = datetime(2011, 9 , 12, 20, 00) 57 | end = datetime(2011, 9 , 12, 21, 00) 58 | timerange = OrgTimeRange(True, start, end) 59 | expected = "<2011-09-12 Mon 20:00-21:00>" 60 | self.assertEqual(str(timerange), expected) 61 | 62 | def test_OrdDate_str_inactive(self): 63 | u"""Representation of OrgDates""" 64 | start = date(2011, 9 , 12) 65 | end = date(2011, 9 , 13) 66 | timerange = OrgTimeRange(False, start, end) 67 | expected = "[2011-09-12 Mon]--[2011-09-13 Tue]" 68 | self.assertEqual(str(timerange), expected) 69 | 70 | start = datetime(2011, 9 , 12, 20, 00) 71 | end = datetime(2011, 9 , 13, 21, 59) 72 | timerange = OrgTimeRange(False, start, end) 73 | expected = "[2011-09-12 Mon 20:00]--[2011-09-13 Tue 21:59]" 74 | self.assertEqual(str(timerange), expected) 75 | 76 | start = datetime(2011, 9 , 12, 20, 00) 77 | end = datetime(2011, 9 , 12, 21, 00) 78 | timerange = OrgTimeRange(False, start, end) 79 | expected = "[2011-09-12 Mon 20:00-21:00]" 80 | self.assertEqual(str(timerange), expected) 81 | 82 | def suite(): 83 | return unittest.TestLoader().loadTestsFromTestCase(OrgTimeRangeTestCase) 84 | -------------------------------------------------------------------------------- /tests/test_plugin_date.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import print_function 4 | 5 | import unittest 6 | import sys 7 | sys.path.append(u'../ftplugin') 8 | 9 | from datetime import date 10 | from datetime import datetime 11 | 12 | from orgmode.plugins.Date import Date 13 | 14 | 15 | class DateTestCase(unittest.TestCase): 16 | u"""Tests all the functionality of the Date plugin. 17 | 18 | Also see: 19 | http://orgmode.org/manual/The-date_002ftime-prompt.html#The-date_002ftime-prompt 20 | """ 21 | 22 | def setUp(self): 23 | self.d = date(2011, 5, 22) 24 | 25 | def test_modify_time_with_None(self): 26 | # no modification should happen 27 | res = Date._modify_time(self.d, None) 28 | self.assertEquals(self.d, res) 29 | 30 | def test_modify_time_with_dot(self): 31 | # no modification should happen 32 | res = Date._modify_time(self.d, u'.') 33 | self.assertEquals(self.d, res) 34 | 35 | def test_modify_time_with_given_relative_days(self): 36 | # modifier and expected result 37 | test_data = [(u'+0d', self.d), 38 | (u'+1d', date(2011, 5, 23)), 39 | (u'+2d', date(2011, 5, 24)), 40 | (u'+7d', date(2011, 5, 29)), 41 | (u'+9d', date(2011, 5, 31)), 42 | (u'+10d', date(2011, 6, 1)), 43 | (u'7d', self.d)] # wrong format: plus is missing 44 | 45 | for modifier, expected in test_data: 46 | self.assertEquals(expected, Date._modify_time(self.d, modifier)) 47 | 48 | def test_modify_time_with_given_relative_days_without_d(self): 49 | # modifier and expected result 50 | test_data = [(u'+0', self.d), 51 | (u'+1', date(2011, 5, 23)), 52 | (u'+2', date(2011, 5, 24)), 53 | (u'+7', date(2011, 5, 29)), 54 | (u'+9', date(2011, 5, 31)), 55 | (u'+10', date(2011, 6, 1))] 56 | 57 | for modifier, expected in test_data: 58 | result = Date._modify_time(self.d, modifier) 59 | self.assertEquals(expected, result) 60 | 61 | def test_modify_time_with_given_relative_weeks(self): 62 | # modifier and expected result 63 | test_data = [(u'+1w', date(2011, 5, 29)), 64 | (u'+2w', date(2011, 6, 5)), 65 | (u'+3w', date(2011, 6, 12)), 66 | (u'+3w', date(2011, 6, 12)), 67 | (u'+0w', self.d), 68 | (u'3w', self.d), # wrong format 69 | (u'+w', self.d)] # wrong format 70 | 71 | for modifier, expected in test_data: 72 | self.assertEquals(expected, Date._modify_time(self.d, modifier)) 73 | 74 | def test_modify_time_with_given_relative_months(self): 75 | test_data = [(u'+0m', self.d), 76 | (u'+1m', date(2011, 6, 22)), 77 | (u'+2m', date(2011, 7, 22))] 78 | 79 | for modifier, expected in test_data: 80 | self.assertEquals(expected, Date._modify_time(self.d, modifier)) 81 | 82 | def test_modify_time_with_given_relative_years(self): 83 | test_data = [(u'+1y', date(2012, 5, 22)), 84 | (u'+10y', date(2021, 5, 22)), 85 | (u'+0y', self.d)] 86 | 87 | for modifier, expected in test_data: 88 | self.assertEquals(expected, Date._modify_time(self.d, modifier)) 89 | 90 | 91 | def test_modify_time_with_given_weekday(self): 92 | # use custom day instead of self.d to ease testing 93 | cust_day = date(2011, 5, 25) # it's a Wednesday 94 | #print(cust_day.weekday()) # 2 95 | test_data = [(u'Thu', date(2011, 5, 26)), 96 | (u'thu', date(2011, 5, 26)), 97 | (u'tHU', date(2011, 5, 26)), 98 | (u'THU', date(2011, 5, 26)), 99 | (u'Fri', date(2011, 5, 27)), 100 | (u'sat', date(2011, 5, 28)), 101 | (u'sun', date(2011, 5, 29)), 102 | (u'mon', date(2011, 5, 30)), 103 | (u'tue', date(2011, 5, 31)), 104 | (u'wed', date(2011, 6, 1))] 105 | 106 | for modifier, expected in test_data: 107 | self.assertEquals(expected, Date._modify_time(cust_day, modifier)) 108 | 109 | def test_modify_time_with_month_and_day(self): 110 | cust_date = date(2006, 6, 13) 111 | test_data = [(u'sep 15', date(2006, 9, 15)), 112 | (u'Sep 15', date(2006, 9, 15)), 113 | (u'SEP 15', date(2006, 9, 15)), 114 | (u'feb 15', date(2007, 2, 15)), 115 | (u'jan 1', date(2007, 1, 1)), 116 | (u'7/5', date(2006, 7, 5)), 117 | (u'2/5', date(2007, 2, 5)),] 118 | 119 | for modifier, expected in test_data: 120 | self.assertEquals(expected, Date._modify_time(cust_date, modifier)) 121 | 122 | def test_modify_time_with_time(self): 123 | cust_date = date(2006, 6, 13) 124 | test_data = [(u'12:45', datetime(2006, 6, 13, 12, 45)), 125 | (u'1:45', datetime(2006, 6, 13, 1, 45)), 126 | (u'1:05', datetime(2006, 6, 13, 1, 5)),] 127 | 128 | for modifier, expected in test_data: 129 | res = Date._modify_time(cust_date, modifier) 130 | self.assertTrue(isinstance(res, datetime)) 131 | self.assertEquals(expected, res) 132 | 133 | def test_modify_time_with_full_dates(self): 134 | result = Date._modify_time(self.d, u'2011-01-12') 135 | expected = date(2011, 1, 12) 136 | self.assertEquals(expected, result) 137 | 138 | reults = Date._modify_time(self.d, u'2015-03-12') 139 | expected = date(2015, 3, 12) 140 | self.assertEquals(expected, reults) 141 | 142 | cust_date = date(2006, 6, 13) 143 | test_data = [(u'3-2-5', date(2003, 2, 5)), 144 | (u'12-2-28', date(2012, 2, 28)), 145 | (u'2/5/3', date(2003, 2, 5)), 146 | (u'sep 12 9', date(2009, 9, 12)), 147 | (u'jan 2 99', date(2099, 1, 2)),] 148 | 149 | for modifier, expected in test_data: 150 | self.assertEquals(expected, Date._modify_time(cust_date, modifier)) 151 | 152 | def test_modify_time_with_only_days(self): 153 | cust_date = date(2006, 6, 13) 154 | test_data = [(u'14', date(2006, 6, 14)), 155 | (u'12', date(2006, 7, 12)), 156 | (u'1', date(2006, 7, 1)), 157 | (u'29', date(2006, 6, 29)),] 158 | for modifier, expected in test_data: 159 | self.assertEquals(expected, Date._modify_time(cust_date, modifier)) 160 | 161 | def test_modify_time_with_day_and_time(self): 162 | cust_date = date(2006, 6, 13) 163 | test_data = [(u'+1 10:20', datetime(2006, 6, 14, 10, 20)), 164 | (u'+1w 10:20', datetime(2006, 6, 20, 10, 20)), 165 | (u'+2 10:30', datetime(2006, 6, 15, 10, 30)), 166 | (u'+2d 10:30', datetime(2006, 6, 15, 10, 30))] 167 | for modifier, expected in test_data: 168 | result = Date._modify_time(cust_date, modifier) 169 | self.assertEquals(expected, result) 170 | 171 | def suite(): 172 | return unittest.TestLoader().loadTestsFromTestCase(DateTestCase) 173 | -------------------------------------------------------------------------------- /tests/test_plugin_edit_checkbox.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | import sys 5 | sys.path.append(u'../ftplugin') 6 | 7 | import vim 8 | 9 | from orgmode._vim import ORGMODE 10 | 11 | from orgmode.py3compat.encode_compatibility import * 12 | 13 | PLUGIN_NAME = u'EditCheckbox' 14 | 15 | bufnr = 10 16 | 17 | def set_vim_buffer(buf=None, cursor=(2, 0), bufnr=0): 18 | if buf is None: 19 | buf = [] 20 | vim.current.buffer[:] = buf 21 | vim.current.window.cursor = cursor 22 | vim.current.buffer.number = bufnr 23 | 24 | 25 | counter = 0 26 | class EditCheckboxTestCase(unittest.TestCase): 27 | def setUp(self): 28 | if PLUGIN_NAME not in ORGMODE.plugins: 29 | ORGMODE.register_plugin(PLUGIN_NAME) 30 | self.editcheckbox = ORGMODE.plugins[PLUGIN_NAME] 31 | vim.EVALRESULTS = { 32 | # no org_todo_keywords for b 33 | u_encode(u'exists("b:org_todo_keywords")'): u_encode('0'), 34 | # global values for org_todo_keywords 35 | u_encode(u'exists("g:org_todo_keywords")'): u_encode('1'), 36 | u_encode(u'g:org_todo_keywords'): [u_encode(u'TODO'), u_encode(u'|'), u_encode(u'DONE')], 37 | u_encode(u'exists("g:org_improve_split_heading")'): u_encode(u'0'), 38 | u_encode(u'exists("b:org_improve_split_heading")'): u_encode(u'0'), 39 | u_encode(u'exists("g:org_debug")'): u_encode(u'0'), 40 | u_encode(u'exists("b:org_debug")'): u_encode(u'0'), 41 | u_encode(u'exists("*repeat#set()")'): u_encode(u'0'), 42 | u_encode(u'b:changedtick'): u_encode(u'%d' % counter), 43 | u_encode(u'&ts'): u_encode(u'8'), 44 | u_encode(u'exists("g:org_tag_column")'): u_encode(u'0'), 45 | u_encode(u'exists("b:org_tag_column")'): u_encode(u'0'), 46 | u_encode(u"v:count"): u_encode(u'0'), 47 | # jump to insert mode after adding heading/checkbox 48 | u_encode(u'exists("g:org_prefer_insert_mode")'): u_encode(u'0'), 49 | u_encode(u'exists("b:org_prefer_insert_mode")'): u_encode(u'0')} 50 | 51 | self.c1 = u""" 52 | * heading1 [%] 53 | - [ ] checkbox1 [/] 54 | - [ ] checkbox2 55 | - [ ] checkbox3 56 | - [ ] checkbox4 57 | - [ ] checkbox5 58 | - [ ] checkbox6 59 | - [ ] checkbox7 60 | - [ ] checkbox8 61 | """.split(u'\n') 62 | 63 | self.c2 = u""" 64 | * a checkbox list [%] 65 | - checkbox [0%] 66 | - [ ] test1 67 | - [ ] test2 68 | - [ ] test3 69 | """.split(u'\n') 70 | 71 | self.c3 = u""" 72 | * heading 73 | 1. [ ] another main task [%] 74 | - [ ] sub task 1 75 | - [ ] sub task 2 76 | 2. [ ] another main task 77 | """.split(u'\n') 78 | 79 | self.c4 = u""" 80 | * heading 81 | """.split(u'\n') 82 | 83 | self.c5 = u""" 84 | * heading1 85 | 1. item 86 | 9. item 87 | }. item 88 | a. item 89 | z. item 90 | A. item 91 | Z. item 92 | aa. item 93 | """.split("\n") 94 | 95 | def test_toggle(self): 96 | global bufnr 97 | bufnr += 1 98 | # test on self.c1 99 | set_vim_buffer(buf=self.c1, cursor=(6, 0), bufnr=bufnr) 100 | # update_checkboxes_status 101 | self.editcheckbox.update_checkboxes_status() 102 | self.assertEqual(vim.current.buffer[1], u"* heading1 [0%]") 103 | # toggle 104 | self.editcheckbox.toggle() 105 | self.assertEqual(vim.current.buffer[5], u" - [X] checkbox4") 106 | 107 | bufnr += 1 108 | set_vim_buffer(buf=self.c1, cursor=(9, 0), bufnr=bufnr) 109 | # toggle and check checkbox status 110 | self.editcheckbox.toggle() 111 | self.assertEqual(vim.current.buffer[8], u" - [X] checkbox7") 112 | self.assertEqual(vim.current.buffer[7], u" - [-] checkbox6") 113 | self.assertEqual(vim.current.buffer[6], u" - [-] checkbox5") 114 | 115 | # new_checkbox 116 | bufnr += 1 117 | set_vim_buffer(buf=self.c1, cursor=(9, 0), bufnr=bufnr) 118 | vim.current.window.cursor = (9, 0) 119 | self.assertEqual(vim.current.buffer[9], u' - [ ] checkbox8') 120 | self.editcheckbox.new_checkbox(below=True) 121 | # vim's buffer behave just opposite to Python's list when inserting a 122 | # new item. The new entry is appended in vim put prepended in Python! 123 | self.assertEqual(vim.current.buffer[10], u' - [ ] checkbox8') 124 | self.assertEqual(vim.current.buffer[9], u' - [ ] ') 125 | self.editcheckbox.update_checkboxes_status() 126 | 127 | def test_no_status_checkbox(self): 128 | global bufnr 129 | bufnr += 1 130 | # test on self.c2 131 | set_vim_buffer(buf=self.c2, bufnr=bufnr) 132 | self.assertEqual(vim.current.buffer[2], u" - checkbox [0%]") 133 | # toggle 134 | vim.current.window.cursor = (4, 0) 135 | self.editcheckbox.toggle() 136 | self.assertEqual(vim.current.buffer[3], u" - [X] test1") 137 | 138 | # self.editcheckbox.update_checkboxes_status() 139 | # see if the no status checkbox update its status 140 | self.assertEqual(vim.current.buffer[2], u" - checkbox [33%]") 141 | 142 | def test_number_list(self): 143 | global bufnr 144 | bufnr += 1 145 | set_vim_buffer(buf=self.c3, bufnr=bufnr) 146 | vim.current.window.cursor = (6, 0) 147 | self.editcheckbox.toggle() 148 | self.assertEqual(vim.current.buffer[5], u" 2. [X] another main task") 149 | 150 | def test_new_checkbox(self): 151 | global bufnr 152 | bufnr += 1 153 | set_vim_buffer(buf=self.c4, bufnr=bufnr) 154 | vim.current.window.cursor = (2, 1) 155 | self.editcheckbox.new_checkbox(below=True) 156 | self.assertEqual(vim.current.buffer[2], u" - [ ] ") 157 | 158 | def test_item_decrement(self): 159 | global bufnr 160 | bufnr += 1 161 | set_vim_buffer(buf=self.c5, bufnr=bufnr) 162 | 163 | vim.current.window.cursor = (3, 1) 164 | self.editcheckbox.new_checkbox(below=False, plain=True) 165 | self.assertEqual(vim.current.buffer[2], u" 0. ") 166 | self.assertEqual(vim.current.buffer[3], u" 1. item") 167 | 168 | vim.current.window.cursor = (3, 1) 169 | self.editcheckbox.new_checkbox(below=False, plain=True) 170 | self.assertEqual(vim.current.buffer[1], u"* heading1") 171 | self.assertEqual(vim.current.buffer[2], u" 0. ") 172 | self.assertEqual(vim.current.buffer[3], u" 1. item") 173 | 174 | vim.current.window.cursor = (5, 1) 175 | self.editcheckbox.new_checkbox(below=False, plain=True) 176 | self.assertEqual(vim.current.buffer[4], u" 8. ") 177 | self.assertEqual(vim.current.buffer[5], u" 9. item") 178 | 179 | vim.current.window.cursor = (8, 1) 180 | self.editcheckbox.new_checkbox(below=False, plain=True) 181 | # no further decrement than a 182 | self.assertEqual(vim.current.buffer[6], u" }. item") 183 | self.assertEqual(vim.current.buffer[7], u" a. item") 184 | self.assertEqual(vim.current.buffer[8], u" z. item") 185 | 186 | def test_item_decrementA(self): 187 | global bufnr 188 | bufnr += 1 189 | set_vim_buffer(buf=self.c5, bufnr=bufnr) 190 | vim.current.window.cursor = (8, 1) 191 | self.editcheckbox.new_checkbox(below=False, plain=True) 192 | # decrement from A to z 193 | self.assertEqual(vim.current.buffer[7], u" z. ") 194 | self.assertEqual(vim.current.buffer[8], u" A. item") 195 | 196 | def test_item_increment(self): 197 | global bufnr 198 | bufnr += 1 199 | set_vim_buffer(buf=self.c5, bufnr=bufnr) 200 | 201 | vim.current.window.cursor = (3, 1) 202 | self.editcheckbox.new_checkbox(below=True, plain=True) 203 | self.assertEqual(vim.current.buffer[2], u" 1. item") 204 | self.assertEqual(vim.current.buffer[3], u" 2. ") 205 | 206 | vim.current.window.cursor = (5, 1) 207 | self.editcheckbox.new_checkbox(below=True, plain=True) 208 | self.assertEqual(vim.current.buffer[4], u" 9. item") 209 | self.assertEqual(vim.current.buffer[5], u" }. item") 210 | self.assertEqual(vim.current.buffer[6], u" 10. ") 211 | 212 | def test_item_incrementz(self): 213 | global bufnr 214 | bufnr += 1 215 | set_vim_buffer(buf=self.c5, bufnr=bufnr) 216 | 217 | vim.current.window.cursor = (6, 1) 218 | self.editcheckbox.new_checkbox(below=True, plain=True) 219 | self.assertEqual(vim.current.buffer[5], u" a. item") 220 | self.assertEqual(vim.current.buffer[6], u" b. ") 221 | 222 | vim.current.window.cursor = (8, 1) 223 | self.editcheckbox.new_checkbox(below=True, plain=True) 224 | self.assertEqual(vim.current.buffer[7], u" z. item") 225 | self.assertEqual(vim.current.buffer[8], u" A. ") 226 | 227 | vim.current.window.cursor = (11, 1) 228 | self.editcheckbox.new_checkbox(below=True, plain=True) 229 | self.assertEqual(vim.current.buffer[10], u" Z. item") 230 | self.assertEqual(vim.current.buffer[11], u" aa. item") 231 | self.assertEqual(vim.current.buffer[12], u"") 232 | 233 | vim.current.window.cursor = (12, 1) 234 | self.editcheckbox.new_checkbox(below=True, plain=True) 235 | self.assertEqual(vim.current.buffer[11], u" aa. item") 236 | self.assertEqual(vim.current.buffer[12], u"") 237 | 238 | def suite(): 239 | return unittest.TestLoader().loadTestsFromTestCase(EditCheckboxTestCase) 240 | -------------------------------------------------------------------------------- /tests/test_plugin_mappings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import print_function 4 | 5 | import sys 6 | sys.path.append(u'../ftplugin') 7 | 8 | import unittest 9 | import orgmode.settings 10 | from orgmode.exceptions import PluginError 11 | from orgmode._vim import ORGMODE 12 | from orgmode.keybinding import MODE_ALL, Plug 13 | 14 | import vim 15 | 16 | from orgmode.py3compat.encode_compatibility import * 17 | 18 | ORG_PLUGINS = ['ShowHide', '|', 'Navigator', 'EditStructure', '|', 'Hyperlinks', '|', 'Todo', 'TagsProperties', 'Date', 'Agenda', 'Misc', '|', 'Export'] 19 | 20 | 21 | class MappingTestCase(unittest.TestCase): 22 | u"""Tests all plugins for overlapping mappings.""" 23 | def test_non_overlapping_plug_mappings(self): 24 | def find_overlapping_mappings(kb, all_keybindings): 25 | found_overlapping_mapping = False 26 | for tkb in all_keybindings: 27 | if kb.mode == tkb.mode or MODE_ALL in (kb.mode, tkb.mode): 28 | if isinstance(kb._action, Plug) and isinstance(tkb._action, Plug): 29 | akb = kb.action 30 | atkb = tkb.action 31 | if (akb.startswith(atkb) or atkb.startswith(akb)) and akb != atkb: 32 | print(u'\nERROR: Found overlapping mapping: %s (%s), %s (%s)' % (kb.key, akb, tkb.key, atkb)) 33 | found_overlapping_mapping = True 34 | 35 | if all_keybindings: 36 | res = find_overlapping_mappings(all_keybindings[0], all_keybindings[1:]) 37 | if not found_overlapping_mapping: 38 | return res 39 | return found_overlapping_mapping 40 | 41 | if self.keybindings: 42 | self.assertFalse(find_overlapping_mappings(self.keybindings[0], self.keybindings[1:])) 43 | 44 | def setUp(self): 45 | self.keybindings = [] 46 | 47 | vim.EVALRESULTS = { 48 | u'exists("g:org_debug")': 0, 49 | u'exists("b:org_debug")': 0, 50 | u'exists("*repeat#set()")': 0, 51 | u'b:changedtick': 0, 52 | u_encode(u'exists("b:org_plugins")'): 0, 53 | u_encode(u'exists("g:org_plugins")'): 1, 54 | u_encode(u'g:org_plugins'): ORG_PLUGINS, 55 | } 56 | for plugin in filter(lambda p: p != '|', ORG_PLUGINS): 57 | try: 58 | ORGMODE.register_plugin(plugin) 59 | except PluginError: 60 | pass 61 | if plugin in ORGMODE._plugins: 62 | self.keybindings.extend(ORGMODE._plugins[plugin].keybindings) 63 | 64 | 65 | def suite(): 66 | return unittest.TestLoader().loadTestsFromTestCase(MappingTestCase) 67 | -------------------------------------------------------------------------------- /tests/test_plugin_misc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | import sys 6 | sys.path.append(u'../ftplugin') 7 | 8 | import vim 9 | 10 | from orgmode._vim import indent_orgmode, fold_orgmode, ORGMODE 11 | 12 | from orgmode.py3compat.encode_compatibility import * 13 | 14 | ORGMODE.debug = True 15 | 16 | START = True 17 | END = False 18 | 19 | counter = 0 20 | class MiscTestCase(unittest.TestCase): 21 | def setUp(self): 22 | global counter 23 | counter += 1 24 | vim.CMDHISTORY = [] 25 | vim.CMDRESULTS = {} 26 | vim.EVALHISTORY = [] 27 | vim.EVALRESULTS = { 28 | # no org_todo_keywords for b 29 | u_encode(u'exists("b:org_todo_keywords")'): u_encode('0'), 30 | # global values for org_todo_keywords 31 | u_encode(u'exists("g:org_todo_keywords")'): u_encode('1'), 32 | u_encode(u'g:org_todo_keywords'): [u_encode(u'TODO'), u_encode(u'|'), u_encode(u'DONE')], 33 | u_encode(u'exists("g:org_debug")'): u_encode(u'0'), 34 | u_encode(u'exists("g:org_debug")'): u_encode(u'0'), 35 | u_encode(u'exists("*repeat#set()")'): u_encode(u'0'), 36 | u_encode(u"v:count"): u_encode(u'0'), 37 | u_encode(u'b:changedtick'): u_encode(u'%d' % counter), 38 | u_encode(u"v:lnum"): u_encode(u'0')} 39 | vim.current.buffer[:] = [ u_encode(i) for i in u""" 40 | * Überschrift 1 41 | Text 1 42 | 43 | Bla bla 44 | ** Überschrift 1.1 45 | Text 2 46 | 47 | Bla Bla bla 48 | ** Überschrift 1.2 49 | Text 3 50 | 51 | **** Überschrift 1.2.1.falsch 52 | 53 | Bla Bla bla bla 54 | *** Überschrift 1.2.1 55 | * Überschrift 2 56 | * Überschrift 3 57 | asdf sdf 58 | """.split(u'\n') ] 59 | 60 | def test_indent_noheading(self): 61 | # test first heading 62 | vim.current.window.cursor = (1, 0) 63 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'1') 64 | indent_orgmode() 65 | self.assertEqual(len(vim.CMDHISTORY), 0) 66 | 67 | def test_indent_heading(self): 68 | # test first heading 69 | vim.current.window.cursor = (2, 0) 70 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'2') 71 | indent_orgmode() 72 | self.assertEqual(len(vim.CMDHISTORY), 0) 73 | 74 | def test_indent_heading_middle(self): 75 | # test first heading 76 | vim.current.window.cursor = (3, 0) 77 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'3') 78 | indent_orgmode() 79 | self.assertEqual(len(vim.CMDHISTORY), 1) 80 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:indent_level = 2')) 81 | 82 | def test_indent_heading_middle2(self): 83 | # test first heading 84 | vim.current.window.cursor = (4, 0) 85 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'4') 86 | indent_orgmode() 87 | self.assertEqual(len(vim.CMDHISTORY), 1) 88 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:indent_level = 2')) 89 | 90 | def test_indent_heading_end(self): 91 | # test first heading 92 | vim.current.window.cursor = (5, 0) 93 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'5') 94 | indent_orgmode() 95 | self.assertEqual(len(vim.CMDHISTORY), 1) 96 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:indent_level = 2')) 97 | 98 | def test_fold_heading_start(self): 99 | # test first heading 100 | vim.current.window.cursor = (2, 0) 101 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'2') 102 | fold_orgmode() 103 | self.assertEqual(len(vim.CMDHISTORY), 1) 104 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = ">1"')) 105 | 106 | def test_fold_heading_middle(self): 107 | # test first heading 108 | vim.current.window.cursor = (3, 0) 109 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'3') 110 | fold_orgmode() 111 | self.assertEqual(len(vim.CMDHISTORY), 1) 112 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = 1')) 113 | 114 | def test_fold_heading_end(self): 115 | # test first heading 116 | vim.current.window.cursor = (5, 0) 117 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'5') 118 | fold_orgmode() 119 | self.assertEqual(len(vim.CMDHISTORY), 1) 120 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = 1')) 121 | 122 | def test_fold_heading_end_of_last_child(self): 123 | # test first heading 124 | vim.current.window.cursor = (16, 0) 125 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'16') 126 | fold_orgmode() 127 | self.assertEqual(len(vim.CMDHISTORY), 1) 128 | # which is also end of the parent heading <1 129 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = ">3"')) 130 | 131 | def test_fold_heading_end_of_last_child_next_heading(self): 132 | # test first heading 133 | vim.current.window.cursor = (17, 0) 134 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'17') 135 | fold_orgmode() 136 | self.assertEqual(len(vim.CMDHISTORY), 1) 137 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = ">1"')) 138 | 139 | def test_fold_middle_subheading(self): 140 | # test first heading 141 | vim.current.window.cursor = (13, 0) 142 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'13') 143 | fold_orgmode() 144 | self.assertEqual(len(vim.CMDHISTORY), 1) 145 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = ">4"')) 146 | 147 | def test_fold_middle_subheading2(self): 148 | # test first heading 149 | vim.current.window.cursor = (14, 0) 150 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'14') 151 | fold_orgmode() 152 | self.assertEqual(len(vim.CMDHISTORY), 1) 153 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = 4')) 154 | 155 | def test_fold_middle_subheading3(self): 156 | # test first heading 157 | vim.current.window.cursor = (15, 0) 158 | vim.EVALRESULTS[u_encode(u'v:lnum')] = u_encode(u'15') 159 | fold_orgmode() 160 | self.assertEqual(len(vim.CMDHISTORY), 1) 161 | self.assertEqual(vim.CMDHISTORY[-1], u_encode(u'let b:fold_expr = 4')) 162 | 163 | def suite(): 164 | return unittest.TestLoader().loadTestsFromTestCase(MiscTestCase) 165 | -------------------------------------------------------------------------------- /tests/test_plugin_tags_properties.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | import sys 6 | sys.path.append(u'../ftplugin') 7 | 8 | import vim 9 | 10 | from orgmode._vim import indent_orgmode, fold_orgmode, ORGMODE 11 | 12 | from orgmode.py3compat.encode_compatibility import * 13 | 14 | ORGMODE.debug = True 15 | 16 | START = True 17 | END = False 18 | 19 | counter = 0 20 | class TagsPropertiesTestCase(unittest.TestCase): 21 | def setUp(self): 22 | global counter 23 | counter += 1 24 | vim.CMDHISTORY = [] 25 | vim.CMDRESULTS = {} 26 | vim.EVALHISTORY = [] 27 | vim.EVALRESULTS = { 28 | # no org_todo_keywords for b 29 | u_encode(u'exists("b:org_todo_keywords")'): u_encode('0'), 30 | # global values for org_todo_keywords 31 | u_encode(u'exists("g:org_todo_keywords")'): u_encode('1'), 32 | u_encode(u'g:org_todo_keywords'): [u_encode(u'TODO'), u_encode(u'|'), u_encode(u'DONE')], 33 | u_encode(u'&ts'): u_encode(u'6'), 34 | u_encode(u'exists("b:org_tag_column")'): u_encode(u'0'), 35 | u_encode(u'exists("g:org_tag_column")'): u_encode(u'0'), 36 | u_encode(u'exists("g:org_debug")'): u_encode(u'0'), 37 | u_encode(u'exists("b:org_debug")'): u_encode(u'0'), 38 | u_encode(u'exists("*repeat#set()")'): u_encode(u'0'), 39 | u_encode(u'b:changedtick'): (u_encode(u'%d' % counter)), 40 | u_encode(u"v:count"): u_encode(u'0')} 41 | if not u'TagsProperties' in ORGMODE.plugins: 42 | ORGMODE.register_plugin(u'TagsProperties') 43 | self.tagsproperties = ORGMODE.plugins[u'TagsProperties'] 44 | vim.current.buffer[:] = [ u_encode(i) for i in u""" 45 | * Überschrift 1 46 | Text 1 47 | 48 | Bla bla 49 | ** Überschrift 1.1 50 | Text 2 51 | 52 | Bla Bla bla 53 | ** Überschrift 1.2 54 | Text 3 55 | 56 | **** Überschrift 1.2.1.falsch 57 | 58 | Bla Bla bla bla 59 | *** Überschrift 1.2.1 60 | * Überschrift 2 61 | * Überschrift 3 62 | asdf sdf 63 | """.split(u'\n') ] 64 | 65 | def test_new_property(self): 66 | u""" TODO: Docstring for test_new_property 67 | 68 | :returns: TODO 69 | """ 70 | pass 71 | 72 | def test_set_tags(self): 73 | # set first tag 74 | vim.current.window.cursor = (2, 0) 75 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u':hello:') 76 | self.tagsproperties.set_tags() 77 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t\t :hello:')) 78 | 79 | # set second tag 80 | vim.EVALRESULTS[u_encode(u'input("Tags: ", ":hello:", "customlist,Org_complete_tags")')] = u_encode(u':hello:world:') 81 | self.tagsproperties.set_tags() 82 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 83 | 84 | def test_parse_tags_no_colons_single_tag(self): 85 | vim.current.window.cursor = (2, 0) 86 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u'hello') 87 | self.tagsproperties.set_tags() 88 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t\t :hello:')) 89 | 90 | def test_parse_tags_no_colons_multiple_tags(self): 91 | vim.current.window.cursor = (2, 0) 92 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u'hello:world') 93 | self.tagsproperties.set_tags() 94 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 95 | 96 | def test_parse_tags_single_colon_left_single_tag(self): 97 | vim.current.window.cursor = (2, 0) 98 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u':hello') 99 | self.tagsproperties.set_tags() 100 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t\t :hello:')) 101 | 102 | def test_parse_tags_single_colon_left_multiple_tags(self): 103 | vim.current.window.cursor = (2, 0) 104 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u':hello:world') 105 | self.tagsproperties.set_tags() 106 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 107 | 108 | def test_parse_tags_single_colon_right_single_tag(self): 109 | vim.current.window.cursor = (2, 0) 110 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u'hello:') 111 | self.tagsproperties.set_tags() 112 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t\t :hello:')) 113 | 114 | def test_parse_tags_single_colon_right_multiple_tags(self): 115 | vim.current.window.cursor = (2, 0) 116 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u'hello:world:') 117 | self.tagsproperties.set_tags() 118 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 119 | 120 | def test_filter_empty_tags(self): 121 | vim.current.window.cursor = (2, 0) 122 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u'::hello::') 123 | self.tagsproperties.set_tags() 124 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t\t :hello:')) 125 | 126 | def test_delete_tags(self): 127 | # set up 128 | vim.current.window.cursor = (2, 0) 129 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u':hello:world:') 130 | self.tagsproperties.set_tags() 131 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 132 | 133 | # delete second of two tags 134 | vim.EVALRESULTS[u_encode(u'input("Tags: ", ":hello:world:", "customlist,Org_complete_tags")')] = u_encode(u':hello:') 135 | self.tagsproperties.set_tags() 136 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t\t :hello:')) 137 | 138 | # delete last tag 139 | vim.EVALRESULTS[u_encode(u'input("Tags: ", ":hello:", "customlist,Org_complete_tags")')] = u_encode(u'') 140 | self.tagsproperties.set_tags() 141 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1')) 142 | 143 | def test_realign_tags_noop(self): 144 | vim.current.window.cursor = (2, 0) 145 | self.tagsproperties.realign_tags() 146 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1')) 147 | 148 | def test_realign_tags_remove_spaces(self): 149 | # remove spaces in multiple locations 150 | vim.current.buffer[1] = u_encode(u'* Überschrift 1 ') 151 | vim.current.window.cursor = (2, 0) 152 | self.tagsproperties.realign_tags() 153 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1')) 154 | 155 | # remove tabs and spaces in multiple locations 156 | vim.current.buffer[1] = u_encode(u'*\t \tÜberschrift 1 \t') 157 | vim.current.window.cursor = (2, 0) 158 | self.tagsproperties.realign_tags() 159 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1')) 160 | 161 | def test_realign_tags(self): 162 | vim.current.window.cursor = (2, 0) 163 | vim.EVALRESULTS[u_encode(u'input("Tags: ", "", "customlist,Org_complete_tags")')] = u_encode(u':hello:world:') 164 | self.tagsproperties.set_tags() 165 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 166 | 167 | d = ORGMODE.get_document() 168 | heading = d.find_current_heading() 169 | self.assertEqual(str(heading), u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 170 | self.tagsproperties.realign_tags() 171 | heading = d.find_current_heading() 172 | self.assertEqual(str(heading), u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 173 | self.assertEqual(vim.current.buffer[1], u_encode(u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:')) 174 | 175 | def suite(): 176 | return unittest.TestLoader().loadTestsFromTestCase(TagsPropertiesTestCase) 177 | -------------------------------------------------------------------------------- /tests/vim.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class VimWindow(object): 5 | u""" Docstring for VimWindow """ 6 | 7 | def __init__(self, test): 8 | object.__init__(self) 9 | self._test = test 10 | self.cursor = (1, 0) 11 | 12 | def buffer(): 13 | def fget(self): 14 | return self._test.buffer 15 | 16 | def fset(self, value): 17 | self._test.buffer = value 18 | return locals() 19 | buffer = property(**buffer()) 20 | 21 | 22 | class VimBuffer(list): 23 | def __init__(self, iterable=None): 24 | self.number = 0 25 | if iterable is not None: 26 | list.__init__(self, iterable) 27 | else: 28 | list.__init__(self) 29 | 30 | def append(self, o): 31 | u""" 32 | mimic the specific behavior of vim.current.buffer 33 | """ 34 | if isinstance(o, list) or isinstance(o, tuple): 35 | for i in o: 36 | list.append(self, i) 37 | else: 38 | list.append(self, o) 39 | 40 | 41 | class VimTest(object): 42 | u""" Replacement for vim API """ 43 | 44 | def __init__(self): 45 | object.__init__(self) 46 | self._buffer = VimBuffer() 47 | self.window = VimWindow(self) 48 | 49 | def buffer(): 50 | def fget(self): 51 | return self._buffer 52 | 53 | def fset(self, value): 54 | self._buffer = VimBuffer(value) 55 | return locals() 56 | buffer = property(**buffer()) 57 | 58 | 59 | EVALHISTORY = [] 60 | EVALRESULTS = { 61 | u'exists("g:org_debug")': 0, 62 | u'exists("b:org_debug")': 0, 63 | u'exists("*repeat#set()")': 0, 64 | u'exists("b:org_plugins")': 0, 65 | u'exists("g:org_plugins")': 0, 66 | u'b:changedtick': 0, 67 | } 68 | 69 | 70 | def eval(cmd): 71 | u""" evaluate command 72 | 73 | :returns: results stored in EVALRESULTS 74 | """ 75 | EVALHISTORY.append(cmd) 76 | return EVALRESULTS.get(cmd, None) 77 | 78 | 79 | CMDHISTORY = [] 80 | CMDRESULTS = {} 81 | 82 | 83 | def command(cmd): 84 | CMDHISTORY.append(cmd) 85 | return CMDRESULTS.get(cmd, None) 86 | 87 | 88 | current = VimTest() 89 | --------------------------------------------------------------------------------