Note Taking Manual

Table of Contents

1 TODO Clean up and Replace previous Method

2 TODO Clear off Workload of attempts

3 Introduction

The important features are:

  • Writing Material
  • Finding Material
  • Reading Material
    • Mobile
    • Desktop
  • Sharing Material

3.1 Org-Mode and Markdown

While org-mode is full featured and powerful, there are a few reasons I don't like it for the backbone of a note taking system:

3.1.1 Problems with org-mode

  • Emacs with org-mode is just far too unstable, I've spent hours, well no weeks, literally 9-5 weeks trying to get it stable, you blink and it fails to export, or inline create math or whatever, whereas markdown just works, lacking in features, but, it just works.
  • Emacs takes an enormous amount of configuration
    • my ~/.emacs.d/init.el is already at like 500 lines and I'm using a starter kit (Spacemacs)
      • With Emacs 28, this is now in ~/.config/emacs/init.el where it should be but I don't really look forward to moving it.
  • Emacs can get really slow
    • This is probably on my end, but again, a pain in the ass
  • No mobile editors (see 2.1 below)
    • I don't like beorg, it sucks for long notes, doesn't support inline math and it doesn't work well with git, using Dropbox is nothing but a headache when it comes to syncing.
      • I've heard good things about it's support for the agenda but I don't use org-mode like that, I use the todo features to track a specific project in an index but I use ToDoist because it's just simpler to use.
  • It only works with emacs
    • The Vim Rendition is half-way there
    • markdown works in both and emacs doesn't scroll with the mouse which is a shame on the laptop.
    • You'll miss fzf, helm-locate and helm-ag don't even come close.
  • No live preview for math sucks
  • Math inline preview will break if there is a bug above
    • this is a dealbreaker honestly, it's ridiculous
  • Exported Math depends on previous math, whereas markdown is compartmentalised
  • yasnippets doesn't hold a candle to using UltiSnips to write LaTeX in vim. and company-mode isn't much better than Deoplete, but i'll admit YCM is a buggy mess that fails when you blink
  • bugs in init.el can break HTML export

3.1.2 Strengths to org-mode

Although it does have some features that justify using it:

  • inline LaTeX preview is really great
    • if youre willing to compile ghostscript v50 from source if you're not on Arch-Linux
      • oh and you can tollerate opening your init.el to inclrease the font size as opposed to using C-x C-+ C--
  • It really is more readable as raw text than Markdown
    • This means if you use WorkingCopy on iOS you can practically edit and work with your org set-up
      • If you're using org-wiki you can even follow the HTML File through all the links which is great, because I think the tags and agenda suck for navigating notes/notebooks.1
      • Alternatively you could use python3 -m http.server 8351 --bind 192.168.0.134 to look on the ipad, but this is annoying because you have to grap your ipv4 before doing that if you're out of the house unlike iamcco's preview which does it automatically.
  • Foldable Code Boxes out of the box

