1

I want to implement a loose version of Niklas Luhmann's Zettelkasten in Vim. At the core of his method are note snippets that Continue the current note or Brahch off from it, introducing a slightly different topic or concept. In the note name, letters indicate branches and numerals indicate continuations. Like so:

note100
note101
    note101a        # branches off from note100 (related topic)
    note101b        # also branches off from note100 (related topic)
        note101b01  # continues note101b (same topic)
        note101b02  # also continues note101b (same topic)
    note101c
note102

To implement this in Vim, I need new file names that are automatically enumerated either as a "continuation" or a "branch" of the note in current buffer. As a non-coder making first "real" steps in Vimscript, this is where I'm at with the Branching Note function:

function! ZettelkastenNewBranchingNote()
    let b:current_note_name = expand('%:t:r')
    let b:new_branching_note = call(BranchingFunctionThatReturnsNewNoteName)
    silent execute 'edit' b:new_branching_note
    echomsg 'New branching note ' b:new_branching_note 'created.'
endfunction

The BranchingFunctionThatReturnsNewNoteName() should take b:current_note_name and extend it with automatic alphabetical(!) index (counting alphabetically upwards). How could I accomplish this?

Also, for my New Continued Note function: how could I numerically count upwards from the last numeric part of the current file name? (E.g. 100a01 > 100a02.)

Thanks for any advice!

(Somewhat relatedly, here the Nexus plugin is suggested, but I'd prefer to keep my script self-contained.)

Community
  • 1
  • 1
martz
  • 839
  • 6
  • 21

1 Answers1

2

You provide a great deal of context (which is great), but are light on the needed algorithm. To me, it looks like this: If the current file ends with a letter, increase it, else (it's a number), append an a to start the alphabetical sequence.

Checks are done in Vim with regular expressions; \a is a short form for [A-Za-z] (you could also write [[:alpha:]]; yes it's that flexible), and $ anchors it to the end of the name:

if b:current_note_name =~ '\a$'
    ...

Extract the last character with matchstr().

    let lastAlpha = matchstr(b:current_note_name, '\a$')
    if lastAlpha ==? 'z'
        " TODO: Handle overflow
    endif

To "increase" an alphabetical character, convert it first to a number, increase, then back:

    let newAlpha = nr2char(char2nr(lastAlpha) + 1)

To replace, you use substitute(), again with the same regexp.

    let b:new_branching_note = substitute(b:current_note_name, '\a$', newAlpha, '')

Appending is simple:

else
    let b:new_branching_note = b:current_note_name . 'a'
endif
Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
  • Thank you very much, also for the explanations; these are very helpful in my learning process. (I particularly like the nr2char builtin - very nice!) This solution does correctly create the file but I also get "E121: Undefined variable: b:new_branching_note". Why? – martz Dec 08 '13 at 22:43
  • The variable isn't defined yet (in that buffer). You may need a check somewhere: `if ! exists('b:new_branching_note`) ...` – Ingo Karkat Dec 09 '13 at 07:49
  • Thanks! Problem solved with `let b:current_note_name = exists('b:current_note_name') ? b:current_note_name : expand('%:t:r')`. I also had to modify some variable types from `b:` to `s:`. – martz Dec 09 '13 at 21:13