Refile function
I think it would be useful to have to have a function in wiki.vim similar to org-refile in Emacs' org-mode. The way it would work is as follows. If we e.g. have a MarkDown file like this:
# Inbox
## Foo
Random text here.
## Bar
More random text here.
### Subheading
More here.
# Tasks
## Baz
Even more random text here.
# Someday
## Qux
More text.
Then having the cursor in the subsection "Bar" and activating a "refile" function should give a fuzzy-search popup similar to WikiFzfToc, that lets you pick a different heading (e.g. "Tasks"). When you do that, you should get something like this:
# Inbox
## Foo
Random text here.
# Tasks
## Baz
Even more random text here.
## Bar
More random text here.
### Subheading
More here.
# Someday
## Qux
More text.
This is particularly useful for GTD-type workflows, for moving tasks between headings efficiently. But it can also be useful for working with structured notes in general, as it makes it easy to "refactor" notes.
Just being able to refile between same-level headings (e.g. moving "Foo" from "Inbox" to "Tasks" or "Someday" in the example above) would already be very useful. Org-mode refiling also supports refiling between multiple files (so that you can let the Inbox and Someday be different note files instead of different headings), and refiling between different levels (e.g. moving Bar inside Qux, in which case ## Bar becomes ### Bar and ### Subheading becomes #### Subheading).
Interesting idea. I think we can fit this into wiki.vim. I'll put a disclaimer that this works with ATX headers only (at least for starters).
As a first step, I would implement a function like this:
function wiki#refile#current_section(target)
" The following is pseudo code!
let l:lines = s:cut_current_section()
call append(l:lines, a:target)
endfunction
Here target is either a list that specifies the target file and line number, or a wiki link such as target#destination. Given:
1 # Inbox
2 ## Foo
3 Random text here.
4
5 ## Bar
6 More random text here.
7
8 # Tasks
9
10 ## Baz
11 Even more random text here.
12
13 ### Subheading
14 More here.
15
16 # Someday
17 ## Qux
18 More text.
With the cursor within ## Bar section,
-
call wiki#refile#current_section(['.', 8])will move the section as is to just below line 8. -
call wiki#refile#current_section('#Tasks')will move the section as is to "top of" section# Tasks, but below any introduction test. In this case below line 9. This could be extended to allow a way to specify the "section position". -
call wiki#refile#current_section('#Tasks#Baz')will move the section to just below line 12, but the header level is changed into### Bar. Levels of subsections would also be changed. This allows to dynamically "upgrade" and "downgrade" sections when refiling.
There is already functionality for parsing the headers of the current file with wiki#page#gather_toc_entries(). This could easily be extended to parse any file.
When this works, then it should be easy to create various FzF style refiling functions for interactive menus.
I think it is smart to properly specify how functions such as wiki#refile#current_section would work before we start any implementation. At the moment, it seems to me like my ideas are good. One could also consider a wiki#refile#section(source, target) type function and similar.
I would start any implementation of this by building some tests within the tests/ folder. Just saying. In case you (or anyone) should want to try and work on this yourself :)
I've started to look into this (see branch feat/refile). I've made a simple mapping of <leader>wq for now to run a simple function wiki#page#refile() which currently does nothing. Except asking for input to specify a target. The input allows tab completion of a link.
I think we need to properly specify the target. One idea: Say we want to refile the current section of MyPage.wiki to OtherPage.wiki, we would specify the target as something like OtherPage#SomeSection::number. This means to move the current section to the page OtherPage.wiki to a sub section under SomeSection. The number specifies the order. E.g. 1 would put it at the top.
So, updated pseudo code:
function wiki#page#refile()
" Target syntax: page_name#anchor::location
let l:target = input()
" Convert target string to page(path), lnum, new header level
let [l:page, l:lnum, l:new_level] = parse_target(l:target)
if input_wrong | return | endif
let l:lines = delete_current_section()
let l:lines = adjust_header(l:lines, l:new_level)
call insert_at_target(l:lines, l:page, l:lnum)
endfunction
Currently missing: target parser, code to delete current section and to insert lines at target. I think the target parser is the most difficult part here.
Thoughts?
It only took 3 years. #309 is at proof of concept-stage and is really quite close to being good. I need more work on tests, because this feature needs to be robust. It should fail in a good way when there are problems, for instance.
I'll close the issue and let discussions continue in #309.