WorkingCopyiOSwithOrg.gif

  • Once it is set up creating links with SPC a o l feels amazing
  • Inline code is amazing with outshine mode
    • I cannot get outshine to play with R though so I don't know
  • Literate Programming with it is amazing, so many of my bash scripts start as org-mode using org-edit-special and then I just pull the bash out [fn:9] and use =SPC m e e t u to give myself a manual/help dialog for it, it feels like magic!!
  • Managing long documents with emacs is a lot easier, because the folding feels very natural and the syntax highlighting is brilliant.
  • citeproc-org makes your HTML documents look just like they would with BibTeX
  • org-mode supports the minted package out of the box (minted looks better than listing and actually supports most languages like vimscript and elisp
  • org-mode interprets LaTeX properly and then passes it to mathjax, markdown is so confusing because you wrap everything in $ even if you wouldn't in LaTeX and I think that's ridiculous.
  • you never need to leave emacs
    • I map C-c e=/=v to vim emacs so it shouldn't matter.

3.1.3 Use Case

Basically the choice of format will depend on the note type,

  • A long document like a manual will go into org-mode
    • because the interlinking is brilliant and the inbuild HTML export
  • A short note will go into md because
    • fzf works in vim works with md
    • more apps support it (MWeb/iaWriter)
    • More programs have support for smaller document notes:
    • live preview of math is excellent
    • Two features, missing by org-mode2 but available for MD which are crucial to filtering through small notes (and available in Evernote) are:
      • Something I call fuzzy-search-with-live-preview which is provided only by Notable
      • Recursively Filtering through tags
        • this isn't available in md but can be easily implemented with #tags and then you can use a live preview with something like MarkText or a vim auto live preview like iamcco's which is unavailable for

3.1.4 Using pandoc

Thankfully pandoc means you shouldn't really too much about this stuff though, you can literally paste org-mode out of the clipboard into Markdown and vice-versa if you map a bash script to a keybinding 3

    input=$(xclip -o -selection clipboard)
  alias xclip='xclip -selection clipboard'
# To Org
  xclip -o |  pandoc -s -f markdown -t org | xclip 
# Back to Markdown
  xclip -o |  pandoc -s -t markdown -f org | xclip 

Actually with pipes you can do all sort of cool things, like this is an example of how to pull a website into markdown:

curl https://orgmode.org/manual/Markdown-Export.html#Markdown-Export | pandoc -f HTML -t gfm | xclip -selection clipboard

and reference it using beautifulsoup:

   arglink=$(xclip -o -selection clipboard)
 title=$(wget -qO- $arglink |
 perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
 recode html..)
 outputlink="[$title]($arglink)"
echo $outputlink | xclip -selection clipboard
  1. Problems with links

    Links may become a pain in the ass to maintain, so what i do is copy the file name to the clipboard and use fzf with this bash script to make a relative link to a file:

    #!/bin/bash
    # Don't forget to adjust the permissions with:
    #chmod +x ~/somecrazyfolder/script1
    
    ## Program
    
    
    ### Description
    # This will use fzf to find filenames that might correspond to a path from a broken link in the clipboard.
    
    # so let's say that ~[](~/broken/path/to/rsico.png)~ is a broken link, I can use ~yi(~ to copy that to the clipboard in vim  and run the following bash scipt to return the correct link:
    
    # Requires:
      # * gnu coreutils (specifically realpath)
      # * fzf
      # * xclip
    
    ### Code
    brokenPath=$(xclip -o -selection clipboard)
    #find ~/Dropbox/ -name $(echo $(basename $brokenPath)) | fzf | xclip -selection clipboard
    NewFile=$(find ~/Dropbox/ -name $(echo $(basename $brokenPath)) | fzf)
    echo $NewFile | xclip -selection clipboard
    
    echo "
    Put the path of the source file in the clipboard and Press any Key to Continue
    "
    
    # this will just continue after a key stroke
    read -d'' -s -n1
    
    echo "
    Using:
    
    "
    
    sourceFile=$(xclip -o -selection clipboard)
    
    echo "
    SOURCE_FILE.......$sourceFile
    NEW_ATTACHMENT....$NewFile 
    "
    
    
    sourcePath=$(dirname $sourceFile)
    
    relativePath=$(realpath --relative-to=$sourcePath $NewFile)
    relPathWithDot="./"$relativePath
    echo $relPathWithDot | xclip -selection clipboard
    
    echo "
    
    Success! Relative path is in clipboard
    "
    
    exit 0
    ## vim:fdm=expr:fdl=0
    ## vim:fde=getline(v\:lnum)=~'^##'?'>'.(matchend(getline(v\:lnum),'##*')-2)\:'='
    
    

4 Sharing Material

4.1 Markdown

  • HackMD is an option
  • MkDocs and GitHub

4.2 Org-Mode

4.3 HTML and iOS

  • Shortcuts
    • iCloud is quicker
    • Dropbox allows mathjax
    • WorkingCopy (best)
      • phenomenal, uses mathml for math in MD
      • uses MathJax to view Math in HTML

5 Writing Material

5.1 Diagrams

5.1.1 Apple Pencil

5.1.2 TiKz

Tikz is awesome but this is actually a bit of work to implement:

See Previous work on

  1. write in LaTeX
  2. export using a luascript
  3. grab the svg
    1. be aware that getting an svg in LaTeX is a real pain, so you can go from TeX to HTML with the lua script but not really back, its madness.
    2. Or you could go from svg to png but then you lose scaling so the whole thing sucks
    3. You could also use LaTeX and just export to HTML with Mathjax This is probably the way to go tbh.
      1. You can open the HTML from notable :shrug:

5.1.3 InkScape

6 Finding Material

6.1 Tags

Tags revolve around:

  • Entering the same tag
  • Browsing through tags

6.1.1 Yaml Tags

These are basically Notebooks, they make more sense than folders because you can change them using vim and sed which scales better over many files and is easier to maintain than manually maintaining symlinks across directories.

These are supported by:

And they work really well for there rigid strucutre

  1. Inserting YAML Tags   ATTACH

    In order to insert a YAML tag into a note with vim you can use FZF to read a text file and make suggestions from a text file with those entries:

    imap <expr> <C-c><C-y> fzf#vim#complete('cat ~/Notes/MD/notes/00tags.csv')
    

    In order to get that text file you can use an R that leverages RMarkdown to pull the yaml out:

    noteFiles <- c(dir(pattern="*.Rmd"), dir(pattern="*.md"), dir(pattern="*.txt"), dir(pattern="*.markdown"))
    tagVector <- c()
    
    # Run the following code over the entire folder
    for (i in noteFiles){
      yamlExtract <- yaml_front_matter(input = i )
      MDTags      <- (yamlExtract$tags)
      tagVector <- c(MDTags, tagVector)
    
    
    # Generate Symlinks
      for (tagDirPath in MDTags) {
            actDirPath  <- paste0("./aaaamytest/", tagDirPath)
            dir.create(path = actDirPath, recursive = TRUE)
            linkPath=paste0( actDirPath, "/", i)
            print(i)
            print(linkPath)
            createLink(link = linkPath, target = i)
      }
    }
    

    Then you can just regenerate the tags as needed with $ Rscript makeTags.R and insert them with C-c C-y.

    This can be seen in this gif:

    YAMLInsertion.gif

  2. Browsing Yaml Tags

    In order to browse YAML tags just search for the verbatim structure with ripgrep, in this context YAML tags are only used to set up notebook directories, so they will always be nested with / characters, hence the number of false positives will be small enough to justify this simplicity:

      cat 00tags.csv  | rg '[a-zA-Z0-9]+/[a-zA-Z0-9/]+'  | fzf | xargs rg -l > /tmp/kdkdjaksd;
      cat /tmp/kdkdjaksd
    # I couldn't get a pipe to work so I had to save to /tmp
    
    1. Folder Structure

      You can Also browse through the YAML tags like a folder structure, the above RScript at 6.1.1.1 uses a nested for loop to create a directory structure with symlinks for the corresponding notes.

6.1.2 #Tags

So the advantage to inline tags is that they are:

  1. Really simple to implement and use
    1. for example using YAML basically requires a parser because:
      1. if you're working with something rigid like YAML you need to support it properly or the system will fall apart, but YAML can use:
        1. python-style lists
        2. mappings
        3. New line sequences
      2. Even if YAML used just one syntax, it would not be easy to implement in regex because look around features don't like to work with wild cards, moreover doing something like \-\-\-\n[\w\W]*tags:\s cannot be efficient.
  2. Can appear anywhere in your document
    1. If you use iamcco's preview, the scroll can be locked to once you jump to the tag it will be in the preview as well.
  3. Because they are easy to implement they can be concurrently filtered

I've elected to use #tags rather than @4 becuase it's more common and is implemented by iaWriter, meaning I can use smart folders on the iPad, :tag: was another option I rejected 5.

In order to reduce false positives it's important to have a really clear definition of a tag, I've chosen to do \s#TAGNAME\s, this should work well, I just need to be mindful to include spaces around the tags.

  1. Listing already Created tags

    This is where #tags really shine, because they are easy to parse and because ripgrep and fzf are both lightning fast all the notes can be searched and all the tags listed on the fly like so:

    imap <expr> <C-c><C-t> fzf#vim#complete('rg --pcre2 "\s#[a-zA-Z-@]+\s" -o --no-filename $HOME/Notes/MD/notes -t md \| sort -u')
    

    Then simply presing C-c C-t in vim will allow you to enter the matching tag.

  2. Filtering by the desired tag

    This is where #tags are amazing, because they are so simple, they can be recursively filtered for, first create a temporary file to store any notes that have tags in them6, then use ripgrep with look-around to extract the tag name:

    First find all the tags and offer the user

       # Make a temp file to store results if necessary
      if test -f 00TagMatchList; then
              echo "subsequent search";
      else
               # List in order of modification Date, top newest
              ls -t *.md > 00TagMatchList;
      fi
    
    tagval=$(cat 00TagMatchList | xargs -d '\n' rg --pcre2 --no-pcre2-unicode --no-filename '(?<=[\n\s]#)[a-zA-z]+(?=[\s\n$])' -o | sort -u | fzf)
    

    After the tags have been identified and passed to the user, save the tagval as a temp file and search through all the notes listed in the file for any matches:

    if [[ ! -z $tagval ]]; then
        echo '
          wait for fzf to finish otherwise ripgrep has
    nothing with which to filter  '
        exit 1
    else
      cat 00TagMatchList | xargs rg ":$tagval:|\s#$tagval\s" -l > 00TagMatchList;
    fi
       bat 00TagMatchList
    

    Now you can re run those last two commands (which I've written into a bash script as tagFilter.sh here, over and over again until the number of listed tags is down to a reasonable number7 .

    Once you're satisfied that the results are sufficiently filtered you can dump them as symlinks into a direcory like so:

    mkdir 00TagMatch
    rm 00TagMatch/*
    ln -s $(realpath $(cat 00TagMatchList)) ./00TagMatch; rm 00TagMatchList
    

    Then you can go through that directory using fzf and --preview with 8:

    rg --files-with-matches --no-messages "$1" | fzf --preview "highlight -O ansi -l {} 2> /dev/null | rg --colors 'match:bg:yellow' --ignore-case --pretty --context 10 '$1' || rg --ignore-case --pretty --context 10 '$1' {}"
    

    Or you you could preview the files in ranger using glow by appending the following to your scope.sh:9

    ...
      md|markdown)
        glow -s dark "${FILE_PATH}" && { dump | trim; exit 5; }
        ;;
     ...
    
    1. Example

      This can be seen in the below gif:

      hashtagfilter.gif

  3. Integrating with TMSU

    Alternatively you can leverage TMSU to make all the symlinks, both is probably the way to go because that way you're not tied to TMSU (plus the mounting is a little buggy) but you can still leverage it

    # Piping is still better than a loop because ripgrep acts on everything
        # Unfoutunately you cannot pipe directley into tmsu
      cd ~/Notes/MD/notes
      rg --pcre2 '(?<=\s#)[a-zA-Z]+(?=\s)' *.md -o \
          | sed s+:+\ + | sed s/^/tmsu\ tag\ / | bash
    

    TMSU wouldn't work so well with nested yaml TAGS because TMSU doesn't have any notion of nested tags, instead it would be easier to create symlinks directly from R using R.utils::createLink()

  4. Browsing through the Symlinks

    Then you can mount the TMSU Virtual File System wherever you like and there is an easy to browse through tags.

    What works really well though is to open nvim in the directory with:

    # any other way causes a crash
    # also confusingly =|= is to vim as =;= is to bash
    nvim -c 'set noautochdir | cd 00tmsutags/ | pwd'#+end_src
    

    and then search through the files using :Files from FZF (mapped to C-p / SPC f f) and/or NerdTree, and use iamcco's preview in Firefox with Tree Style Tab to stay organised. If you'd rather work from bash you can use fzf with the --preview option from before.

    Or you could use vim with and a preview app like iamcco's.

    Or you could preview all the markdown in a rendered state by using MarkText / or Typora, or Zettlr, Abricotine, Typora, MarkdownViewer Chrome Plugin10 , MkDocs or Docsify, are other options that work in some way.

    Another good option for navigating the 'tags are now folders' structure is to use VSCode and/or atom, both are well suited to navigating through a dense structure.

    Dillinger is also really cool, but, I don't know what I'd use it for, could I get it on the ipad by hosting my own server maybe?

  5. Renaming Tags

    Just use a careful application of sed if this is necessary:

    sed -i s+#OldTag+#NewTag+g
    
  6. Renaming Files

    Somewhat integral to the Tag Filtering operation above is reasonable file names, if it's necessary to fix the file name just use chdir "%p"; ! mv "%" newname.md.

    This will break links, but if a note is already linked from elsewhere you'd make a new note and/or delete the old one.

  7. Searching Tag Under Cursor

    In order to search for the word under the cursor you could just :Rg by FZF , :NV by notational-fzf-vim offers a seamless preview as well so I'll just use that.

    Add the following to .vimrc and you'll be able to search for a tag under the cursor with SPC f g and if you forget keyboard shortcuts SPC Tab will list them.

    "let mapleader="\<Space>"
    map <Space> <Leader>
    
    :set iskeyword+=#
    nmap <Space>fg :NV <C-r><C-w> <CR>
    nmap <leader><tab> <plug>(fzf-maps-n)
    

7 Viewing Material

7.1 Vim-Plugin

7.2 Firefox

while Previewing MD in the browser, in order to keep your sanity, you're going to want to use this Tree add on to keep yourself organised.

7.3 Chrome Browser Extension

Firefox will not allow local MD files to be rendered with an add on as a security policy, instead you can Firefox doesn't allow markdown files to be rendered inside the browser if they are local ( nor does it make it easy if you do it with a simple python3 -m http.server 8089 --bind 192.168.0.137 ) you'd be better off just doing it in chrome with This extension

7.4 WYSIWYG Editor

7.5 Notable

8 Appendix

8.1 Emacs Speaks Statistics

Emacs is amazing for literate programming, but it's a nightmare to work with, it has it's place but Nvim-R is definitely best in class for literate programming using R-Markdown, but there are cases where using R in org-mode is really handy, for example, to make a bar chart of all the words in this manual:

## Load Tidy Verse
library(tidyverse)

## Scan Through the Manual
  words <- tolower(scan("./manual.org",
                   what = "", na.strings = c("|",":"))
                  )

## Use Grep to pull out org #+ Blocks
  words <- words[-grep(pattern = "#.*", x = words)]

## Sort the words by frequency and cut the results
  topwords <- sort(table(words[nchar(words) > 3]), decreasing = TRUE)[1:9]
  topwords <- as_tibble(topwords, .name_repair = "universal")
  names(topwords) <- c("Word", "Frequency")
  print(topwords)

Word Frequency
with 54
this 44
using 29
tags 24
because 21
just 21
like 21
will 21
that 20
## Make Plot
WordFreqPlot <-  ggplot(topwords, aes(y = Frequency, x = Word, fill = -Frequency))  +
     geom_col() +
     theme_minimal()


# Export the Plot into the working directory
plotname <- "WordCount"
png(filename=paste0(plotname, ".png"))
print(WordFreqPlot)
dev.off()

# Print the =org-mode= link syntax
print(paste0(
   "\n",
    "Output:", "\n",
     "[[./", plotname, ".png", "]]"))
x
Output:
WordCount.png

8.1.1 Using ESS with org-babel

  1. Output types
    1. Results Type

      Notice that this block when executed with C-c will give the STDOUT

      rnorm(9)
      
      [1]  0.6382742  0.8345823  1.7164897 -1.6547841  0.3749552 -0.3740537 -0.1397769
      [8]  1.7248219 -0.6240926
      

      Where as this block will give the expected results:

      rnorm(9)
      
      -0.291413700921148
      -0.842118271320166
      0.607393290039903
      -1.45235488571945
      0.76756412055268
      -0.781050222761955
      -0.00871441944811291
      2.55762250149617
      0.035717298920082
    2. Format Type

      You can also change the output to better integrate with org by using :format raw or :format org:

      rnorm(9)
      
      -0.77482993685678
      0.0965881713078849
      -0.14713783099907
      0.872082762958436
      0.430324516204023
      1.09693115216299
      -1.08671165152439
      0.0577277935967486
      1.99238195515524
  2. Working with Graphics

    Switching back to :results value so we don't get crap from the graphic export:

    library(tidyverse)
    rnorm(9) %>% hist()
    

    We can see that this gives us a popup, which we don't really want, instead, let's deal with an inline image, previously I was able to acheive this by using :results output graphics, that's since stopped working, it would probably better to just bypass the broken org-babel bullshit and deal with it all from R, it's not as nice but theres not much I can do about that.

    library("ggplot2")
    # Using SVG is also an option, but LaTeX sucks.
    svg(filename="pipe.svg")
    
    # Give the filename of the plot and a Description
    plotname="chocolatemouselamp"
    description= "Just a test to get =org-babel= plots"
    
    # Export the Plot into the working directory
    png(filename=paste0(plotname, ".png"))
    print(qplot(mpg, wt, data = mtcars))
    dev.off()
    
    # Print the =org-mode= link syntax
    print(paste0(
    
       "\n",
        "Output:", "\n",
         "[[./", plotname, ".png", "]]"))
    
    Output:
    chocolatemouselamp.png

Footnotes:

1

Yes I've been patient, no it doesn't work for me.

2

Atleast easily in a fashion I could make work

3

OK, so I know this is a pain in i3, and yes i3-gaps looks awesome, but you could probably get away with using xmodmap somehow, and this would be WM agnostic.

4

This is used by Notes.vim

5

This is used by VimWiki and org-mode, I don't like them because pymarkdown already uses : to delimit emojis. Also org-mode only uses them in Headlines, according to the manual.

6

A variable would be quicker than a file because it's stored in memory, I did a file when I was playing in the terminal using for loops rather than pipes and it just made it's way into the script I'm using, there is a TODO next to it but the whole script needs to be rewritten anyway.

7

This is why using descriptive file names is important, with all notes in one directory it will be necessary to have unique file names, but using a sample of 1000 words and never repeating a word and not using the same 3 words in two files there will be \(\binom{1000}{3} > 10^6\) different combinations, so there is no need to use a UUID.

8

I got this idea from the Github Wiki

9

ranger crashes all the time though, there's some bug with the way the directories are mounted and vim, for example vim can only change into that directory after being loaded, so vim -c 'cd 00tmsutags' is fine but vim 00tmsutags is not fine.

10

You might want to start a python server for this with python3 -m https.server 8392

Author: ryan

Created: 2020-02-03 Mon 12:20

Validate