I broke up with neovim....vim is my best friend now
This commit is contained in:
312
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Agenda.py
Normal file
312
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Agenda.py
Normal file
@@ -0,0 +1,312 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from datetime import date
|
||||
import os
|
||||
import glob
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import ORGMODE, get_bufnumber, get_bufname, echoe
|
||||
from orgmode import settings
|
||||
from orgmode.keybinding import Keybinding, Plug, Command
|
||||
from orgmode.menu import Submenu, ActionEntry, add_cmd_mapping_menu
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.unicode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class Agenda(object):
|
||||
u"""
|
||||
The Agenda Plugin uses liborgmode.agenda to display the agenda views.
|
||||
|
||||
The main task is to format the agenda from liborgmode.agenda.
|
||||
Also all the mappings: jump from agenda to todo, etc are realized here.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'Agenda')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
@classmethod
|
||||
def _switch_to(cls, bufname, vim_commands=None):
|
||||
u"""
|
||||
Swicht to the buffer with bufname.
|
||||
|
||||
A list of vim.commands (if given) gets executed as well.
|
||||
|
||||
TODO: this should be extracted and imporved to create an easy to use
|
||||
way to create buffers/jump to buffers. Otherwise there are going to be
|
||||
quite a few ways to open buffers in vimorgmode.
|
||||
"""
|
||||
cmds = [
|
||||
u'botright split org:%s' % bufname,
|
||||
u'setlocal buftype=nofile',
|
||||
u'setlocal modifiable',
|
||||
u'setlocal nonumber',
|
||||
# call opendoc() on enter the original todo item
|
||||
u'nnoremap <silent> <buffer> <CR> :exec "%s ORGMODE.plugins[u\'Agenda\'].opendoc()"<CR>' % VIM_PY_CALL,
|
||||
u'nnoremap <silent> <buffer> <TAB> :exec "%s ORGMODE.plugins[u\'Agenda\'].opendoc(switch=True)"<CR>' % VIM_PY_CALL,
|
||||
u'nnoremap <silent> <buffer> <S-CR> :exec "%s ORGMODE.plugins[u\'Agenda\'].opendoc(split=True)"<CR>' % VIM_PY_CALL,
|
||||
# statusline
|
||||
u'setlocal statusline=Org\\ %s' % bufname]
|
||||
if vim_commands:
|
||||
cmds.extend(vim_commands)
|
||||
for cmd in cmds:
|
||||
vim.command(u_encode(cmd))
|
||||
|
||||
@classmethod
|
||||
def _get_agendadocuments(self):
|
||||
u"""
|
||||
Return the org documents of the agenda files; return None if no
|
||||
agenda documents are defined.
|
||||
|
||||
TODO: maybe turn this into an decorator?
|
||||
"""
|
||||
# load org files of agenda
|
||||
agenda_files = settings.get(u'org_agenda_files', u',')
|
||||
if not agenda_files or agenda_files == ',':
|
||||
echoe(
|
||||
u"No org_agenda_files defined. Use :let "
|
||||
u"g:org_agenda_files=['~/org/index.org'] to add "
|
||||
u"files to the agenda view.")
|
||||
return
|
||||
return self._load_agendafiles(agenda_files)
|
||||
|
||||
@classmethod
|
||||
def _load_agendafiles(self, agenda_files):
|
||||
# glob for files in agenda_files
|
||||
resolved_files = []
|
||||
for f in agenda_files:
|
||||
f = glob.glob(os.path.join(
|
||||
os.path.expanduser(os.path.dirname(f)),
|
||||
os.path.basename(f)))
|
||||
resolved_files.extend(f)
|
||||
|
||||
agenda_files = [os.path.realpath(f) for f in resolved_files]
|
||||
|
||||
# load the agenda files into buffers
|
||||
for agenda_file in agenda_files:
|
||||
vim.command(u_encode(u'badd %s' % agenda_file.replace(" ", "\\ ")))
|
||||
|
||||
# determine the buffer nr of the agenda files
|
||||
agenda_nums = [get_bufnumber(fn) for fn in agenda_files]
|
||||
|
||||
# collect all documents of the agenda files and create the agenda
|
||||
return [ORGMODE.get_document(i) for i in agenda_nums if i is not None]
|
||||
|
||||
@classmethod
|
||||
def opendoc(cls, split=False, switch=False):
|
||||
u"""
|
||||
If you are in the agenda view jump to the document the item in the
|
||||
current line belongs to. cls.line2doc is used for that.
|
||||
|
||||
:split: if True, open the document in a new split window.
|
||||
:switch: if True, switch to another window and open the the document
|
||||
there.
|
||||
"""
|
||||
row, _ = vim.current.window.cursor
|
||||
try:
|
||||
bufname, bufnr, destrow = cls.line2doc[row]
|
||||
except:
|
||||
return
|
||||
|
||||
# reload source file if it is not loaded
|
||||
if get_bufname(bufnr) is None:
|
||||
vim.command(u_encode(u'badd %s' % bufname))
|
||||
bufnr = get_bufnumber(bufname)
|
||||
tmp = cls.line2doc[row]
|
||||
cls.line2doc[bufnr] = tmp
|
||||
# delete old endry
|
||||
del cls.line2doc[row]
|
||||
|
||||
if split:
|
||||
vim.command(u_encode(u"sbuffer %s" % bufnr))
|
||||
elif switch:
|
||||
vim.command(u_encode(u"wincmd w"))
|
||||
vim.command(u_encode(u"buffer %d" % bufnr))
|
||||
else:
|
||||
vim.command(u_encode(u"buffer %s" % bufnr))
|
||||
vim.command(u_encode(u"normal! %dgg <CR>" % (destrow + 1)))
|
||||
|
||||
@classmethod
|
||||
def list_next_week(cls):
|
||||
agenda_documents = cls._get_agendadocuments()
|
||||
if not agenda_documents:
|
||||
return
|
||||
cls.list_next_week_for(agenda_documents)
|
||||
|
||||
@classmethod
|
||||
def list_next_week_for_buffer(cls):
|
||||
agenda_documents = vim.current.buffer.name
|
||||
loaded_agendafiles = cls._load_agendafiles([agenda_documents])
|
||||
cls.list_next_week_for(loaded_agendafiles)
|
||||
|
||||
|
||||
@classmethod
|
||||
def list_next_week_for(cls, agenda_documents):
|
||||
raw_agenda = ORGMODE.agenda_manager.get_next_week_and_active_todo(
|
||||
agenda_documents)
|
||||
|
||||
# if raw_agenda is empty, return directly
|
||||
if not raw_agenda:
|
||||
vim.command('echom "All caught-up. No agenda or active todo next week."')
|
||||
return
|
||||
|
||||
# create buffer at bottom
|
||||
cmd = [u'setlocal filetype=orgagenda', ]
|
||||
cls._switch_to(u'AGENDA', cmd)
|
||||
|
||||
# line2doc is a dic with the mapping:
|
||||
# line in agenda buffer --> source document
|
||||
# It's easy to jump to the right document this way
|
||||
cls.line2doc = {}
|
||||
# format text for agenda
|
||||
last_date = raw_agenda[0].active_date
|
||||
final_agenda = [u'Week Agenda:', unicode(last_date)]
|
||||
for i, h in enumerate(raw_agenda):
|
||||
# insert date information for every new date (not datetime)
|
||||
if unicode(h.active_date)[1:11] != unicode(last_date)[1:11]:
|
||||
today = date.today()
|
||||
# insert additional "TODAY" string
|
||||
if h.active_date.year == today.year and \
|
||||
h.active_date.month == today.month and \
|
||||
h.active_date.day == today.day:
|
||||
section = unicode(h.active_date) + u" TODAY"
|
||||
today_row = len(final_agenda) + 1
|
||||
else:
|
||||
section = unicode(h.active_date)
|
||||
final_agenda.append(section)
|
||||
|
||||
# update last_date
|
||||
last_date = h.active_date
|
||||
|
||||
bufname = os.path.basename(vim.buffers[h.document.bufnr].name)
|
||||
bufname = bufname[:-4] if bufname.endswith(u'.org') else bufname
|
||||
formatted = u" %(bufname)s (%(bufnr)d) %(todo)s %(title)s" % {
|
||||
'bufname': bufname,
|
||||
'bufnr': h.document.bufnr,
|
||||
'todo': h.todo,
|
||||
'title': h.title
|
||||
}
|
||||
final_agenda.append(formatted)
|
||||
cls.line2doc[len(final_agenda)] = (get_bufname(h.document.bufnr), h.document.bufnr, h.start)
|
||||
|
||||
# show agenda
|
||||
vim.current.buffer[:] = [u_encode(i) for i in final_agenda]
|
||||
vim.command(u_encode(u'setlocal nomodifiable conceallevel=2 concealcursor=nc'))
|
||||
# try to jump to the position of today
|
||||
try:
|
||||
vim.command(u_encode(u'normal! %sgg<CR>' % today_row))
|
||||
except:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def list_all_todos(cls, current_buffer=False):
|
||||
u""" List all todos in one buffer.
|
||||
|
||||
Args:
|
||||
current_buffer (bool):
|
||||
False: all agenda files
|
||||
True: current org_file
|
||||
"""
|
||||
if current_buffer:
|
||||
agenda_documents = vim.current.buffer.name
|
||||
loaded_agendafiles = cls._load_agendafiles([agenda_documents])
|
||||
else:
|
||||
loaded_agendafiles = cls._get_agendadocuments()
|
||||
if not loaded_agendafiles:
|
||||
return
|
||||
raw_agenda = ORGMODE.agenda_manager.get_todo(loaded_agendafiles)
|
||||
|
||||
cls.line2doc = {}
|
||||
# create buffer at bottom
|
||||
cmd = [u'setlocal filetype=orgagenda']
|
||||
cls._switch_to(u'AGENDA', cmd)
|
||||
|
||||
# format text of agenda
|
||||
final_agenda = []
|
||||
for i, h in enumerate(raw_agenda):
|
||||
tmp = u"%s %s" % (h.todo, h.title)
|
||||
final_agenda.append(tmp)
|
||||
cls.line2doc[len(final_agenda)] = (get_bufname(h.document.bufnr), h.document.bufnr, h.start)
|
||||
|
||||
# show agenda
|
||||
vim.current.buffer[:] = [u_encode(i) for i in final_agenda]
|
||||
vim.command(u_encode(u'setlocal nomodifiable conceallevel=2 concealcursor=nc'))
|
||||
|
||||
@classmethod
|
||||
def list_timeline(cls):
|
||||
"""
|
||||
List a timeline of the current buffer to get an overview of the
|
||||
current file.
|
||||
"""
|
||||
raw_agenda = ORGMODE.agenda_manager.get_timestamped_items(
|
||||
[ORGMODE.get_document()])
|
||||
|
||||
# create buffer at bottom
|
||||
cmd = [u'setlocal filetype=orgagenda']
|
||||
cls._switch_to(u'AGENDA', cmd)
|
||||
|
||||
cls.line2doc = {}
|
||||
# format text of agenda
|
||||
final_agenda = []
|
||||
for i, h in enumerate(raw_agenda):
|
||||
tmp = fmt.format('{} {}', h.todo, h.title).lstrip().rstrip()
|
||||
final_agenda.append(tmp)
|
||||
cls.line2doc[len(final_agenda)] = (get_bufname(h.document.bufnr), h.document.bufnr, h.start)
|
||||
|
||||
# show agenda
|
||||
vim.current.buffer[:] = [u_encode(i) for i in final_agenda]
|
||||
vim.command(u_encode(u'setlocal nomodifiable conceallevel=2 concealcursor=nc'))
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of the plugin.
|
||||
|
||||
Key bindings and other initialization should be done here.
|
||||
"""
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u"OrgAgendaTodo",
|
||||
function=u'%s ORGMODE.plugins[u"Agenda"].list_all_todos()' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>cat',
|
||||
menu_desrc=u'Agenda for all TODOs'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u"OrgBufferAgendaTodo",
|
||||
function=u'%s ORGMODE.plugins[u"Agenda"].list_all_todos(current_buffer=True)' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>caT',
|
||||
menu_desrc=u'Agenda for all TODOs based on current buffer'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u"OrgAgendaWeek",
|
||||
function=u'%s ORGMODE.plugins[u"Agenda"].list_next_week()' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>caa',
|
||||
menu_desrc=u'Agenda for the week'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u"OrgBufferAgendaWeek",
|
||||
function=u'%s ORGMODE.plugins[u"Agenda"].list_next_week_for_buffer()' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>caA',
|
||||
menu_desrc=u'Agenda for the week based on current buffer'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgAgendaTimeline',
|
||||
function=u'%s ORGMODE.plugins[u"Agenda"].list_timeline()' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>caL',
|
||||
menu_desrc=u'Timeline for this buffer'
|
||||
)
|
||||
316
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Date.py
Normal file
316
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Date.py
Normal file
@@ -0,0 +1,316 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
from datetime import timedelta, date, datetime
|
||||
|
||||
import operator
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import ORGMODE, echom, insert_at_cursor, get_user_input
|
||||
from orgmode import settings
|
||||
from orgmode.keybinding import Keybinding, Plug
|
||||
from orgmode.menu import Submenu, ActionEntry, add_cmd_mapping_menu
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.unicode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class Date(object):
|
||||
u"""
|
||||
Handles all date and timestamp related tasks.
|
||||
|
||||
TODO: extend functionality (calendar, repetitions, ranges). See
|
||||
http://orgmode.org/guide/Dates-and-Times.html#Dates-and-Times
|
||||
"""
|
||||
|
||||
date_regex = r"\d\d\d\d-\d\d-\d\d"
|
||||
datetime_regex = r"[A-Z]\w\w \d\d\d\d-\d\d-\d\d \d\d:\d\d>"
|
||||
|
||||
month_mapping = {
|
||||
u'jan': 1, u'feb': 2, u'mar': 3, u'apr': 4, u'may': 5,
|
||||
u'jun': 6, u'jul': 7, u'aug': 8, u'sep': 9, u'oct': 10, u'nov': 11,
|
||||
u'dec': 12}
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'Dates and Scheduling')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
# set speeddating format that is compatible with orgmode
|
||||
try:
|
||||
if int(vim.eval(u_encode(u'exists(":SpeedDatingFormat")'))) == 2:
|
||||
vim.command(u_encode(u':1SpeedDatingFormat %Y-%m-%d %a'))
|
||||
vim.command(u_encode(u':1SpeedDatingFormat %Y-%m-%d %a %H:%M'))
|
||||
else:
|
||||
echom(u'Speeddating plugin not installed. Please install it.')
|
||||
except:
|
||||
echom(u'Speeddating plugin not installed. Please install it.')
|
||||
|
||||
@classmethod
|
||||
def _modify_time(cls, startdate, modifier):
|
||||
u"""Modify the given startdate according to modifier. Return the new
|
||||
date or datetime.
|
||||
|
||||
See http://orgmode.org/manual/The-date_002ftime-prompt.html
|
||||
"""
|
||||
if modifier is None or modifier == '' or modifier == '.':
|
||||
return startdate
|
||||
|
||||
# rm crap from modifier
|
||||
modifier = modifier.strip()
|
||||
|
||||
ops = {'-': operator.sub, '+': operator.add}
|
||||
|
||||
# check real date
|
||||
date_regex = r"(\d\d\d\d)-(\d\d)-(\d\d)"
|
||||
match = re.search(date_regex, modifier)
|
||||
if match:
|
||||
year, month, day = match.groups()
|
||||
newdate = date(int(year), int(month), int(day))
|
||||
|
||||
# check abbreviated date, separated with '-'
|
||||
date_regex = u"(\\d{1,2})-(\\d+)-(\\d+)"
|
||||
match = re.search(date_regex, modifier)
|
||||
if match:
|
||||
year, month, day = match.groups()
|
||||
newdate = date(2000 + int(year), int(month), int(day))
|
||||
|
||||
# check abbreviated date, separated with '/'
|
||||
# month/day
|
||||
date_regex = u"(\\d{1,2})/(\\d{1,2})"
|
||||
match = re.search(date_regex, modifier)
|
||||
if match:
|
||||
month, day = match.groups()
|
||||
newdate = date(startdate.year, int(month), int(day))
|
||||
# date should be always in the future
|
||||
if newdate < startdate:
|
||||
newdate = date(startdate.year + 1, int(month), int(day))
|
||||
|
||||
# check full date, separated with 'space'
|
||||
# month day year
|
||||
# 'sep 12 9' --> 2009 9 12
|
||||
date_regex = u"(\\w\\w\\w) (\\d{1,2}) (\\d{1,2})"
|
||||
match = re.search(date_regex, modifier)
|
||||
if match:
|
||||
gr = match.groups()
|
||||
day = int(gr[1])
|
||||
month = int(cls.month_mapping[gr[0]])
|
||||
year = 2000 + int(gr[2])
|
||||
newdate = date(year, int(month), int(day))
|
||||
|
||||
# check days as integers
|
||||
date_regex = u"^(\\d{1,2})$"
|
||||
match = re.search(date_regex, modifier)
|
||||
if match:
|
||||
newday, = match.groups()
|
||||
newday = int(newday)
|
||||
if newday > startdate.day:
|
||||
newdate = date(startdate.year, startdate.month, newday)
|
||||
else:
|
||||
# TODO: DIRTY, fix this
|
||||
# this does NOT cover all edge cases
|
||||
newdate = startdate + timedelta(days=28)
|
||||
newdate = date(newdate.year, newdate.month, newday)
|
||||
|
||||
# check for full days: Mon, Tue, Wed, Thu, Fri, Sat, Sun
|
||||
modifier_lc = modifier.lower()
|
||||
match = re.search(u'mon|tue|wed|thu|fri|sat|sun', modifier_lc)
|
||||
if match:
|
||||
weekday_mapping = {
|
||||
u'mon': 0, u'tue': 1, u'wed': 2, u'thu': 3,
|
||||
u'fri': 4, u'sat': 5, u'sun': 6}
|
||||
diff = (weekday_mapping[modifier_lc] - startdate.weekday()) % 7
|
||||
# use next weeks weekday if current weekday is the same as modifier
|
||||
if diff == 0:
|
||||
diff = 7
|
||||
newdate = startdate + timedelta(days=diff)
|
||||
|
||||
# check for days modifier with appended d
|
||||
match = re.search(u'^(\\+|-)(\\d*)d', modifier)
|
||||
if match:
|
||||
op, days = match.groups()
|
||||
newdate = ops[op](startdate, timedelta(days=int(days)))
|
||||
|
||||
# check for days modifier without appended d
|
||||
match = re.search(u'^(\\+|-)(\\d*) |^(\\+|-)(\\d*)$', modifier)
|
||||
if match:
|
||||
groups = match.groups()
|
||||
try:
|
||||
op = groups[0]
|
||||
days = int(groups[1])
|
||||
except:
|
||||
op = groups[2]
|
||||
days = int(groups[3])
|
||||
newdate = ops[op](startdate, timedelta(days=days))
|
||||
|
||||
# check for week modifier
|
||||
match = re.search(u'^(\\+|-)(\\d+)w', modifier)
|
||||
if match:
|
||||
op, weeks = match.groups()
|
||||
newdate = ops[op](startdate, timedelta(weeks=int(weeks)))
|
||||
|
||||
# check for month modifier
|
||||
match = re.search(u'^(\\+|-)(\\d+)m', modifier)
|
||||
if match:
|
||||
op, months = match.groups()
|
||||
newdate = date(startdate.year, ops[op](startdate.month, int(months)),
|
||||
startdate.day)
|
||||
|
||||
# check for year modifier
|
||||
match = re.search(u'^(\\+|-)(\\d*)y', modifier)
|
||||
if match:
|
||||
op, years = match.groups()
|
||||
newdate = date(ops[op](startdate.year, int(years)), startdate.month,
|
||||
startdate.day)
|
||||
|
||||
# check for month day
|
||||
match = re.search(
|
||||
u'(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (\\d{1,2})',
|
||||
modifier.lower())
|
||||
if match:
|
||||
month = cls.month_mapping[match.groups()[0]]
|
||||
day = int(match.groups()[1])
|
||||
newdate = date(startdate.year, int(month), int(day))
|
||||
# date should be always in the future
|
||||
if newdate < startdate:
|
||||
newdate = date(startdate.year + 1, int(month), int(day))
|
||||
|
||||
# check abbreviated date, separated with '/'
|
||||
# month/day/year
|
||||
date_regex = u"(\\d{1,2})/(\\d+)/(\\d+)"
|
||||
match = re.search(date_regex, modifier)
|
||||
if match:
|
||||
month, day, year = match.groups()
|
||||
newdate = date(2000 + int(year), int(month), int(day))
|
||||
|
||||
# check for month day year
|
||||
# sep 12 2011
|
||||
match = re.search(
|
||||
u'(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (\\d{1,2}) (\\d{1,4})',
|
||||
modifier.lower())
|
||||
if match:
|
||||
month = int(cls.month_mapping[match.groups()[0]])
|
||||
day = int(match.groups()[1])
|
||||
if len(match.groups()[2]) < 4:
|
||||
year = 2000 + int(match.groups()[2])
|
||||
else:
|
||||
year = int(match.groups()[2])
|
||||
newdate = date(year, month, day)
|
||||
|
||||
# check for time: HH:MM
|
||||
# '12:45' --> datetime(2006, 06, 13, 12, 45))
|
||||
match = re.search(u'(\\d{1,2}):(\\d\\d)$', modifier)
|
||||
if match:
|
||||
try:
|
||||
startdate = newdate
|
||||
except:
|
||||
pass
|
||||
return datetime(
|
||||
startdate.year, startdate.month, startdate.day,
|
||||
int(match.groups()[0]), int(match.groups()[1]))
|
||||
|
||||
try:
|
||||
return newdate
|
||||
except:
|
||||
return startdate
|
||||
|
||||
@classmethod
|
||||
def insert_timestamp(cls, active=True):
|
||||
u"""
|
||||
Insert a timestamp at the cursor position.
|
||||
|
||||
TODO: show fancy calendar to pick the date from.
|
||||
TODO: add all modifier of orgmode.
|
||||
"""
|
||||
today = date.today()
|
||||
msg = u''.join([
|
||||
u'Inserting ',
|
||||
unicode(u_decode(today.strftime(u'%Y-%m-%d %a'))),
|
||||
u' | Modify date'])
|
||||
modifier = get_user_input(msg)
|
||||
|
||||
# abort if the user canceled the input prompt
|
||||
if modifier is None:
|
||||
return
|
||||
|
||||
newdate = cls._modify_time(today, modifier)
|
||||
|
||||
# format
|
||||
if isinstance(newdate, datetime):
|
||||
newdate = newdate.strftime(
|
||||
u_decode(u_encode(u'%Y-%m-%d %a %H:%M')))
|
||||
else:
|
||||
newdate = newdate.strftime(
|
||||
u_decode(u_encode(u'%Y-%m-%d %a')))
|
||||
timestamp = u'<%s>' % newdate if active else u'[%s]' % newdate
|
||||
|
||||
insert_at_cursor(timestamp)
|
||||
|
||||
@classmethod
|
||||
def insert_timestamp_with_calendar(cls, active=True):
|
||||
u"""
|
||||
Insert a timestamp at the cursor position.
|
||||
Show fancy calendar to pick the date from.
|
||||
|
||||
TODO: add all modifier of orgmode.
|
||||
"""
|
||||
if int(vim.eval(u_encode(u'exists(":CalendarH")'))) != 2:
|
||||
vim.command("echo 'Please install plugin Calendar to enable this function'")
|
||||
return
|
||||
vim.command("CalendarH")
|
||||
# backup calendar_action
|
||||
calendar_action = vim.eval("g:calendar_action")
|
||||
vim.command("let g:org_calendar_action_backup = '" + calendar_action + "'")
|
||||
vim.command("let g:calendar_action = 'CalendarAction'")
|
||||
|
||||
timestamp_template = u'<%s>' if active else u'[%s]'
|
||||
# timestamp template
|
||||
vim.command("let g:org_timestamp_template = '" + timestamp_template + "'")
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of the plugin.
|
||||
|
||||
Key bindings and other initialization should be done here.
|
||||
"""
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgDateInsertTimestampActiveCmdLine',
|
||||
key_mapping=u'<localleader>sa',
|
||||
function=u'%s ORGMODE.plugins[u"Date"].insert_timestamp()' % VIM_PY_CALL,
|
||||
menu_desrc=u'Timest&'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgDateInsertTimestampInactiveCmdLine',
|
||||
key_mapping='<localleader>si',
|
||||
function=u'%s ORGMODE.plugins[u"Date"].insert_timestamp(False)' % VIM_PY_CALL,
|
||||
menu_desrc=u'Timestamp (&inactive)'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgDateInsertTimestampActiveWithCalendar',
|
||||
key_mapping=u'<localleader>pa',
|
||||
function=u'%s ORGMODE.plugins[u"Date"].insert_timestamp_with_calendar()' % VIM_PY_CALL,
|
||||
menu_desrc=u'Timestamp with Calendar'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgDateInsertTimestampInactiveWithCalendar',
|
||||
key_mapping=u'<localleader>pi',
|
||||
function=u'%s ORGMODE.plugins[u"Date"].insert_timestamp_with_calendar(False)' % VIM_PY_CALL,
|
||||
menu_desrc=u'Timestamp with Calendar(inactive)'
|
||||
)
|
||||
|
||||
submenu = self.menu + Submenu(u'Change &Date')
|
||||
submenu + ActionEntry(u'Day &Earlier', u'<C-x>', u'<C-x>')
|
||||
submenu + ActionEntry(u'Day &Later', u'<C-a>', u'<C-a>')
|
||||
@@ -0,0 +1,328 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
from orgmode._vim import echo, echom, echoe, ORGMODE, apply_count, repeat, insert_at_cursor, indent_orgmode
|
||||
from orgmode import settings
|
||||
from orgmode.menu import Submenu, Separator, ActionEntry, add_cmd_mapping_menu
|
||||
from orgmode.keybinding import Keybinding, Plug, Command
|
||||
from orgmode.liborgmode.checkboxes import Checkbox
|
||||
from orgmode.liborgmode.dom_obj import OrderListType
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
from orgmode.py3compat.unicode_compatibility import *
|
||||
|
||||
class EditCheckbox(object):
|
||||
u"""
|
||||
Checkbox plugin.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'Edit Checkbox')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
@classmethod
|
||||
def new_checkbox(cls, below=None, plain=None):
|
||||
'''
|
||||
if below is:
|
||||
True -> create new list below current line
|
||||
False/None -> create new list above current line
|
||||
if plain is:
|
||||
True -> create a plainlist item
|
||||
False/None -> create an empty checkbox
|
||||
'''
|
||||
d = ORGMODE.get_document()
|
||||
h = d.current_heading()
|
||||
if h is None:
|
||||
return
|
||||
# init checkboxes for current heading
|
||||
h.init_checkboxes()
|
||||
c = h.current_checkbox()
|
||||
|
||||
nc = Checkbox()
|
||||
nc._heading = h
|
||||
|
||||
# default checkbox level
|
||||
level = h.level + 1
|
||||
start = vim.current.window.cursor[0] - 1
|
||||
# if no checkbox is found, insert at current line with indent level=1
|
||||
if c is None:
|
||||
h.checkboxes.append(nc)
|
||||
else:
|
||||
l = c.get_parent_list()
|
||||
idx = c.get_index_in_parent_list()
|
||||
if l is not None and idx is not None:
|
||||
l.insert(idx + (1 if below else 0), nc)
|
||||
# workaround for broken associations, Issue #165
|
||||
nc._parent = c.parent
|
||||
if below:
|
||||
if c.next_sibling:
|
||||
c.next_sibling._previous_sibling = nc
|
||||
nc._next_sibling = c.next_sibling
|
||||
c._next_sibling = nc
|
||||
nc._previous_sibling = c
|
||||
else:
|
||||
if c.previous_sibling:
|
||||
c.previous_sibling._next_sibling = nc
|
||||
nc._next_sibling = c
|
||||
nc._previous_sibling = c.previous_sibling
|
||||
c._previous_sibling = nc
|
||||
|
||||
t = c.type
|
||||
# increase key for ordered lists
|
||||
if t[-1] in OrderListType:
|
||||
try:
|
||||
num = int(t[:-1]) + (1 if below else -1)
|
||||
if num < 0:
|
||||
# don't decrease to numbers below zero
|
||||
echom(u"Can't decrement further than '0'")
|
||||
return
|
||||
t = '%d%s' % (num, t[-1])
|
||||
except ValueError:
|
||||
try:
|
||||
char = ord(t[:-1]) + (1 if below else -1)
|
||||
if below:
|
||||
if char == 91:
|
||||
# stop incrementing at Z (90)
|
||||
echom(u"Can't increment further than 'Z'")
|
||||
return
|
||||
elif char == 123:
|
||||
# increment from z (122) to A
|
||||
char = 65
|
||||
else:
|
||||
if char == 96:
|
||||
# stop decrementing at a (97)
|
||||
echom(u"Can't decrement further than 'a'")
|
||||
return
|
||||
elif char == 64:
|
||||
# decrement from A (65) to z
|
||||
char = 122
|
||||
t = u'%s%s' % (chr(char), t[-1])
|
||||
except ValueError:
|
||||
pass
|
||||
nc.type = t
|
||||
level = c.level
|
||||
|
||||
if below:
|
||||
start = c.end_of_last_child
|
||||
else:
|
||||
start = c.start
|
||||
|
||||
if plain: # only create plainlist item when requested
|
||||
nc.status = None
|
||||
nc.level = level
|
||||
|
||||
if below:
|
||||
start += 1
|
||||
# vim's buffer behave just opposite to Python's list when inserting a
|
||||
# new item. The new entry is appended in vim put prepended in Python!
|
||||
vim.current.buffer.append("") # workaround for neovim
|
||||
vim.current.buffer[start:start] = [unicode(nc)]
|
||||
del vim.current.buffer[-1] # restore from workaround for neovim
|
||||
|
||||
# update checkboxes status
|
||||
cls.update_checkboxes_status()
|
||||
|
||||
# do not start insert upon adding new checkbox, Issue #211
|
||||
if int(settings.get(u'org_prefer_insert_mode', u'1')):
|
||||
vim.command(u_encode(u'exe "normal %dgg"|startinsert!' % (start + 1, )))
|
||||
else:
|
||||
vim.command(u_encode(u'exe "normal %dgg$"' % (start + 1, )))
|
||||
|
||||
@classmethod
|
||||
def toggle(cls, checkbox=None):
|
||||
u"""
|
||||
Toggle the checkbox given in the parameter.
|
||||
If the checkbox is not given, it will toggle the current checkbox.
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
current_heading = d.current_heading()
|
||||
# init checkboxes for current heading
|
||||
if current_heading is None:
|
||||
return
|
||||
current_heading = current_heading.init_checkboxes()
|
||||
|
||||
if checkbox is None:
|
||||
# get current_checkbox
|
||||
c = current_heading.current_checkbox()
|
||||
# no checkbox found
|
||||
if c is None:
|
||||
cls.update_checkboxes_status()
|
||||
return
|
||||
else:
|
||||
c = checkbox
|
||||
|
||||
if c.status == Checkbox.STATUS_OFF or c.status is None:
|
||||
# set checkbox status on if all children are on
|
||||
if c.all_children_status()[0] == 0 or c.are_children_all(Checkbox.STATUS_ON):
|
||||
c.toggle()
|
||||
d.write_checkbox(c)
|
||||
elif c.status is None:
|
||||
c.status = Checkbox.STATUS_OFF
|
||||
d.write_checkbox(c)
|
||||
|
||||
elif c.status == Checkbox.STATUS_ON:
|
||||
if c.all_children_status()[0] == 0 or c.is_child_one(Checkbox.STATUS_OFF):
|
||||
c.toggle()
|
||||
d.write_checkbox(c)
|
||||
|
||||
elif c.status == Checkbox.STATUS_INT:
|
||||
# can't toggle intermediate state directly according to emacs orgmode
|
||||
pass
|
||||
# update checkboxes status
|
||||
cls.update_checkboxes_status()
|
||||
|
||||
@classmethod
|
||||
def _update_subtasks(cls):
|
||||
d = ORGMODE.get_document()
|
||||
h = d.current_heading()
|
||||
# init checkboxes for current heading
|
||||
h.init_checkboxes()
|
||||
# update heading subtask info
|
||||
c = h.first_checkbox
|
||||
if c is None:
|
||||
return
|
||||
total, on = c.all_siblings_status()
|
||||
h.update_subtasks(total, on)
|
||||
# update all checkboxes under current heading
|
||||
cls._update_checkboxes_subtasks(c)
|
||||
|
||||
@classmethod
|
||||
def _update_checkboxes_subtasks(cls, checkbox):
|
||||
# update checkboxes
|
||||
for c in checkbox.all_siblings():
|
||||
if c.children:
|
||||
total, on = c.first_child.all_siblings_status()
|
||||
c.update_subtasks(total, on)
|
||||
cls._update_checkboxes_subtasks(c.first_child)
|
||||
|
||||
@classmethod
|
||||
def update_checkboxes_status(cls):
|
||||
d = ORGMODE.get_document()
|
||||
h = d.current_heading()
|
||||
if h is None:
|
||||
return
|
||||
# init checkboxes for current heading
|
||||
h.init_checkboxes()
|
||||
|
||||
cls._update_checkboxes_status(h.first_checkbox)
|
||||
cls._update_subtasks()
|
||||
|
||||
@classmethod
|
||||
def _update_checkboxes_status(cls, checkbox=None):
|
||||
u""" helper function for update checkboxes status
|
||||
:checkbox: The first checkbox of this indent level
|
||||
:return: The status of the parent checkbox
|
||||
"""
|
||||
if checkbox is None:
|
||||
return
|
||||
|
||||
status_off, status_on, status_int, total = 0, 0, 0, 0
|
||||
# update all top level checkboxes' status
|
||||
for c in checkbox.all_siblings():
|
||||
current_status = c.status
|
||||
# if this checkbox is not leaf, its status should determine by all its children
|
||||
if c.all_children_status()[0] > 0:
|
||||
current_status = cls._update_checkboxes_status(c.first_child)
|
||||
|
||||
# don't update status if the checkbox has no status
|
||||
if c.status is None:
|
||||
current_status = None
|
||||
# the checkbox needs to have status
|
||||
else:
|
||||
total += 1
|
||||
|
||||
# count number of status in this checkbox level
|
||||
if current_status == Checkbox.STATUS_OFF:
|
||||
status_off += 1
|
||||
elif current_status == Checkbox.STATUS_ON:
|
||||
status_on += 1
|
||||
elif current_status == Checkbox.STATUS_INT:
|
||||
status_int += 1
|
||||
|
||||
# write status if any update
|
||||
if current_status is not None and c.status != current_status:
|
||||
c.status = current_status
|
||||
d = ORGMODE.get_document()
|
||||
d.write_checkbox(c)
|
||||
|
||||
parent_status = Checkbox.STATUS_INT
|
||||
# all silbing checkboxes are off status
|
||||
if total == 0:
|
||||
pass
|
||||
elif status_off == total:
|
||||
parent_status = Checkbox.STATUS_OFF
|
||||
# all silbing checkboxes are on status
|
||||
elif status_on == total:
|
||||
parent_status = Checkbox.STATUS_ON
|
||||
# one silbing checkbox is on or int status
|
||||
elif status_on != 0 or status_int != 0:
|
||||
parent_status = Checkbox.STATUS_INT
|
||||
# other cases
|
||||
else:
|
||||
parent_status = None
|
||||
|
||||
return parent_status
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of the plugin.
|
||||
|
||||
Key bindings and other initialization should be done here.
|
||||
"""
|
||||
# default setting if it is not already set.
|
||||
|
||||
# checkbox related operation
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgCheckBoxNewAbove',
|
||||
function=u'%s ORGMODE.plugins[u"EditCheckbox"].new_checkbox()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>cN',
|
||||
menu_desrc=u'New CheckBox Above'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgCheckBoxNewBelow',
|
||||
function=u'%s ORGMODE.plugins[u"EditCheckbox"].new_checkbox(below=True)<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>cn',
|
||||
menu_desrc=u'New CheckBox Below'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgCheckBoxToggle',
|
||||
function=u':silent! %s ORGMODE.plugins[u"EditCheckbox"].toggle()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>cc',
|
||||
menu_desrc=u'Toggle Checkbox'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgCheckBoxUpdate',
|
||||
function=u':silent! %s ORGMODE.plugins[u"EditCheckbox"].update_checkboxes_status()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>c#',
|
||||
menu_desrc=u'Update Subtasks'
|
||||
)
|
||||
# plainlist related operation
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgPlainListItemNewAbove',
|
||||
function=u'%s ORGMODE.plugins[u"EditCheckbox"].new_checkbox(plain=True)<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>cL',
|
||||
menu_desrc=u'New PlainList Item Above'
|
||||
)
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgPlainListItemNewBelow',
|
||||
function=u'%s ORGMODE.plugins[u"EditCheckbox"].new_checkbox(below=True, plain=True)<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>cl',
|
||||
menu_desrc=u'New PlainList Item Below'
|
||||
)
|
||||
@@ -0,0 +1,428 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import ORGMODE, apply_count, repeat, realign_tags
|
||||
from orgmode import settings
|
||||
from orgmode.exceptions import HeadingDomError
|
||||
from orgmode.keybinding import Keybinding, Plug, MODE_INSERT, MODE_NORMAL
|
||||
from orgmode.menu import Submenu, Separator, ActionEntry
|
||||
from orgmode.liborgmode.base import Direction
|
||||
from orgmode.liborgmode.headings import Heading
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
|
||||
class EditStructure(object):
|
||||
u""" EditStructure plugin """
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'&Edit Structure')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
@classmethod
|
||||
def new_heading(cls, below=None, insert_mode=False, end_of_last_child=False):
|
||||
u"""
|
||||
:below: True, insert heading below current heading, False,
|
||||
insert heading above current heading, None, special
|
||||
behavior for insert mode, use the current text as
|
||||
heading
|
||||
:insert_mode: True, if action is performed in insert mode
|
||||
:end_of_last_child: True, insert heading at the end of last child,
|
||||
otherwise the newly created heading will "take
|
||||
over" the current heading's children
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
current_heading = d.current_heading()
|
||||
cursor = vim.current.window.cursor[:]
|
||||
if not current_heading:
|
||||
# the user is in meta data region
|
||||
pos = cursor[0] - 1
|
||||
heading = Heading(title=d.meta_information[pos], body=d.meta_information[pos + 1:])
|
||||
d.headings.insert(0, heading)
|
||||
del d.meta_information[pos:]
|
||||
d.write()
|
||||
vim.command(u_encode(u'exe "normal %dgg"|startinsert!' % (heading.start_vim, )))
|
||||
return heading
|
||||
|
||||
# check for plain list(checkbox)
|
||||
current_heading.init_checkboxes()
|
||||
c = current_heading.current_checkbox()
|
||||
if c is not None:
|
||||
ORGMODE.plugins[u"EditCheckbox"].new_checkbox(below, not c.status)
|
||||
return
|
||||
|
||||
heading = Heading(level=current_heading.level)
|
||||
|
||||
# it's weird but this is the behavior of original orgmode
|
||||
if below is None:
|
||||
below = cursor[1] != 0 or end_of_last_child
|
||||
|
||||
# insert newly created heading
|
||||
l = current_heading.get_parent_list()
|
||||
idx = current_heading.get_index_in_parent_list()
|
||||
if l is not None and idx is not None:
|
||||
l.insert(idx + (1 if below else 0), heading)
|
||||
else:
|
||||
raise HeadingDomError(u'Current heading is not properly linked in DOM')
|
||||
|
||||
if below and not end_of_last_child:
|
||||
# append heading at the end of current heading and also take
|
||||
# over the children of current heading
|
||||
for child in current_heading.children:
|
||||
heading.children.append(child, taint=False)
|
||||
current_heading.children.remove_slice(
|
||||
0, len(current_heading.children),
|
||||
taint=False)
|
||||
|
||||
# if cursor is currently on a heading, insert parts of it into the
|
||||
# newly created heading
|
||||
if insert_mode and cursor[1] != 0 and cursor[0] == current_heading.start_vim:
|
||||
offset = cursor[1] - current_heading.level - 1 - (
|
||||
len(current_heading.todo) + 1 if current_heading.todo else 0)
|
||||
if offset < 0:
|
||||
offset = 0
|
||||
if int(settings.get(u'org_improve_split_heading', u'1')) and \
|
||||
offset > 0 and len(current_heading.title) == offset + 1 \
|
||||
and current_heading.title[offset - 1] not in (u' ', u'\t'):
|
||||
offset += 1
|
||||
heading.title = current_heading.title[offset:]
|
||||
current_heading.title = current_heading.title[:offset]
|
||||
heading.body = current_heading.body[:]
|
||||
current_heading.body = []
|
||||
|
||||
d.write()
|
||||
# do not start insert upon adding new headings, unless already in insert mode. Issue #211
|
||||
if int(settings.get(u'org_prefer_insert_mode', u'1')) or insert_mode:
|
||||
vim.command(u_encode(u'exe "normal %dgg"|startinsert!' % (heading.start_vim, )))
|
||||
else:
|
||||
vim.command(u_encode(u'exe "normal %dgg$"' % (heading.start_vim, )))
|
||||
|
||||
# return newly created heading
|
||||
return heading
|
||||
|
||||
@classmethod
|
||||
def _append_heading(cls, heading, parent):
|
||||
if heading.level <= parent.level:
|
||||
raise ValueError('Heading level not is lower than parent level: %d ! > %d' % (heading.level, parent.level))
|
||||
|
||||
if parent.children and parent.children[-1].level < heading.level:
|
||||
cls._append_heading(heading, parent.children[-1])
|
||||
else:
|
||||
parent.children.append(heading, taint=False)
|
||||
|
||||
@classmethod
|
||||
def _change_heading_level(cls, level, including_children=True, on_heading=False, insert_mode=False):
|
||||
u"""
|
||||
Change level of heading realtively with or without including children.
|
||||
|
||||
:level: the number of levels to promote/demote heading
|
||||
:including_children: True if should should be included in promoting/demoting
|
||||
:on_heading: True if promoting/demoting should only happen when the cursor is on the heading
|
||||
:insert_mode: True if vim is in insert mode
|
||||
"""
|
||||
# TODO : current promote and demote works for only headings. Since
|
||||
# checkboxes also have tree structure. We should think of
|
||||
# expanding the functionality of promoting and demoting to
|
||||
# checkboxes as well
|
||||
d = ORGMODE.get_document()
|
||||
current_heading = d.current_heading()
|
||||
if not current_heading or on_heading and current_heading.start_vim != vim.current.window.cursor[0]:
|
||||
# TODO figure out the actually pressed keybinding and feed these
|
||||
# keys instead of making keys up like this
|
||||
if level > 0:
|
||||
if insert_mode:
|
||||
vim.eval(u_encode(u'feedkeys("\\<C-t>", "n")'))
|
||||
elif including_children:
|
||||
vim.eval(u_encode(u'feedkeys(">]]", "n")'))
|
||||
elif on_heading:
|
||||
vim.eval(u_encode(u'feedkeys(">>", "n")'))
|
||||
else:
|
||||
vim.eval(u_encode(u'feedkeys(">}", "n")'))
|
||||
else:
|
||||
if insert_mode:
|
||||
vim.eval(u_encode(u'feedkeys("\\<C-d>", "n")'))
|
||||
elif including_children:
|
||||
vim.eval(u_encode(u'feedkeys("<]]", "n")'))
|
||||
elif on_heading:
|
||||
vim.eval(u_encode(u'feedkeys("<<", "n")'))
|
||||
else:
|
||||
vim.eval(u_encode(u'feedkeys("<}", "n")'))
|
||||
# return True because otherwise apply_count will not work
|
||||
return True
|
||||
|
||||
# don't allow demotion below level 1
|
||||
if current_heading.level == 1 and level < 1:
|
||||
return False
|
||||
|
||||
# reduce level of demotion to a minimum heading level of 1
|
||||
if (current_heading.level + level) < 1:
|
||||
level = 1
|
||||
|
||||
def indent(heading, ic):
|
||||
if not heading:
|
||||
return
|
||||
heading.level += level
|
||||
|
||||
if ic:
|
||||
for child in heading.children:
|
||||
indent(child, ic)
|
||||
|
||||
# save cursor position
|
||||
c = vim.current.window.cursor[:]
|
||||
|
||||
# indent the promoted/demoted heading
|
||||
indent_end_vim = current_heading.end_of_last_child_vim if including_children else current_heading.end_vim
|
||||
indent(current_heading, including_children)
|
||||
|
||||
# when changing the level of a heading, its position in the DOM
|
||||
# needs to be updated. It's likely that the heading gets a new
|
||||
# parent and new children when demoted or promoted
|
||||
|
||||
# find new parent
|
||||
p = current_heading.parent
|
||||
pl = current_heading.get_parent_list()
|
||||
ps = current_heading.previous_sibling
|
||||
nhl = current_heading.level
|
||||
|
||||
if level > 0:
|
||||
# demotion
|
||||
# subheading or top level heading
|
||||
if ps and nhl > ps.level:
|
||||
pl.remove(current_heading, taint=False)
|
||||
# find heading that is the new parent heading
|
||||
oh = ps
|
||||
h = ps
|
||||
while nhl > h.level:
|
||||
oh = h
|
||||
if h.children:
|
||||
h = h.children[-1]
|
||||
else:
|
||||
break
|
||||
np = h if nhl > h.level else oh
|
||||
|
||||
# append current heading to new heading
|
||||
np.children.append(current_heading, taint=False)
|
||||
|
||||
# if children are not included, distribute them among the
|
||||
# parent heading and it's siblings
|
||||
if not including_children:
|
||||
for h in current_heading.children[:]:
|
||||
if h and h.level <= nhl:
|
||||
cls._append_heading(h, np)
|
||||
current_heading.children.remove(h, taint=False)
|
||||
else:
|
||||
# promotion
|
||||
if p and nhl <= p.level:
|
||||
idx = current_heading.get_index_in_parent_list() + 1
|
||||
# find the new parent heading
|
||||
oh = p
|
||||
h = p
|
||||
while nhl <= h.level:
|
||||
# append new children to current heading
|
||||
for child in h.children[idx:]:
|
||||
cls._append_heading(child, current_heading)
|
||||
h.children.remove_slice(idx, len(h.children), taint=False)
|
||||
idx = h.get_index_in_parent_list() + 1
|
||||
if h.parent:
|
||||
h = h.parent
|
||||
else:
|
||||
break
|
||||
ns = oh.next_sibling
|
||||
while ns and ns.level > current_heading.level:
|
||||
nns = ns.next_sibling
|
||||
cls._append_heading(ns, current_heading)
|
||||
ns = nns
|
||||
|
||||
# append current heading to new parent heading / document
|
||||
pl.remove(current_heading, taint=False)
|
||||
if nhl > h.level:
|
||||
h.children.insert(idx, current_heading, taint=False)
|
||||
else:
|
||||
d.headings.insert(idx, current_heading, taint=False)
|
||||
|
||||
d.write()
|
||||
|
||||
# restore cursor position
|
||||
vim.current.window.cursor = (c[0], c[1] + level)
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
@realign_tags
|
||||
@repeat
|
||||
@apply_count
|
||||
def demote_heading(cls, including_children=True, on_heading=False, insert_mode=False):
|
||||
if cls._change_heading_level(1, including_children=including_children, on_heading=on_heading, insert_mode=insert_mode):
|
||||
if including_children:
|
||||
return u'OrgDemoteSubtree'
|
||||
return u'OrgDemoteHeading'
|
||||
|
||||
@classmethod
|
||||
@realign_tags
|
||||
@repeat
|
||||
@apply_count
|
||||
def promote_heading(cls, including_children=True, on_heading=False, insert_mode=False):
|
||||
if cls._change_heading_level(-1, including_children=including_children, on_heading=on_heading, insert_mode=insert_mode):
|
||||
if including_children:
|
||||
return u'OrgPromoteSubtreeNormal'
|
||||
return u'OrgPromoteHeadingNormal'
|
||||
|
||||
@classmethod
|
||||
def _move_heading(cls, direction=Direction.FORWARD, including_children=True):
|
||||
u""" Move heading up or down
|
||||
|
||||
:returns: heading or None
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
current_heading = d.current_heading()
|
||||
if not current_heading or \
|
||||
(direction == Direction.FORWARD and not current_heading.next_sibling) or \
|
||||
(direction == Direction.BACKWARD and not current_heading.previous_sibling):
|
||||
return None
|
||||
|
||||
cursor_offset = vim.current.window.cursor[0] - (current_heading._orig_start + 1)
|
||||
l = current_heading.get_parent_list()
|
||||
if l is None:
|
||||
raise HeadingDomError(u'Current heading is not properly linked in DOM')
|
||||
|
||||
if not including_children:
|
||||
if current_heading.previous_sibling:
|
||||
npl = current_heading.previous_sibling.children
|
||||
for child in current_heading.children:
|
||||
npl.append(child, taint=False)
|
||||
elif current_heading.parent:
|
||||
# if the current heading doesn't have a previous sibling it
|
||||
# must be the first heading
|
||||
np = current_heading.parent
|
||||
for child in current_heading.children:
|
||||
cls._append_heading(child, np)
|
||||
else:
|
||||
# if the current heading doesn't have a parent, its children
|
||||
# must be added as top level headings to the document
|
||||
npl = l
|
||||
for child in current_heading.children[::-1]:
|
||||
npl.insert(0, child, taint=False)
|
||||
current_heading.children.remove_slice(0, len(current_heading.children), taint=False)
|
||||
|
||||
idx = current_heading.get_index_in_parent_list()
|
||||
if idx is None:
|
||||
raise HeadingDomError(u'Current heading is not properly linked in DOM')
|
||||
|
||||
offset = 1 if direction == Direction.FORWARD else -1
|
||||
del l[idx]
|
||||
l.insert(idx + offset, current_heading)
|
||||
|
||||
d.write()
|
||||
|
||||
vim.current.window.cursor = (
|
||||
current_heading.start_vim + cursor_offset,
|
||||
vim.current.window.cursor[1])
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
@repeat
|
||||
@apply_count
|
||||
def move_heading_upward(cls, including_children=True):
|
||||
if cls._move_heading(direction=Direction.BACKWARD, including_children=including_children):
|
||||
if including_children:
|
||||
return u'OrgMoveSubtreeUpward'
|
||||
return u'OrgMoveHeadingUpward'
|
||||
|
||||
@classmethod
|
||||
@repeat
|
||||
@apply_count
|
||||
def move_heading_downward(cls, including_children=True):
|
||||
if cls._move_heading(direction=Direction.FORWARD, including_children=including_children):
|
||||
if including_children:
|
||||
return u'OrgMoveSubtreeDownward'
|
||||
return u'OrgMoveHeadingDownward'
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
# EditStructure related default settings
|
||||
settings.set(u'org_improve_split_heading', u'1')
|
||||
# EditStructure related keybindings
|
||||
self.keybindings.append(Keybinding(u'<C-S-CR>',
|
||||
Plug(u'OrgNewHeadingAboveNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].new_heading(below=False)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'New Heading &above', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'<localleader>hN', u'<Plug>OrgNewHeadingAboveNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'<localleader><CR>', u'<Plug>OrgNewHeadingAboveNormal', mode=MODE_NORMAL))
|
||||
|
||||
self.keybindings.append(Keybinding(u'<S-CR>',
|
||||
Plug(u'OrgNewHeadingBelowNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].new_heading(below=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'New Heading &below', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'<localleader>hh', u'<Plug>OrgNewHeadingBelowNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'<localleader><CR>', u'<Plug>OrgNewHeadingBelowNormal', mode=MODE_NORMAL))
|
||||
|
||||
self.keybindings.append(Keybinding(u'<C-CR>', Plug(u'OrgNewHeadingBelowAfterChildrenNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].new_heading(below=True, end_of_last_child=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'New Heading below, after &children', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'<localleader>hn', u'<Plug>OrgNewHeadingBelowAfterChildrenNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'<CR>', u'<Plug>OrgNewHeadingBelowAfterChildrenNormal', mode=MODE_NORMAL))
|
||||
|
||||
self.keybindings.append(Keybinding(u'<C-S-CR>', Plug(u'OrgNewHeadingAboveInsert', u'<C-o>:<C-u>silent! %s ORGMODE.plugins[u"EditStructure"].new_heading(below=False, insert_mode=True)<CR>' % VIM_PY_CALL, mode=MODE_INSERT)))
|
||||
self.keybindings.append(Keybinding(u'<S-CR>', Plug(u'OrgNewHeadingBelowInsert', u'<C-o>:<C-u>silent! %s ORGMODE.plugins[u"EditStructure"].new_heading(below=True, insert_mode=True)<CR>' % VIM_PY_CALL, mode=MODE_INSERT)))
|
||||
self.keybindings.append(Keybinding(u'<C-CR>', Plug(u'OrgNewHeadingBelowAfterChildrenInsert', u'<C-o>:<C-u>silent! %s ORGMODE.plugins[u"EditStructure"].new_heading(insert_mode=True, end_of_last_child=True)<CR>' % VIM_PY_CALL, mode=MODE_INSERT)))
|
||||
|
||||
self.menu + Separator()
|
||||
|
||||
self.keybindings.append(Keybinding(u'm{', Plug(u'OrgMoveHeadingUpward',
|
||||
u'%s ORGMODE.plugins[u"EditStructure"].move_heading_upward(including_children=False)<CR>' % VIM_PY_CALL)))
|
||||
self.keybindings.append(Keybinding(u'm[[',
|
||||
Plug(u'OrgMoveSubtreeUpward', u'%s ORGMODE.plugins[u"EditStructure"].move_heading_upward()<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Move Subtree &Up', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'm}',
|
||||
Plug(u'OrgMoveHeadingDownward', u'%s ORGMODE.plugins[u"EditStructure"].move_heading_downward(including_children=False)<CR>' % VIM_PY_CALL)))
|
||||
self.keybindings.append(Keybinding(u'm]]',
|
||||
Plug(u'OrgMoveSubtreeDownward', u'%s ORGMODE.plugins[u"EditStructure"].move_heading_downward()<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Move Subtree &Down', self.keybindings[-1])
|
||||
|
||||
self.menu + Separator()
|
||||
|
||||
self.menu + ActionEntry(u'&Copy Heading', u'yah', u'yah')
|
||||
self.menu + ActionEntry(u'C&ut Heading', u'dah', u'dah')
|
||||
|
||||
self.menu + Separator()
|
||||
|
||||
self.menu + ActionEntry(u'&Copy Subtree', u'yar', u'yar')
|
||||
self.menu + ActionEntry(u'C&ut Subtree', u'dar', u'dar')
|
||||
self.menu + ActionEntry(u'&Paste Subtree', u'p', u'p')
|
||||
|
||||
self.menu + Separator()
|
||||
|
||||
self.keybindings.append(Keybinding(u'<ah', Plug(u'OrgPromoteHeadingNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].promote_heading(including_children=False)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Promote Heading', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'<<', Plug(u'OrgPromoteOnHeadingNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].promote_heading(including_children=False, on_heading=True)<CR>' % VIM_PY_CALL)))
|
||||
self.keybindings.append(Keybinding(u'<{', u'<Plug>OrgPromoteHeadingNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'<ih', u'<Plug>OrgPromoteHeadingNormal', mode=MODE_NORMAL))
|
||||
|
||||
self.keybindings.append(Keybinding(u'<ar', Plug(u'OrgPromoteSubtreeNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].promote_heading()<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Promote Subtree', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'<[[', u'<Plug>OrgPromoteSubtreeNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'<ir', u'<Plug>OrgPromoteSubtreeNormal', mode=MODE_NORMAL))
|
||||
|
||||
self.keybindings.append(Keybinding(u'>ah', Plug(u'OrgDemoteHeadingNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].demote_heading(including_children=False)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Demote Heading', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'>>', Plug(u'OrgDemoteOnHeadingNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].demote_heading(including_children=False, on_heading=True)<CR>' % VIM_PY_CALL)))
|
||||
self.keybindings.append(Keybinding(u'>}', u'<Plug>OrgDemoteHeadingNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'>ih', u'<Plug>OrgDemoteHeadingNormal', mode=MODE_NORMAL))
|
||||
|
||||
self.keybindings.append(Keybinding(u'>ar', Plug(u'OrgDemoteSubtreeNormal', u':silent! %s ORGMODE.plugins[u"EditStructure"].demote_heading()<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Demote Subtree', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'>]]', u'<Plug>OrgDemoteSubtreeNormal', mode=MODE_NORMAL))
|
||||
self.keybindings.append(Keybinding(u'>ir', u'<Plug>OrgDemoteSubtreeNormal', mode=MODE_NORMAL))
|
||||
|
||||
# other keybindings
|
||||
self.keybindings.append(Keybinding(u'<C-d>', Plug(u'OrgPromoteOnHeadingInsert', u'<C-o>:silent! %s ORGMODE.plugins[u"EditStructure"].promote_heading(including_children=False, on_heading=True, insert_mode=True)<CR>' % VIM_PY_CALL, mode=MODE_INSERT)))
|
||||
self.keybindings.append(Keybinding(u'<C-t>', Plug(u'OrgDemoteOnHeadingInsert', u'<C-o>:silent! %s ORGMODE.plugins[u"EditStructure"].demote_heading(including_children=False, on_heading=True, insert_mode=True)<CR>' % VIM_PY_CALL, mode=MODE_INSERT)))
|
||||
181
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Export.py
Normal file
181
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Export.py
Normal file
@@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import ORGMODE, echoe, echom
|
||||
from orgmode.menu import Submenu, ActionEntry, add_cmd_mapping_menu
|
||||
from orgmode.keybinding import Keybinding, Plug, Command
|
||||
from orgmode import settings
|
||||
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class Export(object):
|
||||
u"""
|
||||
Export a orgmode file using emacs orgmode.
|
||||
|
||||
This is a *very simple* wrapper of the emacs/orgmode export. emacs and
|
||||
orgmode need to be installed. We simply call emacs with some options to
|
||||
export the .org.
|
||||
|
||||
TODO: Offer export options in vim. Don't use the menu.
|
||||
TODO: Maybe use a native implementation.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'Export')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
@classmethod
|
||||
def _get_init_script(cls):
|
||||
init_script = settings.get(u'org_export_init_script', u'')
|
||||
if init_script:
|
||||
init_script = os.path.expandvars(os.path.expanduser(init_script))
|
||||
if os.path.exists(init_script):
|
||||
return init_script
|
||||
else:
|
||||
echoe(u'Unable to find init script %s' % init_script)
|
||||
|
||||
@classmethod
|
||||
def _export(cls, format_):
|
||||
"""Export current file to format.
|
||||
|
||||
Args:
|
||||
format_: pdf or html
|
||||
|
||||
Returns:
|
||||
return code
|
||||
"""
|
||||
emacsbin = os.path.expandvars(os.path.expanduser(
|
||||
settings.get(u'org_export_emacs', u'/usr/bin/emacs')))
|
||||
if not os.path.exists(emacsbin):
|
||||
echoe(u'Unable to find emacs binary %s' % emacsbin)
|
||||
|
||||
# build the export command
|
||||
cmd = [
|
||||
emacsbin,
|
||||
u'-nw',
|
||||
u'--batch',
|
||||
u'--visit=%s' % vim.eval(u'expand("%:p")'),
|
||||
u'--funcall=%s' % format_
|
||||
]
|
||||
# source init script as well
|
||||
init_script = cls._get_init_script()
|
||||
if init_script:
|
||||
cmd.extend(['--script', init_script])
|
||||
|
||||
# export
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
p.wait()
|
||||
|
||||
if p.returncode != 0 or settings.get(u'org_export_verbose') == 1:
|
||||
echom('\n'.join(map(lambda x: x.decode(), p.communicate())))
|
||||
return p.returncode
|
||||
|
||||
@classmethod
|
||||
def topdf(cls):
|
||||
u"""Export the current buffer as pdf using emacs orgmode."""
|
||||
ret = cls._export(u'org-latex-export-to-pdf')
|
||||
if ret != 0:
|
||||
echoe(u'PDF export failed.')
|
||||
else:
|
||||
echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'pdf'))
|
||||
|
||||
@classmethod
|
||||
def tobeamer(cls):
|
||||
u"""Export the current buffer as beamer pdf using emacs orgmode."""
|
||||
ret = cls._export(u'org-beamer-export-to-pdf')
|
||||
if ret != 0:
|
||||
echoe(u'PDF export failed.')
|
||||
else:
|
||||
echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'pdf'))
|
||||
|
||||
@classmethod
|
||||
def tohtml(cls):
|
||||
u"""Export the current buffer as html using emacs orgmode."""
|
||||
ret = cls._export(u'org-html-export-to-html')
|
||||
if ret != 0:
|
||||
echoe(u'HTML export failed.')
|
||||
else:
|
||||
echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'html'))
|
||||
|
||||
@classmethod
|
||||
def tolatex(cls):
|
||||
u"""Export the current buffer as latex using emacs orgmode."""
|
||||
ret = cls._export(u'org-latex-export-to-latex')
|
||||
if ret != 0:
|
||||
echoe(u'latex export failed.')
|
||||
else:
|
||||
echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'tex'))
|
||||
|
||||
@classmethod
|
||||
def tomarkdown(cls):
|
||||
u"""Export the current buffer as markdown using emacs orgmode."""
|
||||
ret = cls._export(u'org-md-export-to-markdown')
|
||||
if ret != 0:
|
||||
echoe('Markdown export failed. Make sure org-md-export-to-markdown is loaded in emacs, see the manual for details.')
|
||||
else:
|
||||
echom(u'Export successful: %s.%s' % (vim.eval(u'expand("%:r")'), 'md'))
|
||||
|
||||
def register(self):
|
||||
u"""Registration and keybindings."""
|
||||
|
||||
# path to emacs executable
|
||||
settings.set(u'org_export_emacs', u'/usr/bin/emacs')
|
||||
# verbose output for export
|
||||
settings.set(u'org_export_verbose', 0)
|
||||
# allow the user to define an initialization script
|
||||
settings.set(u'org_export_init_script', u'')
|
||||
|
||||
# to PDF
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgExportToPDF',
|
||||
function=u':%s ORGMODE.plugins[u"Export"].topdf()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>ep',
|
||||
menu_desrc=u'To PDF (via Emacs)'
|
||||
)
|
||||
# to Beamer PDF
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgExportToBeamerPDF',
|
||||
function=u':%s ORGMODE.plugins[u"Export"].tobeamer()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>eb',
|
||||
menu_desrc=u'To Beamer PDF (via Emacs)'
|
||||
)
|
||||
# to latex
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgExportToLaTeX',
|
||||
function=u':%s ORGMODE.plugins[u"Export"].tolatex()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>el',
|
||||
menu_desrc=u'To LaTeX (via Emacs)'
|
||||
)
|
||||
# to HTML
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgExportToHTML',
|
||||
function=u':%s ORGMODE.plugins[u"Export"].tohtml()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>eh',
|
||||
menu_desrc=u'To HTML (via Emacs)'
|
||||
)
|
||||
# to Markdown
|
||||
add_cmd_mapping_menu(
|
||||
self,
|
||||
name=u'OrgExportToMarkdown',
|
||||
function=u':%s ORGMODE.plugins[u"Export"].tomarkdown()<CR>' % VIM_PY_CALL,
|
||||
key_mapping=u'<localleader>em',
|
||||
menu_desrc=u'To Markdown (via Emacs)'
|
||||
)
|
||||
@@ -0,0 +1,219 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import echom, ORGMODE, realign_tags
|
||||
from orgmode.menu import Submenu, Separator, ActionEntry
|
||||
from orgmode.keybinding import Keybinding, Plug, Command
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class Hyperlinks(object):
|
||||
u""" Hyperlinks plugin """
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'Hyperlinks')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
uri_match = re.compile(
|
||||
r'^\[{2}(?P<uri>[^][]*)(\]\[(?P<description>[^][]*))?\]{2}')
|
||||
|
||||
@classmethod
|
||||
def _get_link(cls, cursor=None):
|
||||
u"""
|
||||
Get the link the cursor is on and return it's URI and description
|
||||
|
||||
:cursor: None or (Line, Column)
|
||||
:returns: None if no link was found, otherwise {uri:URI,
|
||||
description:DESCRIPTION, line:LINE, start:START, end:END}
|
||||
or uri and description could be None if not set
|
||||
"""
|
||||
cursor = cursor if cursor else vim.current.window.cursor
|
||||
line = u_decode(vim.current.buffer[cursor[0] - 1])
|
||||
|
||||
# if the cursor is on the last bracket, it's not recognized as a hyperlink
|
||||
start = line.rfind(u'[[', 0, cursor[1])
|
||||
if start == -1:
|
||||
start = line.rfind(u'[[', 0, cursor[1] + 2)
|
||||
end = line.find(u']]', cursor[1])
|
||||
if end == -1:
|
||||
end = line.find(u']]', cursor[1] - 1)
|
||||
|
||||
# extract link
|
||||
if start != -1 and end != -1:
|
||||
end += 2
|
||||
match = Hyperlinks.uri_match.match(line[start:end])
|
||||
|
||||
res = {
|
||||
u'line': line,
|
||||
u'start': start,
|
||||
u'end': end,
|
||||
u'uri': None,
|
||||
u'description': None}
|
||||
if match:
|
||||
res.update(match.groupdict())
|
||||
# reverse character escaping(partly done due to matching)
|
||||
res[u'uri'] = res[u'uri'].replace(u'\\\\', u'\\')
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def follow(cls, action=u'openLink', visual=u''):
|
||||
u""" Follow hyperlink. If called on a regular string UTL determines the
|
||||
outcome. Normally a file with that name will be opened.
|
||||
|
||||
:action: "copy" if the link should be copied to clipboard, otherwise
|
||||
the link will be opened
|
||||
:visual: "visual" if Universal Text Linking should be triggered in
|
||||
visual mode
|
||||
|
||||
:returns: URI or None
|
||||
"""
|
||||
if not int(vim.eval(u'exists(":Utl")')):
|
||||
echom(u'Universal Text Linking plugin not installed, unable to proceed.')
|
||||
return
|
||||
|
||||
action = u'copyLink' \
|
||||
if (action and action.startswith(u'copy')) \
|
||||
else u'openLink'
|
||||
visual = u'visual' if visual and visual.startswith(u'visual') else u''
|
||||
|
||||
link = Hyperlinks._get_link()
|
||||
|
||||
if link and link[u'uri'] is not None:
|
||||
# call UTL with the URI
|
||||
vim.command(u_encode(u'Utl %s %s %s' % (action, visual, link[u'uri'])))
|
||||
return link[u'uri']
|
||||
else:
|
||||
# call UTL and let it decide what to do
|
||||
vim.command(u_encode(u'Utl %s %s' % (action, visual)))
|
||||
|
||||
@classmethod
|
||||
@realign_tags
|
||||
def insert(cls, uri=None, description=None):
|
||||
u""" Inserts a hyperlink. If no arguments are provided, an interactive
|
||||
query will be started.
|
||||
|
||||
:uri: The URI that will be opened
|
||||
:description: An optional description that will be displayed instead of
|
||||
the URI
|
||||
|
||||
:returns: (URI, description)
|
||||
"""
|
||||
link = Hyperlinks._get_link()
|
||||
if link:
|
||||
if uri is None and link[u'uri'] is not None:
|
||||
uri = link[u'uri']
|
||||
if description is None and link[u'description'] is not None:
|
||||
description = link[u'description']
|
||||
|
||||
if uri is None:
|
||||
uri = vim.eval(u'input("Link: ", "", "file")')
|
||||
elif link:
|
||||
uri = vim.eval(u'input("Link: ", "%s", "file")' % link[u'uri'])
|
||||
if uri is None:
|
||||
return
|
||||
else:
|
||||
uri = u_decode(uri)
|
||||
|
||||
# character escaping
|
||||
uri = uri.replace(u'\\', u'\\\\\\\\')
|
||||
uri = uri.replace(u' ', u'\\ ')
|
||||
|
||||
if description is None:
|
||||
description = u_decode(vim.eval(u'input("Description: ")'))
|
||||
elif link:
|
||||
description = vim.eval(
|
||||
u'input("Description: ", "%s")' %
|
||||
u_decode(link[u'description']))
|
||||
if description is None:
|
||||
return
|
||||
|
||||
cursor = vim.current.window.cursor
|
||||
cl = u_decode(vim.current.buffer[cursor[0] - 1])
|
||||
head = cl[:cursor[1] + 1] if not link else cl[:link[u'start']]
|
||||
tail = cl[cursor[1] + 1:] if not link else cl[link[u'end']:]
|
||||
|
||||
separator = u''
|
||||
if description:
|
||||
separator = u']['
|
||||
|
||||
if uri or description:
|
||||
vim.current.buffer[cursor[0] - 1] = \
|
||||
u_encode(u''.join((head, u'[[%s%s%s]]' % (uri, separator, description), tail)))
|
||||
elif link:
|
||||
vim.current.buffer[cursor[0] - 1] = \
|
||||
u_encode(u''.join((head, tail)))
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
cmd = Command(
|
||||
u'OrgHyperlinkFollow',
|
||||
u'%s ORGMODE.plugins[u"Hyperlinks"].follow()' % VIM_PY_CALL)
|
||||
self.commands.append(cmd)
|
||||
self.keybindings.append(
|
||||
Keybinding(u'gl', Plug(u'OrgHyperlinkFollow', self.commands[-1])))
|
||||
self.menu + ActionEntry(u'&Follow Link', self.keybindings[-1])
|
||||
|
||||
cmd = Command(
|
||||
u'OrgHyperlinkCopy',
|
||||
u'%s ORGMODE.plugins[u"Hyperlinks"].follow(action=u"copy")' % VIM_PY_CALL)
|
||||
self.commands.append(cmd)
|
||||
self.keybindings.append(
|
||||
Keybinding(u'gyl', Plug(u'OrgHyperlinkCopy', self.commands[-1])))
|
||||
self.menu + ActionEntry(u'&Copy Link', self.keybindings[-1])
|
||||
|
||||
cmd = Command(
|
||||
u'OrgHyperlinkInsert',
|
||||
u'%s ORGMODE.plugins[u"Hyperlinks"].insert(<f-args>)' % VIM_PY_CALL,
|
||||
arguments=u'*')
|
||||
self.commands.append(cmd)
|
||||
self.keybindings.append(
|
||||
Keybinding(u'gil', Plug(u'OrgHyperlinkInsert', self.commands[-1])))
|
||||
self.menu + ActionEntry(u'&Insert Link', self.keybindings[-1])
|
||||
|
||||
self.menu + Separator()
|
||||
|
||||
# find next link
|
||||
cmd = Command(
|
||||
u'OrgHyperlinkNextLink',
|
||||
u":if search('\\[\\{2}\\zs[^][]*\\(\\]\\[[^][]*\\)\\?\\ze\\]\\{2}', 's') == 0 | echo 'No further link found.' | endif")
|
||||
self.commands.append(cmd)
|
||||
self.keybindings.append(
|
||||
Keybinding(u'gn', Plug(u'OrgHyperlinkNextLink', self.commands[-1])))
|
||||
self.menu + ActionEntry(u'&Next Link', self.keybindings[-1])
|
||||
|
||||
# find previous link
|
||||
cmd = Command(
|
||||
u'OrgHyperlinkPreviousLink',
|
||||
u":if search('\\[\\{2}\\zs[^][]*\\(\\]\\[[^][]*\\)\\?\\ze\\]\\{2}', 'bs') == 0 | echo 'No further link found.' | endif")
|
||||
self.commands.append(cmd)
|
||||
self.keybindings.append(
|
||||
Keybinding(u'go', Plug(u'OrgHyperlinkPreviousLink', self.commands[-1])))
|
||||
self.menu + ActionEntry(u'&Previous Link', self.keybindings[-1])
|
||||
|
||||
self.menu + Separator()
|
||||
|
||||
# Descriptive Links
|
||||
cmd = Command(u'OrgHyperlinkDescriptiveLinks', u':setlocal cole=2')
|
||||
self.commands.append(cmd)
|
||||
self.menu + ActionEntry(u'&Descriptive Links', self.commands[-1])
|
||||
|
||||
# Literal Links
|
||||
cmd = Command(u'OrgHyperlinkLiteralLinks', u':setlocal cole=0')
|
||||
self.commands.append(cmd)
|
||||
self.menu + ActionEntry(u'&Literal Links', self.commands[-1])
|
||||
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import echo, echom, echoe, ORGMODE, apply_count, repeat
|
||||
from orgmode.menu import Submenu, Separator, ActionEntry
|
||||
from orgmode.keybinding import Keybinding, Plug, Command
|
||||
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class LoggingWork(object):
|
||||
u""" LoggingWork plugin """
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'&Logging work')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
@classmethod
|
||||
def action(cls):
|
||||
u""" Some kind of action
|
||||
|
||||
:returns: TODO
|
||||
"""
|
||||
pass
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
# an Action menu entry which binds "keybinding" to action ":action"
|
||||
self.commands.append(Command(u'OrgLoggingRecordDoneTime', u'%s ORGMODE.plugins[u"LoggingWork"].action()' % VIM_PY_CALL))
|
||||
self.menu + ActionEntry(u'&Record DONE time', self.commands[-1])
|
||||
171
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Misc.py
Normal file
171
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Misc.py
Normal file
@@ -0,0 +1,171 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import ORGMODE, apply_count
|
||||
from orgmode.menu import Submenu
|
||||
from orgmode.keybinding import Keybinding, Plug, MODE_VISUAL, MODE_OPERATOR
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class Misc(object):
|
||||
u""" Miscellaneous functionality """
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'Misc')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
@classmethod
|
||||
def jump_to_first_character(cls):
|
||||
heading = ORGMODE.get_document().current_heading()
|
||||
if not heading or heading.start_vim != vim.current.window.cursor[0]:
|
||||
vim.eval(u_encode(u'feedkeys("^", "n")'))
|
||||
return
|
||||
|
||||
vim.current.window.cursor = (vim.current.window.cursor[0], heading.level + 1)
|
||||
|
||||
@classmethod
|
||||
def edit_at_first_character(cls):
|
||||
heading = ORGMODE.get_document().current_heading()
|
||||
if not heading or heading.start_vim != vim.current.window.cursor[0]:
|
||||
vim.eval(u_encode(u'feedkeys("I", "n")'))
|
||||
return
|
||||
|
||||
vim.current.window.cursor = (vim.current.window.cursor[0], heading.level + 1)
|
||||
vim.command(u_encode(u'startinsert'))
|
||||
|
||||
# @repeat
|
||||
@classmethod
|
||||
@apply_count
|
||||
def i_heading(cls, mode=u'visual', selection=u'inner', skip_children=False):
|
||||
u"""
|
||||
inner heading text object
|
||||
"""
|
||||
heading = ORGMODE.get_document().current_heading()
|
||||
if heading:
|
||||
if selection != u'inner':
|
||||
heading = heading if not heading.parent else heading.parent
|
||||
|
||||
line_start, col_start = [int(i) for i in vim.eval(u_encode(u'getpos("\'<")'))[1:3]]
|
||||
line_end, col_end = [int(i) for i in vim.eval(u_encode(u'getpos("\'>")'))[1:3]]
|
||||
|
||||
if mode != u'visual':
|
||||
line_start = vim.current.window.cursor[0]
|
||||
line_end = line_start
|
||||
|
||||
start = line_start
|
||||
end = line_end
|
||||
move_one_character_back = u'' if mode == u'visual' else u'h'
|
||||
|
||||
if heading.start_vim < line_start:
|
||||
start = heading.start_vim
|
||||
if heading.end_vim > line_end and not skip_children:
|
||||
end = heading.end_vim
|
||||
elif heading.end_of_last_child_vim > line_end and skip_children:
|
||||
end = heading.end_of_last_child_vim
|
||||
|
||||
if mode != u'visual' and not vim.current.buffer[end - 1]:
|
||||
end -= 1
|
||||
move_one_character_back = u''
|
||||
|
||||
swap_cursor = u'o' if vim.current.window.cursor[0] == line_start else u''
|
||||
|
||||
if selection == u'inner' and vim.current.window.cursor[0] != line_start:
|
||||
h = ORGMODE.get_document().current_heading()
|
||||
if h:
|
||||
heading = h
|
||||
|
||||
visualmode = u_decode(vim.eval(u'visualmode()')) if mode == u'visual' else u'v'
|
||||
|
||||
if line_start == start and line_start != heading.start_vim:
|
||||
if col_start in (0, 1):
|
||||
vim.command(u_encode(u'normal! %dgg0%s%dgg$%s%s' % (start, visualmode, end, move_one_character_back, swap_cursor)))
|
||||
else:
|
||||
vim.command(u_encode(u'normal! %dgg0%dl%s%dgg$%s%s' % (start, col_start - 1, visualmode, end, move_one_character_back, swap_cursor)))
|
||||
else:
|
||||
vim.command(u_encode(u'normal! %dgg0%dl%s%dgg$%s%s' % (start, heading.level + 1, visualmode, end, move_one_character_back, swap_cursor)))
|
||||
|
||||
if selection == u'inner':
|
||||
if mode == u'visual':
|
||||
return u'OrgInnerHeadingVisual' if not skip_children else u'OrgInnerTreeVisual'
|
||||
else:
|
||||
return u'OrgInnerHeadingOperator' if not skip_children else u'OrgInnerTreeOperator'
|
||||
else:
|
||||
if mode == u'visual':
|
||||
return u'OrgOuterHeadingVisual' if not skip_children else u'OrgOuterTreeVisual'
|
||||
else:
|
||||
return u'OrgOuterHeadingOperator' if not skip_children else u'OrgOuterTreeOperator'
|
||||
elif mode == u'visual':
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
|
||||
# @repeat
|
||||
@classmethod
|
||||
@apply_count
|
||||
def a_heading(cls, selection=u'inner', skip_children=False):
|
||||
u"""
|
||||
a heading text object
|
||||
"""
|
||||
heading = ORGMODE.get_document().current_heading()
|
||||
if heading:
|
||||
if selection != u'inner':
|
||||
heading = heading if not heading.parent else heading.parent
|
||||
|
||||
line_start, col_start = [int(i) for i in vim.eval(u_encode(u'getpos("\'<")'))[1:3]]
|
||||
line_end, col_end = [int(i) for i in vim.eval(u_encode(u'getpos("\'>")'))[1:3]]
|
||||
|
||||
start = line_start
|
||||
end = line_end
|
||||
|
||||
if heading.start_vim < line_start:
|
||||
start = heading.start_vim
|
||||
if heading.end_vim > line_end and not skip_children:
|
||||
end = heading.end_vim
|
||||
elif heading.end_of_last_child_vim > line_end and skip_children:
|
||||
end = heading.end_of_last_child_vim
|
||||
|
||||
swap_cursor = u'o' if vim.current.window.cursor[0] == line_start else u''
|
||||
|
||||
vim.command(u_encode(u'normal! %dgg%s%dgg$%s' % (start, vim.eval(u_encode(u'visualmode()')), end, swap_cursor)))
|
||||
if selection == u'inner':
|
||||
return u'OrgAInnerHeadingVisual' if not skip_children else u'OrgAInnerTreeVisual'
|
||||
else:
|
||||
return u'OrgAOuterHeadingVisual' if not skip_children else u'OrgAOuterTreeVisual'
|
||||
else:
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
self.keybindings.append(Keybinding(u'^',
|
||||
Plug(u'OrgJumpToFirstCharacter', u'%s ORGMODE.plugins[u"Misc"].jump_to_first_character()<CR>' % VIM_PY_CALL)))
|
||||
self.keybindings.append(Keybinding(u'I',
|
||||
Plug(u'OrgEditAtFirstCharacter', u'%s ORGMODE.plugins[u"Misc"].edit_at_first_character()<CR>' % VIM_PY_CALL)))
|
||||
|
||||
self.keybindings.append(Keybinding(u'ih', Plug(u'OrgInnerHeadingVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading()<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'ah', Plug(u'OrgAInnerHeadingVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].a_heading()<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'Oh', Plug(u'OrgOuterHeadingVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(selection=u"outer")<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'OH', Plug(u'OrgAOuterHeadingVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].a_heading(selection=u"outer")<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
|
||||
self.keybindings.append(Keybinding(u'ih', Plug(u'OrgInnerHeadingOperator', u':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator")<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'ah', u':normal Vah<CR>', mode=MODE_OPERATOR))
|
||||
self.keybindings.append(Keybinding(u'Oh', Plug(u'OrgOuterHeadingOperator', ':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator", selection=u"outer")<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'OH', u':normal VOH<CR>', mode=MODE_OPERATOR))
|
||||
|
||||
self.keybindings.append(Keybinding(u'ir', Plug(u'OrgInnerTreeVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'ar', Plug(u'OrgAInnerTreeVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].a_heading(skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'Or', Plug(u'OrgOuterTreeVisual', u'<:<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(selection=u"outer", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'OR', Plug(u'OrgAOuterTreeVisual', u':<C-u>%s ORGMODE.plugins[u"Misc"].a_heading(selection=u"outer", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
|
||||
self.keybindings.append(Keybinding(u'ir', Plug(u'OrgInnerTreeOperator', u':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'ar', u':normal Var<CR>', mode=MODE_OPERATOR))
|
||||
self.keybindings.append(Keybinding(u'Or', Plug(u'OrgOuterTreeOperator', u':<C-u>%s ORGMODE.plugins[u"Misc"].i_heading(mode=u"operator", selection=u"outer", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'OR', u':normal VOR<CR>', mode=MODE_OPERATOR))
|
||||
@@ -0,0 +1,324 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import echo, ORGMODE, apply_count
|
||||
from orgmode.menu import Submenu, ActionEntry
|
||||
from orgmode.keybinding import Keybinding, MODE_VISUAL, MODE_OPERATOR, Plug
|
||||
from orgmode.liborgmode.documents import Direction
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class Navigator(object):
|
||||
u""" Implement navigation in org-mode documents """
|
||||
|
||||
def __init__(self):
|
||||
object.__init__(self)
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'&Navigate Headings')
|
||||
self.keybindings = []
|
||||
|
||||
@classmethod
|
||||
@apply_count
|
||||
def parent(cls, mode):
|
||||
u"""
|
||||
Focus parent heading
|
||||
|
||||
:returns: parent heading or None
|
||||
"""
|
||||
heading = ORGMODE.get_document().current_heading()
|
||||
if not heading:
|
||||
if mode == u'visual':
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
else:
|
||||
echo(u'No heading found')
|
||||
return
|
||||
|
||||
if not heading.parent:
|
||||
if mode == u'visual':
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
else:
|
||||
echo(u'No parent heading found')
|
||||
return
|
||||
|
||||
p = heading.parent
|
||||
|
||||
if mode == u'visual':
|
||||
cls._change_visual_selection(heading, p, direction=Direction.BACKWARD, parent=True)
|
||||
else:
|
||||
vim.current.window.cursor = (p.start_vim, p.level + 1)
|
||||
return p
|
||||
|
||||
@classmethod
|
||||
@apply_count
|
||||
def parent_next_sibling(cls, mode):
|
||||
u"""
|
||||
Focus the parent's next sibling
|
||||
|
||||
:returns: parent's next sibling heading or None
|
||||
"""
|
||||
heading = ORGMODE.get_document().current_heading()
|
||||
if not heading:
|
||||
if mode == u'visual':
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
else:
|
||||
echo(u'No heading found')
|
||||
return
|
||||
|
||||
if not heading.parent or not heading.parent.next_sibling:
|
||||
if mode == u'visual':
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
else:
|
||||
echo(u'No parent heading found')
|
||||
return
|
||||
|
||||
ns = heading.parent.next_sibling
|
||||
|
||||
if mode == u'visual':
|
||||
cls._change_visual_selection(heading, ns, direction=Direction.FORWARD, parent=False)
|
||||
elif mode == u'operator':
|
||||
vim.current.window.cursor = (ns.start_vim, 0)
|
||||
else:
|
||||
vim.current.window.cursor = (ns.start_vim, ns.level + 1)
|
||||
return ns
|
||||
|
||||
@classmethod
|
||||
def _change_visual_selection(cls, current_heading, heading, direction=Direction.FORWARD, noheadingfound=False, parent=False):
|
||||
current = vim.current.window.cursor[0]
|
||||
line_start, col_start = [int(i) for i in vim.eval(u_encode(u'getpos("\'<")'))[1:3]]
|
||||
line_end, col_end = [int(i) for i in vim.eval(u_encode(u'getpos("\'>")'))[1:3]]
|
||||
|
||||
f_start = heading.start_vim
|
||||
f_end = heading.end_vim
|
||||
swap_cursor = True
|
||||
|
||||
# << |visual start
|
||||
# selection end >>
|
||||
if current == line_start:
|
||||
if (direction == Direction.FORWARD and line_end < f_start) or noheadingfound and not direction == Direction.BACKWARD:
|
||||
swap_cursor = False
|
||||
|
||||
# focus heading HERE
|
||||
# << |visual start
|
||||
# selection end >>
|
||||
|
||||
# << |visual start
|
||||
# focus heading HERE
|
||||
# selection end >>
|
||||
if f_start < line_start and direction == Direction.BACKWARD:
|
||||
if current_heading.start_vim < line_start and not parent:
|
||||
line_start = current_heading.start_vim
|
||||
else:
|
||||
line_start = f_start
|
||||
|
||||
elif (f_start < line_start or f_start < line_end) and not noheadingfound:
|
||||
line_start = f_start
|
||||
|
||||
# << |visual start
|
||||
# selection end >>
|
||||
# focus heading HERE
|
||||
else:
|
||||
if direction == Direction.FORWARD:
|
||||
if line_end < f_start and not line_start == f_start - 1 and current_heading:
|
||||
# focus end of previous heading instead of beginning of next heading
|
||||
line_start = line_end
|
||||
line_end = f_start - 1
|
||||
else:
|
||||
# focus end of next heading
|
||||
line_start = line_end
|
||||
line_end = f_end
|
||||
elif direction == Direction.BACKWARD:
|
||||
if line_end < f_end:
|
||||
pass
|
||||
else:
|
||||
line_start = line_end
|
||||
line_end = f_end
|
||||
|
||||
# << visual start
|
||||
# selection end| >>
|
||||
else:
|
||||
# focus heading HERE
|
||||
# << visual start
|
||||
# selection end| >>
|
||||
if line_start > f_start and line_end > f_end and not parent:
|
||||
line_end = f_end
|
||||
swap_cursor = False
|
||||
|
||||
elif (line_start > f_start or line_start == f_start) and \
|
||||
line_end <= f_end and direction == Direction.BACKWARD:
|
||||
line_end = line_start
|
||||
line_start = f_start
|
||||
|
||||
# << visual start
|
||||
# selection end and focus heading end HERE| >>
|
||||
|
||||
# << visual start
|
||||
# focus heading HERE
|
||||
# selection end| >>
|
||||
|
||||
# << visual start
|
||||
# selection end| >>
|
||||
# focus heading HERE
|
||||
else:
|
||||
if direction == Direction.FORWARD:
|
||||
if line_end < f_start - 1:
|
||||
# focus end of previous heading instead of beginning of next heading
|
||||
line_end = f_start - 1
|
||||
else:
|
||||
# focus end of next heading
|
||||
line_end = f_end
|
||||
else:
|
||||
line_end = f_end
|
||||
swap_cursor = False
|
||||
|
||||
move_col_start = u'%dl' % (col_start - 1) if (col_start - 1) > 0 and (col_start - 1) < 2000000000 else u''
|
||||
move_col_end = u'%dl' % (col_end - 1) if (col_end - 1) > 0 and (col_end - 1) < 2000000000 else u''
|
||||
swap = u'o' if swap_cursor else u''
|
||||
|
||||
vim.command(u_encode(u'normal! %dgg%s%s%dgg%s%s' % (line_start, move_col_start, vim.eval(u_encode(u'visualmode()')), line_end, move_col_end, swap)))
|
||||
|
||||
@classmethod
|
||||
def _focus_heading(cls, mode, direction=Direction.FORWARD, skip_children=False):
|
||||
u"""
|
||||
Focus next or previous heading in the given direction
|
||||
|
||||
:direction: True for next heading, False for previous heading
|
||||
:returns: next heading or None
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
current_heading = d.current_heading()
|
||||
heading = current_heading
|
||||
focus_heading = None
|
||||
# FIXME this is just a piece of really ugly and unmaintainable code. It
|
||||
# should be rewritten
|
||||
if not heading:
|
||||
if direction == Direction.FORWARD and d.headings \
|
||||
and vim.current.window.cursor[0] < d.headings[0].start_vim:
|
||||
# the cursor is in the meta information are, therefore focus
|
||||
# first heading
|
||||
focus_heading = d.headings[0]
|
||||
if not (heading or focus_heading):
|
||||
if mode == u'visual':
|
||||
# restore visual selection when no heading was found
|
||||
vim.command(u_encode(u'normal! gv'))
|
||||
else:
|
||||
echo(u'No heading found')
|
||||
return
|
||||
elif direction == Direction.BACKWARD:
|
||||
if vim.current.window.cursor[0] != heading.start_vim:
|
||||
# the cursor is in the body of the current heading, therefore
|
||||
# the current heading will be focused
|
||||
if mode == u'visual':
|
||||
line_start, col_start = [int(i) for i in
|
||||
vim.eval(u_encode(u'getpos("\'<")'))[1:3]]
|
||||
line_end, col_end = [int(i) for i in vim.eval(u_encode(u'getpos("\'>")'))[1:3]]
|
||||
if line_start >= heading.start_vim and line_end > heading.start_vim:
|
||||
focus_heading = heading
|
||||
else:
|
||||
focus_heading = heading
|
||||
|
||||
# so far no heading has been found that the next focus should be on
|
||||
if not focus_heading:
|
||||
if not skip_children and direction == Direction.FORWARD and heading.children:
|
||||
focus_heading = heading.children[0]
|
||||
elif direction == Direction.FORWARD and heading.next_sibling:
|
||||
focus_heading = heading.next_sibling
|
||||
elif direction == Direction.BACKWARD and heading.previous_sibling:
|
||||
focus_heading = heading.previous_sibling
|
||||
if not skip_children:
|
||||
while focus_heading.children:
|
||||
focus_heading = focus_heading.children[-1]
|
||||
else:
|
||||
if direction == Direction.FORWARD:
|
||||
focus_heading = current_heading.next_heading
|
||||
else:
|
||||
focus_heading = current_heading.previous_heading
|
||||
|
||||
noheadingfound = False
|
||||
if not focus_heading:
|
||||
if mode in (u'visual', u'operator'):
|
||||
# the cursor seems to be on the last or first heading of this
|
||||
# document and performs another next/previous operation
|
||||
focus_heading = heading
|
||||
noheadingfound = True
|
||||
else:
|
||||
if direction == Direction.FORWARD:
|
||||
echo(u'Already focussing last heading')
|
||||
else:
|
||||
echo(u'Already focussing first heading')
|
||||
return
|
||||
|
||||
if mode == u'visual':
|
||||
cls._change_visual_selection(current_heading, focus_heading, direction=direction, noheadingfound=noheadingfound)
|
||||
elif mode == u'operator':
|
||||
if direction == Direction.FORWARD and vim.current.window.cursor[0] >= focus_heading.start_vim:
|
||||
vim.current.window.cursor = (focus_heading.end_vim, len(u_decode(vim.current.buffer[focus_heading.end])))
|
||||
else:
|
||||
vim.current.window.cursor = (focus_heading.start_vim, 0)
|
||||
else:
|
||||
vim.current.window.cursor = (focus_heading.start_vim, focus_heading.level + 1)
|
||||
if noheadingfound:
|
||||
return
|
||||
return focus_heading
|
||||
|
||||
@classmethod
|
||||
@apply_count
|
||||
def previous(cls, mode, skip_children=False):
|
||||
u"""
|
||||
Focus previous heading
|
||||
"""
|
||||
return cls._focus_heading(mode, direction=Direction.BACKWARD, skip_children=skip_children)
|
||||
|
||||
@classmethod
|
||||
@apply_count
|
||||
def next(cls, mode, skip_children=False):
|
||||
u"""
|
||||
Focus next heading
|
||||
"""
|
||||
return cls._focus_heading(mode, direction=Direction.FORWARD, skip_children=skip_children)
|
||||
|
||||
def register(self):
|
||||
# normal mode
|
||||
self.keybindings.append(Keybinding(u'g{', Plug('OrgJumpToParentNormal',
|
||||
u'%s ORGMODE.plugins[u"Navigator"].parent(mode=u"normal")<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Up', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'g}',
|
||||
Plug('OrgJumpToParentsSiblingNormal', u'%s ORGMODE.plugins[u"Navigator"].parent_next_sibling(mode=u"normal")<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Down', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'{',
|
||||
Plug(u'OrgJumpToPreviousNormal', u'%s ORGMODE.plugins[u"Navigator"].previous(mode=u"normal")<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Previous', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u'}', Plug(u'OrgJumpToNextNormal',
|
||||
u'%s ORGMODE.plugins[u"Navigator"].next(mode=u"normal")<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Next', self.keybindings[-1])
|
||||
|
||||
# visual mode
|
||||
self.keybindings.append(Keybinding(u'g{', Plug(u'OrgJumpToParentVisual', u'<Esc>:<C-u>%s ORGMODE.plugins[u"Navigator"].parent(mode=u"visual")<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'g}', Plug('OrgJumpToParentsSiblingVisual', u'<Esc>:<C-u>%s ORGMODE.plugins[u"Navigator"].parent_next_sibling(mode=u"visual")<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'{', Plug(u'OrgJumpToPreviousVisual', u'<Esc>:<C-u>%s ORGMODE.plugins[u"Navigator"].previous(mode=u"visual")<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u'}', Plug(u'OrgJumpToNextVisual', u'<Esc>:<C-u>%s ORGMODE.plugins[u"Navigator"].next(mode=u"visual")<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
|
||||
# operator-pending mode
|
||||
self.keybindings.append(Keybinding(u'g{', Plug(u'OrgJumpToParentOperator', u':<C-u>%s ORGMODE.plugins[u"Navigator"].parent(mode=u"operator")<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'g}', Plug('OrgJumpToParentsSiblingOperator', u':<C-u>%s ORGMODE.plugins[u"Navigator"].parent_next_sibling(mode=u"operator")<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'{', Plug(u'OrgJumpToPreviousOperator', u':<C-u>%s ORGMODE.plugins[u"Navigator"].previous(mode=u"operator")<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u'}', Plug(u'OrgJumpToNextOperator', u':<C-u>%s ORGMODE.plugins[u"Navigator"].next(mode=u"operator")<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
|
||||
# section wise movement (skip children)
|
||||
# normal mode
|
||||
self.keybindings.append(Keybinding(u'[[',
|
||||
Plug(u'OrgJumpToPreviousSkipChildrenNormal',
|
||||
u'%s ORGMODE.plugins[u"Navigator"].previous(mode=u"normal", skip_children=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Ne&xt Same Level', self.keybindings[-1])
|
||||
self.keybindings.append(Keybinding(u']]',
|
||||
Plug(u'OrgJumpToNextSkipChildrenNormal',
|
||||
u'%s ORGMODE.plugins[u"Navigator"].next(mode=u"normal", skip_children=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Pre&vious Same Level', self.keybindings[-1])
|
||||
|
||||
# visual mode
|
||||
self.keybindings.append(Keybinding(u'[[', Plug(u'OrgJumpToPreviousSkipChildrenVisual', u'<Esc>:<C-u>%s ORGMODE.plugins[u"Navigator"].previous(mode=u"visual", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
self.keybindings.append(Keybinding(u']]', Plug(u'OrgJumpToNextSkipChildrenVisual', u'<Esc>:<C-u>%s ORGMODE.plugins[u"Navigator"].next(mode=u"visual", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_VISUAL)))
|
||||
|
||||
# operator-pending mode
|
||||
self.keybindings.append(Keybinding(u'[[', Plug(u'OrgJumpToPreviousSkipChildrenOperator', u':<C-u>%s ORGMODE.plugins[u"Navigator"].previous(mode=u"operator", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
self.keybindings.append(Keybinding(u']]', Plug(u'OrgJumpToNextSkipChildrenOperator', u':<C-u>%s ORGMODE.plugins[u"Navigator"].next(mode=u"operator", skip_children=True)<CR>' % VIM_PY_CALL, mode=MODE_OPERATOR)))
|
||||
181
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/ShowHide.py
Normal file
181
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/ShowHide.py
Normal file
@@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode.liborgmode.headings import Heading
|
||||
from orgmode._vim import ORGMODE, apply_count
|
||||
from orgmode import settings
|
||||
from orgmode.menu import Submenu, ActionEntry
|
||||
from orgmode.keybinding import Keybinding, Plug, MODE_NORMAL
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.xrange_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class ShowHide(object):
|
||||
u""" Show Hide plugin """
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'&Show Hide')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
@classmethod
|
||||
def _fold_depth(cls, h):
|
||||
""" Find the deepest level of open folds
|
||||
|
||||
:h: Heading
|
||||
:returns: Tuple (int - level of open folds, boolean - found fold) or None if h is not a Heading
|
||||
"""
|
||||
if not isinstance(h, Heading):
|
||||
return
|
||||
|
||||
if int(vim.eval(u_encode(u'foldclosed(%d)' % h.start_vim))) != -1:
|
||||
return (h.number_of_parents, True)
|
||||
|
||||
res = [h.number_of_parents + 1]
|
||||
found = False
|
||||
for c in h.children:
|
||||
d, f = cls._fold_depth(c)
|
||||
res.append(d)
|
||||
found |= f
|
||||
|
||||
return (max(res), found)
|
||||
|
||||
@classmethod
|
||||
@apply_count
|
||||
def toggle_folding(cls, reverse=False):
|
||||
u""" Toggle folding similar to the way orgmode does
|
||||
|
||||
This is just a convenience function, don't hesitate to use the z*
|
||||
keybindings vim offers to deal with folding!
|
||||
|
||||
:reverse: If False open folding by one level otherwise close it by one.
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
heading = d.current_heading()
|
||||
if not heading:
|
||||
vim.eval(u_encode(u'feedkeys("<Tab>", "n")'))
|
||||
return
|
||||
|
||||
cursor = vim.current.window.cursor[:]
|
||||
|
||||
if int(vim.eval(u_encode(u'foldclosed(%d)' % heading.start_vim))) != -1:
|
||||
if not reverse:
|
||||
# open closed fold
|
||||
p = heading.number_of_parents
|
||||
if not p:
|
||||
p = heading.level
|
||||
vim.command(u_encode(u'normal! %dzo' % p))
|
||||
else:
|
||||
# reverse folding opens all folds under the cursor
|
||||
vim.command(u_encode(u'%d,%dfoldopen!' % (heading.start_vim, heading.end_of_last_child_vim)))
|
||||
vim.current.window.cursor = cursor
|
||||
return heading
|
||||
|
||||
def open_fold(h):
|
||||
if h.number_of_parents <= open_depth:
|
||||
vim.command(u_encode(u'normal! %dgg%dzo' % (h.start_vim, open_depth)))
|
||||
for c in h.children:
|
||||
open_fold(c)
|
||||
|
||||
def close_fold(h):
|
||||
for c in h.children:
|
||||
close_fold(c)
|
||||
if h.number_of_parents >= open_depth - 1 and \
|
||||
int(vim.eval(u_encode(u'foldclosed(%d)' % h.start_vim))) == -1:
|
||||
vim.command(u_encode(u'normal! %dggzc' % (h.start_vim, )))
|
||||
|
||||
# find deepest fold
|
||||
open_depth, found_fold = cls._fold_depth(heading)
|
||||
|
||||
if not reverse:
|
||||
# recursively open folds
|
||||
if found_fold:
|
||||
for child in heading.children:
|
||||
open_fold(child)
|
||||
else:
|
||||
vim.command(u_encode(u'%d,%dfoldclose!' % (heading.start_vim, heading.end_of_last_child_vim)))
|
||||
|
||||
if heading.number_of_parents:
|
||||
# restore cursor position, it might have been changed by open_fold
|
||||
vim.current.window.cursor = cursor
|
||||
|
||||
p = heading.number_of_parents
|
||||
if not p:
|
||||
p = heading.level
|
||||
# reopen fold again because the former closing of the fold closed all levels, including parents!
|
||||
vim.command(u_encode(u'normal! %dzo' % (p, )))
|
||||
else:
|
||||
# close the last level of folds
|
||||
close_fold(heading)
|
||||
|
||||
# restore cursor position
|
||||
vim.current.window.cursor = cursor
|
||||
return heading
|
||||
|
||||
@classmethod
|
||||
@apply_count
|
||||
def global_toggle_folding(cls, reverse=False):
|
||||
""" Toggle folding globally
|
||||
|
||||
:reverse: If False open folding by one level otherwise close it by one.
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
if reverse:
|
||||
foldlevel = int(vim.eval(u_encode(u'&foldlevel')))
|
||||
if foldlevel == 0:
|
||||
# open all folds because the user tries to close folds beyond 0
|
||||
vim.eval(u_encode(u'feedkeys("zR", "n")'))
|
||||
else:
|
||||
# vim can reduce the foldlevel on its own
|
||||
vim.eval(u_encode(u'feedkeys("zm", "n")'))
|
||||
else:
|
||||
found = False
|
||||
for h in d.headings:
|
||||
res = cls._fold_depth(h)
|
||||
if res:
|
||||
found = res[1]
|
||||
if found:
|
||||
break
|
||||
if not found:
|
||||
# no fold found and the user tries to advance the fold level
|
||||
# beyond maximum so close everything
|
||||
vim.eval(u_encode(u'feedkeys("zM", "n")'))
|
||||
else:
|
||||
# fold found, vim can increase the foldlevel on its own
|
||||
vim.eval(u_encode(u'feedkeys("zr", "n")'))
|
||||
|
||||
return d
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
# register plug
|
||||
|
||||
self.keybindings.append(Keybinding(u'<Tab>',
|
||||
Plug(u'OrgToggleFoldingNormal', u'%s ORGMODE.plugins[u"ShowHide"].toggle_folding()<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&Cycle Visibility', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<S-Tab>',
|
||||
Plug(u'OrgToggleFoldingReverse', u'%s ORGMODE.plugins[u"ShowHide"].toggle_folding(reverse=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Cycle Visibility &Reverse', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<localleader>.',
|
||||
Plug(u'OrgGlobalToggleFoldingNormal', u'%s ORGMODE.plugins[u"ShowHide"].global_toggle_folding()<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Cycle Visibility &Globally', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<localleader>,',
|
||||
Plug(u'OrgGlobalToggleFoldingReverse',
|
||||
u'%s ORGMODE.plugins[u"ShowHide"].global_toggle_folding(reverse=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'Cycle Visibility Reverse G&lobally', self.keybindings[-1])
|
||||
|
||||
for i in range(0, 10):
|
||||
self.keybindings.append(Keybinding(u'<localleader>%d' % (i, ), u'zM:set fdl=%d<CR>' % i, mode=MODE_NORMAL))
|
||||
@@ -0,0 +1,213 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
|
||||
from orgmode._vim import ORGMODE, repeat
|
||||
from orgmode.menu import Submenu, ActionEntry
|
||||
from orgmode.keybinding import Keybinding, Plug, Command
|
||||
from orgmode import settings
|
||||
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
class TagsProperties(object):
|
||||
u""" TagsProperties plugin """
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'&TAGS and Properties')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
# commands for this plugin
|
||||
self.commands = []
|
||||
|
||||
@classmethod
|
||||
def complete_tags(cls):
|
||||
u""" build a list of tags and store it in variable b:org_tag_completion
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
heading = d.current_heading()
|
||||
if not heading:
|
||||
return
|
||||
|
||||
leading_portion = u_decode(vim.eval(u'a:ArgLead'))
|
||||
cursor = int(vim.eval(u'a:CursorPos'))
|
||||
|
||||
# extract currently completed tag
|
||||
idx_orig = leading_portion.rfind(u':', 0, cursor)
|
||||
if idx_orig == -1:
|
||||
idx = 0
|
||||
else:
|
||||
idx = idx_orig
|
||||
|
||||
current_tag = leading_portion[idx: cursor].lstrip(u':')
|
||||
head = leading_portion[:idx + 1]
|
||||
if idx_orig == -1:
|
||||
head = u''
|
||||
tail = leading_portion[cursor:]
|
||||
|
||||
# extract all tags of the current file
|
||||
all_tags = set()
|
||||
for h in d.all_headings():
|
||||
for t in h.tags:
|
||||
all_tags.add(t)
|
||||
|
||||
ignorecase = bool(int(settings.get(u'org_tag_completion_ignorecase', int(vim.eval(u'&ignorecase')))))
|
||||
possible_tags = []
|
||||
# TODO current tags never used...
|
||||
current_tags = heading.tags
|
||||
for t in all_tags:
|
||||
if ignorecase:
|
||||
if t.lower().startswith(current_tag.lower()):
|
||||
possible_tags.append(t)
|
||||
elif t.startswith(current_tag):
|
||||
possible_tags.append(t)
|
||||
|
||||
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])))
|
||||
|
||||
@classmethod
|
||||
@repeat
|
||||
def set_tags(cls):
|
||||
u""" Set tags for current heading
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
heading = d.current_heading()
|
||||
if not heading:
|
||||
return
|
||||
|
||||
# retrieve tags
|
||||
res = None
|
||||
if heading.tags:
|
||||
res = vim.eval(u'input("Tags: ", ":%s:", "customlist,Org_complete_tags")' % u':'.join(heading.tags))
|
||||
else:
|
||||
res = vim.eval(u'input("Tags: ", "", "customlist,Org_complete_tags")')
|
||||
|
||||
if res is None:
|
||||
# user pressed <Esc> abort any further processing
|
||||
return
|
||||
|
||||
# remove empty tags
|
||||
heading.tags = [x for x in u_decode(res).strip().strip(u':').split(u':') if x.strip() != u'']
|
||||
|
||||
d.write()
|
||||
|
||||
return u'OrgSetTags'
|
||||
|
||||
@classmethod
|
||||
def find_tags(cls):
|
||||
""" Find tags in current file
|
||||
"""
|
||||
tags = vim.eval(u'input("Find Tags: ", "", "customlist,Org_complete_tags")')
|
||||
if tags is None:
|
||||
# user pressed <Esc> abort any further processing
|
||||
return
|
||||
|
||||
tags = [x for x in u_decode(tags).strip().strip(u':').split(u':') if x.strip() != u'']
|
||||
if tags:
|
||||
searchstring = u'\\('
|
||||
first = True
|
||||
for t1 in tags:
|
||||
if first:
|
||||
first = False
|
||||
searchstring += u'%s' % t1
|
||||
else:
|
||||
searchstring += u'\\|%s' % t1
|
||||
|
||||
for t2 in tags:
|
||||
if t1 == t2:
|
||||
continue
|
||||
searchstring += u'\\(:[a-zA-Z:]*\\)\\?:%s' % t2
|
||||
searchstring += u'\\)'
|
||||
|
||||
vim.command(u'/\\zs:%s:\\ze' % searchstring)
|
||||
return u'OrgFindTags'
|
||||
|
||||
@classmethod
|
||||
def realign_tags(cls):
|
||||
u"""
|
||||
Updates tags when user finished editing a heading
|
||||
"""
|
||||
d = ORGMODE.get_document(allow_dirty=True)
|
||||
heading = d.find_current_heading()
|
||||
if not heading:
|
||||
return
|
||||
|
||||
if vim.current.window.cursor[0] == heading.start_vim:
|
||||
heading.set_dirty_heading()
|
||||
d.write_heading(heading, including_children=False)
|
||||
|
||||
@classmethod
|
||||
def realign_all_tags(cls):
|
||||
u"""
|
||||
Updates tags when user finishes editing a heading
|
||||
"""
|
||||
d = ORGMODE.get_document()
|
||||
for heading in d.all_headings():
|
||||
heading.set_dirty_heading()
|
||||
|
||||
d.write()
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
# an Action menu entry which binds "keybinding" to action ":action"
|
||||
settings.set(u'org_tag_column', vim.eval(u'&textwidth'))
|
||||
settings.set(u'org_tag_completion_ignorecase', int(vim.eval(u'&ignorecase')))
|
||||
|
||||
cmd = Command(
|
||||
u'OrgSetTags',
|
||||
u'%s ORGMODE.plugins[u"TagsProperties"].set_tags()' % VIM_PY_CALL)
|
||||
self.commands.append(cmd)
|
||||
keybinding = Keybinding(
|
||||
u'<localleader>st',
|
||||
Plug(u'OrgSetTags', cmd))
|
||||
self.keybindings.append(keybinding)
|
||||
self.menu + ActionEntry(u'Set &Tags', keybinding)
|
||||
|
||||
cmd = Command(
|
||||
u'OrgFindTags',
|
||||
u'%s ORGMODE.plugins[u"TagsProperties"].find_tags()' % VIM_PY_CALL)
|
||||
self.commands.append(cmd)
|
||||
keybinding = Keybinding(
|
||||
u'<localleader>ft',
|
||||
Plug(u'OrgFindTags', cmd))
|
||||
self.keybindings.append(keybinding)
|
||||
self.menu + ActionEntry(u'&Find Tags', keybinding)
|
||||
|
||||
cmd = Command(
|
||||
u'OrgTagsRealign',
|
||||
u"%s ORGMODE.plugins[u'TagsProperties'].realign_all_tags()" % VIM_PY_CALL)
|
||||
self.commands.append(cmd)
|
||||
|
||||
# workaround to align tags when user is leaving insert mode
|
||||
vim.command(u_encode(u"function Org_complete_tags(ArgLead, CmdLine, CursorPos)\n"
|
||||
+ sys.executable.split('/')[-1] + u""" << EOF
|
||||
ORGMODE.plugins[u'TagsProperties'].complete_tags()
|
||||
EOF
|
||||
if exists('b:org_complete_tags')
|
||||
let tmp = b:org_complete_tags
|
||||
unlet b:org_complete_tags
|
||||
return tmp
|
||||
else
|
||||
return []
|
||||
endif
|
||||
endfunction"""))
|
||||
|
||||
vim.command(u_encode(u"""function Org_realign_tags_on_insert_leave()
|
||||
if !exists('b:org_complete_tag_on_insertleave_au')
|
||||
:au orgmode InsertLeave <buffer> %s ORGMODE.plugins[u'TagsProperties'].realign_tags()
|
||||
let b:org_complete_tag_on_insertleave_au = 1
|
||||
endif
|
||||
endfunction""" % VIM_PY_CALL))
|
||||
|
||||
# this is for all org files opened after this file
|
||||
vim.command(u_encode(u"au orgmode FileType org call Org_realign_tags_on_insert_leave()"))
|
||||
# this is for the current file
|
||||
vim.command(u_encode(u"call Org_realign_tags_on_insert_leave()"))
|
||||
344
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Todo.py
Normal file
344
dot_vim/plugged/vim-orgmode/ftplugin/orgmode/plugins/Todo.py
Normal file
@@ -0,0 +1,344 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import vim
|
||||
import re
|
||||
import itertools as it
|
||||
|
||||
from orgmode._vim import echom, ORGMODE, apply_count, repeat, realign_tags
|
||||
from orgmode import settings
|
||||
from orgmode.liborgmode.base import Direction
|
||||
from orgmode.menu import Submenu, ActionEntry
|
||||
from orgmode.keybinding import Keybinding, Plug
|
||||
from orgmode.exceptions import PluginError
|
||||
|
||||
# temporary todo states for different orgmode buffers
|
||||
ORGTODOSTATES = {}
|
||||
|
||||
from orgmode.py3compat.xrange_compatibility import *
|
||||
from orgmode.py3compat.encode_compatibility import *
|
||||
from orgmode.py3compat.unicode_compatibility import *
|
||||
from orgmode.py3compat.py_py3_string import *
|
||||
|
||||
|
||||
def split_access_key(t, sub=None):
|
||||
u""" Split access key
|
||||
|
||||
Args:
|
||||
t (str): Todo state
|
||||
sub: A value that will be returned instead of access key if there was
|
||||
not access key
|
||||
|
||||
Returns:
|
||||
tuple: Todo state and access key separated (TODO, ACCESS_KEY)
|
||||
|
||||
Example:
|
||||
>>> split_access_key('TODO(t)')
|
||||
>>> ('TODO', '(t)')
|
||||
>>> split_access_key('WANT', sub='(hi)')
|
||||
>>> ('WANT', '(hi)')
|
||||
"""
|
||||
if type(t) != unicode:
|
||||
echom("String must be unicode")
|
||||
return (None, None)
|
||||
|
||||
idx = t.find(u'(')
|
||||
|
||||
v, k = (t, sub)
|
||||
if idx != -1 and t[idx + 1:-1]:
|
||||
v, k = (t[:idx], t[idx + 1:-1])
|
||||
return (v, k)
|
||||
|
||||
|
||||
class Todo(object):
|
||||
u"""
|
||||
Todo plugin.
|
||||
|
||||
Description taken from orgmode.org:
|
||||
|
||||
You can use TODO keywords to indicate different sequential states in the
|
||||
process of working on an item, for example:
|
||||
|
||||
["TODO", "FEEDBACK", "VERIFY", "|", "DONE", "DELEGATED"]
|
||||
|
||||
The vertical bar separates the TODO keywords (states that need action) from
|
||||
the DONE states (which need no further action). If you don't provide the
|
||||
separator bar, the last state is used as the DONE state. With this setup,
|
||||
the command ``,d`` will cycle an entry from TODO to FEEDBACK, then to
|
||||
VERIFY, and finally to DONE and DELEGATED.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
u""" Initialize plugin """
|
||||
object.__init__(self)
|
||||
# menu entries this plugin should create
|
||||
self.menu = ORGMODE.orgmenu + Submenu(u'&TODO Lists')
|
||||
|
||||
# key bindings for this plugin
|
||||
# key bindings are also registered through the menu so only additional
|
||||
# bindings should be put in this variable
|
||||
self.keybindings = []
|
||||
|
||||
@classmethod
|
||||
def _process_all_states(cls, all_states):
|
||||
u""" verify if states defined by user is valid.
|
||||
Return cleaned_todo and flattened if is. Raise Exception if not.
|
||||
Valid checking:
|
||||
* no two state share a same name
|
||||
"""
|
||||
# TODO Write tests. -- Ron89
|
||||
cleaned_todos = [[
|
||||
split_access_key(todo)[0] for todo in it.chain.from_iterable(x)]
|
||||
for x in all_states] + [[None]]
|
||||
|
||||
flattened_todos = list(it.chain.from_iterable(cleaned_todos))
|
||||
if len(flattened_todos) != len(set(flattened_todos)):
|
||||
raise PluginError(u"Duplicate names detected in TODO keyword list. Please examine `g/b:org_todo_keywords`")
|
||||
# TODO This is the case when there are 2 todo states with the same
|
||||
# name. It should be handled by making a simple class to hold TODO
|
||||
# states, which would avoid mixing 2 todo states with the same name
|
||||
# since they would have a different reference (but same content),
|
||||
# albeit this can fail because python optimizes short strings (i.e.
|
||||
# they hold the same ref) so care should be taken in implementation
|
||||
return (cleaned_todos, flattened_todos)
|
||||
|
||||
@classmethod
|
||||
def _get_next_state(
|
||||
cls, current_state, all_states, direction=Direction.FORWARD,
|
||||
next_set=False):
|
||||
u""" Get the next todo state
|
||||
|
||||
Args:
|
||||
current_state (str): The current todo state
|
||||
all_states (list): A list containing all todo states within
|
||||
sublists. The todo states may contain access keys
|
||||
direction: Direction of state or keyword set change (forward or
|
||||
backward)
|
||||
next_set: Advance to the next keyword set in defined direction.
|
||||
|
||||
Returns:
|
||||
str or None: next todo state, or None if there is no next state.
|
||||
|
||||
Note: all_states should have the form of:
|
||||
[(['TODO(t)'], ['DONE(d)']),
|
||||
(['REPORT(r)', 'BUG(b)', 'KNOWNCAUSE(k)'], ['FIXED(f)']),
|
||||
([], ['CANCELED(c)'])]
|
||||
"""
|
||||
cleaned_todos, flattened_todos = cls._process_all_states(all_states)
|
||||
|
||||
# backward direction should really be -1 not 2
|
||||
next_dir = -1 if direction == Direction.BACKWARD else 1
|
||||
# work only with top level index
|
||||
if next_set:
|
||||
top_set = next((
|
||||
todo_set[0] for todo_set in enumerate(cleaned_todos)
|
||||
if current_state in todo_set[1]), -1)
|
||||
ind = (top_set + next_dir) % len(cleaned_todos)
|
||||
if ind != len(cleaned_todos) - 1:
|
||||
echom("Using set: %s" % str(all_states[ind]))
|
||||
else:
|
||||
echom("Keyword removed.")
|
||||
return cleaned_todos[ind][0]
|
||||
# No next set, cycle around everything
|
||||
else:
|
||||
ind = next((
|
||||
todo_iter[0] for todo_iter in enumerate(flattened_todos)
|
||||
if todo_iter[1] == current_state), -1)
|
||||
return flattened_todos[(ind + next_dir) % len(flattened_todos)]
|
||||
|
||||
@classmethod
|
||||
@realign_tags
|
||||
@repeat
|
||||
@apply_count
|
||||
def toggle_todo_state(
|
||||
cls, direction=Direction.FORWARD, interactive=False, next_set=False):
|
||||
u""" Toggle state of TODO item
|
||||
|
||||
:returns: The changed heading
|
||||
"""
|
||||
d = ORGMODE.get_document(allow_dirty=True)
|
||||
|
||||
# get heading
|
||||
heading = d.find_current_heading()
|
||||
if not heading:
|
||||
vim.eval(u'feedkeys("^", "n")')
|
||||
return
|
||||
|
||||
todo_states = d.get_todo_states(strip_access_key=False)
|
||||
# get todo states
|
||||
if not todo_states:
|
||||
echom(u'No todo keywords configured.')
|
||||
return
|
||||
|
||||
current_state = heading.todo
|
||||
|
||||
# get new state interactively
|
||||
if interactive:
|
||||
# determine position of the interactive prompt
|
||||
prompt_pos = settings.get(u'org_todo_prompt_position', u'botright')
|
||||
if prompt_pos not in [u'botright', u'topleft']:
|
||||
prompt_pos = u'botright'
|
||||
|
||||
# pass todo states to new window
|
||||
ORGTODOSTATES[d.bufnr] = todo_states
|
||||
settings.set(
|
||||
u'org_current_state_%d' % d.bufnr,
|
||||
current_state if current_state is not None else u'', overwrite=True)
|
||||
todo_buffer_exists = bool(int(vim.eval(u_encode(
|
||||
u'bufexists("org:todo/%d")' % (d.bufnr, )))))
|
||||
if todo_buffer_exists:
|
||||
# if the buffer already exists, reuse it
|
||||
vim.command(u_encode(
|
||||
u'%s sbuffer org:todo/%d' % (prompt_pos, d.bufnr, )))
|
||||
else:
|
||||
# create a new window
|
||||
vim.command(u_encode(
|
||||
u'keepalt %s %dsplit org:todo/%d' % (prompt_pos, len(todo_states), d.bufnr)))
|
||||
else:
|
||||
new_state = Todo._get_next_state(
|
||||
current_state, todo_states, direction=direction,
|
||||
next_set=next_set)
|
||||
|
||||
cls.set_todo_state(new_state)
|
||||
|
||||
# plug
|
||||
plug = u'OrgTodoForward'
|
||||
if direction == Direction.BACKWARD:
|
||||
plug = u'OrgTodoBackward'
|
||||
|
||||
return plug
|
||||
|
||||
@classmethod
|
||||
def set_todo_state(cls, state):
|
||||
u""" Set todo state for buffer.
|
||||
|
||||
:bufnr: Number of buffer the todo state should be updated for
|
||||
:state: The new todo state
|
||||
"""
|
||||
lineno, colno = vim.current.window.cursor
|
||||
d = ORGMODE.get_document(allow_dirty=True)
|
||||
heading = d.find_current_heading()
|
||||
|
||||
if not heading:
|
||||
return
|
||||
|
||||
current_state = heading.todo
|
||||
|
||||
# set new headline
|
||||
heading.todo = state
|
||||
d.write_heading(heading)
|
||||
|
||||
# move cursor along with the inserted state only when current position
|
||||
# is in the heading; otherwite do nothing
|
||||
if heading.start_vim == lineno and colno > heading.level:
|
||||
if current_state is not None and \
|
||||
colno <= heading.level + len(current_state):
|
||||
# the cursor is actually on the todo keyword
|
||||
# move it back to the beginning of the keyword in that case
|
||||
vim.current.window.cursor = (lineno, heading.level + 1)
|
||||
else:
|
||||
# the cursor is somewhere in the text, move it along
|
||||
if current_state is None and state is None:
|
||||
offset = 0
|
||||
elif current_state is None and state is not None:
|
||||
offset = len(state) + 1
|
||||
elif current_state is not None and state is None:
|
||||
offset = -len(current_state) - 1
|
||||
else:
|
||||
offset = len(state) - len(current_state)
|
||||
vim.current.window.cursor = (lineno, colno + offset)
|
||||
|
||||
@classmethod
|
||||
def init_org_todo(cls):
|
||||
u""" Initialize org todo selection window.
|
||||
"""
|
||||
bufnr = int(re.findall('\d+$',vim.current.buffer.name)[0])
|
||||
all_states = ORGTODOSTATES.get(bufnr, None)
|
||||
|
||||
vim_commands = [
|
||||
u'let g:org_sav_timeoutlen=&timeoutlen',
|
||||
u'au orgmode BufEnter <buffer> :if ! exists("g:org_sav_timeoutlen")|let g:org_sav_timeoutlen=&timeoutlen|set timeoutlen=1|endif',
|
||||
u'au orgmode BufLeave <buffer> :if exists("g:org_sav_timeoutlen")|let &timeoutlen=g:org_sav_timeoutlen|unlet g:org_sav_timeoutlen|endif',
|
||||
u'setlocal nolist tabstop=16 buftype=nofile timeout timeoutlen=1 winfixheight',
|
||||
u'setlocal statusline=Org\\ todo\\ (%s)' % vim.eval(u_encode(u'fnameescape(fnamemodify(bufname(%d), ":t"))' % bufnr)),
|
||||
u'nnoremap <silent> <buffer> <Esc> :%sbw<CR>' % vim.eval(u_encode(u'bufnr("%")')),
|
||||
u'nnoremap <silent> <buffer> <CR> :let g:org_state = fnameescape(expand("<cword>"))<Bar>bw<Bar>exec "%s ORGMODE.plugins[u\'Todo\'].set_todo_state(\'".g:org_state."\')"<Bar>unlet! g:org_state<CR>' % VIM_PY_CALL,
|
||||
]
|
||||
# because timeoutlen can only be set globally it needs to be stored and
|
||||
# restored later
|
||||
# make window a scratch window and set the statusline differently
|
||||
for cmd in vim_commands:
|
||||
vim.command(u_encode(cmd))
|
||||
|
||||
if all_states is None:
|
||||
vim.command(u_encode(u'bw'))
|
||||
echom(u'No todo states available for buffer %s' % vim.current.buffer.name)
|
||||
|
||||
for idx, state in enumerate(all_states):
|
||||
pairs = [split_access_key(x, sub=u' ') for x in it.chain(*state)]
|
||||
line = u'\t'.join(u''.join((u'[%s] ' % x[1], x[0])) for x in pairs)
|
||||
vim.current.buffer.append(u_encode(line))
|
||||
for todo, key in pairs:
|
||||
# FIXME if double key is used for access modified this doesn't work
|
||||
vim.command(u_encode(u'nnoremap <silent> <buffer> %s :bw<CR><c-w><c-p>%s ORGMODE.plugins[u"Todo"].set_todo_state("%s")<CR>' % (key, VIM_PY_CALL, u_decode(todo))))
|
||||
|
||||
# position the cursor of the current todo item
|
||||
vim.command(u_encode(u'normal! G'))
|
||||
current_state = settings.unset(u'org_current_state_%d' % bufnr)
|
||||
if current_state is not None and current_state != '':
|
||||
for i, buf in enumerate(vim.current.buffer):
|
||||
idx = buf.find(current_state)
|
||||
if idx != -1:
|
||||
vim.current.window.cursor = (i + 1, idx)
|
||||
break
|
||||
else:
|
||||
vim.current.window.cursor = (2, 4)
|
||||
|
||||
# finally make buffer non modifiable
|
||||
vim.command(u_encode(u'setfiletype orgtodo'))
|
||||
vim.command(u_encode(u'setlocal nomodifiable'))
|
||||
|
||||
# remove temporary todo states for the current buffer
|
||||
del ORGTODOSTATES[bufnr]
|
||||
|
||||
def register(self):
|
||||
u"""
|
||||
Registration of plugin. Key bindings and other initialization should be done.
|
||||
"""
|
||||
self.keybindings.append(Keybinding(u'<localleader>ct', Plug(
|
||||
u'OrgTodoToggleNonInteractive',
|
||||
u'%s ORGMODE.plugins[u"Todo"].toggle_todo_state(interactive=False)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&TODO/DONE/-', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<localleader>d', Plug(
|
||||
u'OrgTodoToggleInteractive',
|
||||
u'%s ORGMODE.plugins[u"Todo"].toggle_todo_state(interactive=True)<CR>' % VIM_PY_CALL)))
|
||||
self.menu + ActionEntry(u'&TODO/DONE/- (interactive)', self.keybindings[-1])
|
||||
|
||||
# add submenu
|
||||
submenu = self.menu + Submenu(u'Select &keyword')
|
||||
|
||||
self.keybindings.append(Keybinding(u'<S-Right>', Plug(
|
||||
u'OrgTodoForward',
|
||||
u'%s ORGMODE.plugins[u"Todo"].toggle_todo_state()<CR>' % VIM_PY_CALL)))
|
||||
submenu + ActionEntry(u'&Next keyword', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<S-Left>', Plug(
|
||||
u'OrgTodoBackward',
|
||||
u'%s ORGMODE.plugins[u"Todo"].toggle_todo_state(direction=2)<CR>' % VIM_PY_CALL)))
|
||||
submenu + ActionEntry(u'&Previous keyword', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<C-S-Right>', Plug(
|
||||
u'OrgTodoSetForward',
|
||||
u'%s ORGMODE.plugins[u"Todo"].toggle_todo_state(next_set=True)<CR>' % VIM_PY_CALL)))
|
||||
submenu + ActionEntry(u'Next keyword &set', self.keybindings[-1])
|
||||
|
||||
self.keybindings.append(Keybinding(u'<C-S-Left>', Plug(
|
||||
u'OrgTodoSetBackward',
|
||||
u'%s ORGMODE.plugins[u"Todo"].toggle_todo_state(direction=2, next_set=True)<CR>' % VIM_PY_CALL)))
|
||||
submenu + ActionEntry(u'Previous &keyword set', self.keybindings[-1])
|
||||
|
||||
settings.set(u'org_todo_keywords', [u_encode(u'TODO'), u_encode(u'|'), u_encode(u'DONE')])
|
||||
|
||||
settings.set(u'org_todo_prompt_position', u'botright')
|
||||
|
||||
vim.command(u_encode(u'au orgmode BufReadCmd org:todo/* %s ORGMODE.plugins[u"Todo"].init_org_todo()' % VIM_PY_CALL))
|
||||
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
Reference in New Issue
Block a user