From 987370cf7800b83160f657bcf52b15c0a4cb9232 Mon Sep 17 00:00:00 2001 From: Nikolaos Kakouros Date: Thu, 30 Dec 2021 13:16:55 +0000 Subject: [PATCH] Adds TaskWikiOpen and TaskWikiNote commands Co-authored-by: Tomas Babej --- doc/taskwiki.txt | 12 +++++++++ ftplugin/vimwiki/taskwiki.vim | 6 +++++ taskwiki/main.py | 34 +++++++++++++++++++++++++ taskwiki/util.py | 48 +++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) diff --git a/doc/taskwiki.txt b/doc/taskwiki.txt index 81a8ed53e..b52d8033c 100644 --- a/doc/taskwiki.txt +++ b/doc/taskwiki.txt @@ -531,6 +531,8 @@ vn m |:TaskWikiMod| n t |:TaskWikiTags| vn + |:TaskWikiStart| vn - |:TaskWikiStop| + n o |:TaskWikiOpen| + n n |:TaskWikiNote| ============================================================================= 7. COMMANDS *taskwiki-commands* @@ -634,6 +636,16 @@ selected tasks. Supports |cmdline-completion|. +*:TaskWikiOpen* + Opens annotations in the selected task(s) containing links to local files, + urls, etc. This command requires taskopen to be installed + (https://github.com/jschlatow/taskopen). + +*:TaskWikiNote* + Adds a note to the task under cursor and opens it to be edited. This + command requires taskopen to be installed + (https://github.com/jschlatow/taskopen). + ---------------------------------------------------------------------------- Interactive commands. diff --git a/ftplugin/vimwiki/taskwiki.vim b/ftplugin/vimwiki/taskwiki.vim index d3af01cbc..a858b3ec4 100644 --- a/ftplugin/vimwiki/taskwiki.vim +++ b/ftplugin/vimwiki/taskwiki.vim @@ -75,6 +75,8 @@ execute "command! -buffer -nargs=* TaskWikiTags :" . g:taskwiki_py . " Commands that operate on tasks in the buffer execute "command! -buffer -range TaskWikiInfo :," . g:taskwiki_py . "SelectedTasks().info()" +execute "command! -buffer -range TaskWikiOpen :," . g:taskwiki_py . "SelectedTasks().taskopen('open')" +execute "command! -buffer -range TaskWikiNote :," . g:taskwiki_py . "SelectedTasks().taskopen('note')" execute "command! -buffer -range TaskWikiEdit :," . g:taskwiki_py . "SelectedTasks().edit()" execute "command! -buffer -range TaskWikiLink :," . g:taskwiki_py . "SelectedTasks().link()" execute "command! -buffer -range TaskWikiGrid :," . g:taskwiki_py . "SelectedTasks().grid()" @@ -130,6 +132,8 @@ if !exists('g:taskwiki_suppress_mappings') nnoremap hm :TaskWikiHistoryMonthly nnoremap ha :TaskWikiHistoryAnnual nnoremap i :TaskWikiInfo + nnoremap o :TaskWikiOpen + nnoremap n :TaskWikiNote nnoremap l :TaskWikiLink nnoremap m :TaskWikiMod nnoremap p :TaskWikiProjects @@ -149,6 +153,8 @@ if !exists('g:taskwiki_suppress_mappings') vnoremap e :TaskWikiEdit vnoremap g :TaskWikiGrid vnoremap i :TaskWikiInfo + vnoremap o :TaskWikiOpen + vnoremap n :TaskWikiNote vnoremap l :TaskWikiLink vnoremap m :TaskWikiMod vnoremap . :TaskWikiRedo diff --git a/taskwiki/main.py b/taskwiki/main.py index 2a8716f24..d012d74be 100644 --- a/taskwiki/main.py +++ b/taskwiki/main.py @@ -125,6 +125,40 @@ def info(self): util.show_in_split(out, name='info', activate_cursorline=True) break # Show only one task + @errors.pretty_exception_handler + def taskopen(self, mode): + if mode == "note": + args = "-n {task_id} -x 'echo'" + if mode == "open": + args = "-N {task_id}" + + for vimwikitask in self.tasks: + output, exit_status = util.taskopen(args.format(task_id=vimwikitask["id"])) + + if mode == "note": + if exit_status: + vim.command("echohl Error") + vim.command('echo "%s"' % output) + vim.command("echohl None") + # Using `echoerr` is too verbose and scary, using + # echohl+echo instead. + else: + vim.command("edit " + output) + + if mode == "open": + if exit_status: + error_msg = "taskopen failed to open task " + str( + vimwikitask["id"] + ) + + vim.command('echo "%s"' % output) + vim.command("echohl Error") + vim.command('echo "%s"' % error_msg) + vim.command("echohl None") + + else: + vim.command("echomsg 'Opened task %s'" % vimwikitask["id"]) + @errors.pretty_exception_handler def edit(self): for vimwikitask in self.tasks: diff --git a/taskwiki/util.py b/taskwiki/util.py index 030ad9de4..ed7331692 100644 --- a/taskwiki/util.py +++ b/taskwiki/util.py @@ -4,6 +4,7 @@ import contextlib import os +import pexpect import random import sys import vim # pylint: disable=F0401 @@ -96,6 +97,8 @@ def tw_args_to_kwargs(args): return output def get_input(prompt="Enter: ", allow_empty=False, completion=None): + prompt = prompt.replace('"', '\\"') + if completion is not None: value = vim.eval('input("%s", "", "%s")' % (prompt, completion)) else: @@ -441,3 +444,48 @@ def is_midnight(dt): """ return dt.hour == 0 and dt.minute == 0 and dt.second == 0 + +def taskopen(args): + """ + Runs taskopen, handles its interactive prompts, returns final output. + + Params: + args - arguments to be passed to the taskopen command + """ + try: + p = pexpect.spawn( + "taskopen " + args, + timeout=3, + echo=False, + ) + + prompts = [ + "Type number\(s\): ", + "Config file.* does not exist. Do you want to create it? (Y/n)" + ] + + while not p.eof(): + index = p.expect([pexpect.EOF, *prompts]) + + if index == 0: + last_lines = p.before.splitlines() + else: + prompt = p.before.splitlines() + prompt += [bytes(prompts[index-1].replace('.*', ''), "utf-8")] + + input = get_input(b"\n".join(prompt).decode("utf-8")) + + p.sendline(input) + + p.close(force=True) # make sure the process is ended + + except pexpect.exceptions.ExceptionPexpect as e: + if "command was not found" not in e.value: + return "taskopen is not installed", 127 + + if p.exitstatus == 3: # xdg-open: no method to open annotation + last_lines = [last_lines[-1]] + + last_lines = [l.decode("utf-8").rstrip("\r\n") for l in last_lines] + + return "\n".join(last_lines).strip(), p.exitstatus