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'))
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'))
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)
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 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'normal! gv'.encode(u'utf-8')) else: echo(u'No heading found') return if not heading.parent or not heading.parent.next_sibling: if mode == u'visual': vim.command(u'normal! gv'.encode(u'utf-8')) 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
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'normal! gv'.encode(u'utf-8')) else: echo(u'No heading found') return if not heading.parent: if mode == u'visual': vim.command(u'normal! gv'.encode(u'utf-8')) 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
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 # 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'badd %s' % agenda_file.replace(" ", "\ ")).encode(u'utf-8')) # 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]
def test_realign_tags(self): vim.current.window.cursor = (2, 0) vim.EVALRESULTS[u'input("Tags: ", "", "customlist,Org_complete_tags")'. encode(u'utf-8')] = u':hello:world:'.encode('utf-8') self.tagsproperties.set_tags() self.assertEqual( vim.current.buffer[1], u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode( 'utf-8')) d = ORGMODE.get_document() heading = d.find_current_heading() self.assertEqual( str(heading), u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode( 'utf-8')) self.tagsproperties.realign_tags() heading = d.find_current_heading() self.assertEqual( str(heading), u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode( 'utf-8')) self.assertEqual( vim.current.buffer[1], u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode( 'utf-8'))
def new_checkbox(cls, below=None): 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() # default checkbox level level = h.level # if no checkbox is found, insert at current line with indent level=1 if c is None: start = h.start if h.checkboxes: level = h.first_checkbox.level else: level = c.level if below: start = c.end_of_last_child else: start = c.start vim.current.window.cursor = (start + 1, 0) if below: vim.command("normal o") else: vim.command("normal O") new_checkbox = Checkbox(level=level) insert_at_cursor(str(new_checkbox)) vim.command("call feedkeys('a')")
def get_timestamp_header(self): """ info, body - info is the dict of time headers - body is the list of strings """ # will do all the checks and stuff d = ORGMODE.get_document(allow_dirty=True) info, body = {}, d.find_current_heading().body try: firstline = body[0] if not firstline.startswith(' '): parts = [ f.split(': ') for f in firstline.strip().replace(']', '>').split('>') if f ] for k, v in parts: k = k.strip() if k != k.upper(): raise if v[0] == '<': v += '>' elif v[0] == '[': v += ']' else: raise info[k] = v body.pop(0) except: info = {} return info, body
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'getpos("\'<")'.encode(u"utf-8"))[1:3]] line_end, col_end = [int(i) for i in vim.eval(u'getpos("\'>")'.encode(u"utf-8"))[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"normal! %dgg%s%dgg$%s" % (start, vim.eval(u"visualmode()".encode(u"utf-8")), end, swap_cursor) ).encode(u"utf-8") ) 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"normal! gv".encode(u"utf-8"))
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 = filter(lambda x: x.strip() != u'', res.decode(u'utf-8').strip().strip(u':').split(u':')) d.write() return u'OrgSetTags'
def new_checkbox(cls, below=None): 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() # default checkbox level level = h.level # if no checkbox is found, insert at current line with indent level=1 if c is None: start = h.start if h.checkboxes: level = h.first_checkbox.level else: level = c.level if below: start = c.end_of_last_child else: start = c.start vim.current.window.cursor = (start + 1, 0) if below: vim.command("normal o") else: vim.command("normal O") new_checkbox = Checkbox(level=level) insert_at_cursor(str(new_checkbox)) vim.command("call feedkeys('a')")
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 beyound 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 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'feedkeys("^", "n")'.encode(u"utf-8")) return vim.current.window.cursor = (vim.current.window.cursor[0], heading.level + 1)
def update_checkboxes_status(cls): d = ORGMODE.get_document() h = d.current_heading() # init checkboxes for current heading h.init_checkboxes() cls._update_checkboxes_status(h.first_checkbox) cls._update_subtasks()
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'))
def update_checkboxes_status(cls): d = ORGMODE.get_document() h = d.current_heading() # init checkboxes for current heading h.init_checkboxes() cls._update_checkboxes_status(h.first_checkbox) cls._update_subtasks()
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'feedkeys("I", "n")'.encode(u"utf-8")) return vim.current.window.cursor = (vim.current.window.cursor[0], heading.level + 1) vim.command(u"startinsert".encode(u"utf-8"))
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 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
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'bufexists("org:todo/%d")' % (d.bufnr, )).encode(u'utf-8')))) if todo_buffer_exists: # if the buffer already exists, reuse it vim.command(( u'%s sbuffer org:todo/%d' % (prompt_pos, d.bufnr, )).encode(u'utf-8')) else: # create a new window vim.command(( u'keepalt %s %dsplit org:todo/%d' % (prompt_pos, len(todo_states), d.bufnr)).encode(u'utf-8')) else: new_state = Todo._get_next_state( current_state, todo_states, direction=direction, interactive=interactive, next_set=next_set) cls.set_todo_state(new_state) # plug plug = u'OrgTodoForward' if direction == Direction.BACKWARD: plug = u'OrgTodoBackward' return plug
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 test_demote_last_heading(self): vim.current.buffer[:] = [ u_encode(i) for i in u""" * Überschrift 2 * Überschrift 3""".split('\n')] vim.current.window.cursor = (3, 0) h = ORGMODE.get_document().current_heading() self.assertNotEqual(self.editstructure.demote_heading(), None) self.assertEqual(h.end, 2) # self.assertFalse(vim.CMDHISTORY) self.assertEqual(vim.current.buffer[2], u_encode(u'** Überschrift 3')) self.assertEqual(vim.current.window.cursor, [3, 1])
def test_subtasks(self): bufnr = 3 set_vim_buffer(buf=self.c1, bufnr=bufnr) h = ORGMODE.get_document(bufnr=bufnr).current_heading() h.init_checkboxes() c = h.current_checkbox(position=3) c.toggle() c = h.current_checkbox(position=2) (total, on) = c.all_siblings_status() c.update_subtasks(total=total, on=on) self.assertEqual(str(c), " - [-] checkbox1 [50%]")
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)
def test_realign_tags(self): vim.current.window.cursor = (2, 0) vim.EVALRESULTS[u'input("Tags: ", "", "customlist,Org_complete_tags")'.encode(u'utf-8')] = u':hello:world:'.encode('utf-8') self.tagsproperties.set_tags() self.assertEqual(vim.current.buffer[1], u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode('utf-8')) d = ORGMODE.get_document() heading = d.find_current_heading() self.assertEqual(str(heading), u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode('utf-8')) self.tagsproperties.realign_tags() heading = d.find_current_heading() self.assertEqual(str(heading), u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode('utf-8')) self.assertEqual(vim.current.buffer[1], u'* Überschrift 1\t\t\t\t\t\t\t\t :hello:world:'.encode('utf-8'))
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)
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
def contains_active_todo(heading): u""" Returns: bool: True if heading contains an active TODO. """ # TODO make this more efficient by checking some val and not calling the # function # TODO why is this import failing at top level? circular dependecy... from orgmode._vim import ORGMODE active = [] for act in ORGMODE.get_document().get_todo_states(): active.extend(act[0]) return heading.todo in active
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 # toggle to scheduled dates if ORGMODE.plugins.get("Date"): isdone, next_state = False, '' todos = d.get_todo_states() for t in todos: if not isdone and state in t[1]: isdone = True next_state = t[0][0] if ORGMODE.plugins["Date"].update_todo_timestamp(isdone): state = next_state 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)
def test_toggle(self): bufnr = 2 # test init_checkboxes set_vim_buffer(buf=self.c1, bufnr=bufnr) h = ORGMODE.get_document(bufnr=bufnr).current_heading() h.init_checkboxes() # toggle checkbox c = h.current_checkbox(position=4) c.toggle() self.assertEqual(str(c), " - [X] checkbox3") c.toggle() self.assertEqual(str(c), " - [ ] checkbox3") (total, on) = c.all_siblings_status() self.assertEqual((total, on), (2, 1))
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 = vim.eval(u'a:ArgLead').decode(u'utf-8') 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 = [] 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'let b:org_complete_tags = [%s]' % u', '.join([u'"%s%s:%s"' % (head, i, tail) for i in possible_tags])).encode(u'utf-8'))
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])))
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'badd %s' % agenda_file.replace(" ", "\ ")).encode(u'utf-8')) # 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]
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 not c.children 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 not c.children 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()
def test_basic(self): bufnr = 1 set_vim_buffer(buf=self.c1, bufnr=bufnr) h = ORGMODE.get_document(bufnr=bufnr).current_heading() h.init_checkboxes() c = h.current_checkbox(position=2) self.assertEqual(str(c), self.c1[2]) self.assertFalse(c.are_children_all(Checkbox.STATUS_ON)) self.assertTrue(c.is_child_one(Checkbox.STATUS_OFF)) self.assertFalse(c.are_siblings_all(Checkbox.STATUS_ON)) for child in c.all_children(): pass for sibling in c.all_siblings(): pass c = h.current_checkbox(position=3) new_checkbox = c.copy() self.assertEqual(str(c), self.c1[3]) c.get_parent_list() c.get_index_in_parent_list()
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)
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 = 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[:] = [ i.encode(u'utf-8') for i in final_agenda ] vim.command(u'setlocal nomodifiable conceallevel=2 concealcursor=nc'.encode(u'utf-8'))
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'getpos("\'<")'.encode(u"utf-8"))[1:3]] line_end, col_end = [int(i) for i in vim.eval(u'getpos("\'>")'.encode(u"utf-8"))[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 = vim.eval(u"visualmode()").decode(u"utf-8") 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"normal! %dgg0%s%dgg$%s%s" % (start, visualmode, end, move_one_character_back, swap_cursor) ).encode(u"utf-8") ) else: vim.command( ( u"normal! %dgg0%dl%s%dgg$%s%s" % (start, col_start - 1, visualmode, end, move_one_character_back, swap_cursor) ).encode(u"utf-8") ) else: vim.command( ( u"normal! %dgg0%dl%s%dgg$%s%s" % (start, heading.level + 1, visualmode, end, move_one_character_back, swap_cursor) ).encode(u"utf-8") ) 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"normal! gv".encode(u"utf-8"))
def new_checkbox(cls, below=None): 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 if not c.status: nc.status = None level = c.level if below: start = c.end_of_last_child else: start = c.start 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[start:start] = [unicode(nc)] # update checkboxes status cls.update_checkboxes_status() vim.command((u'exe "normal %dgg"|startinsert!' % (start + 1, )).encode(u'utf-8'))