Search code examples
emacsshorg-mode

org-mode, how to automatically generate nice file hierarchy trees with well-formed Org links


When working with Org-Mode, I am looking for a solution to automatically generate tree of well-formed org-mode links.

For instance, to create links to all c++ files under a directory, I want something like:

enter image description here


Update: I just tried @DamianChrzanowski suggestion, the org-fstree package. However I am a little bit disappointed by the results:

enter image description here

The html export result is even worst:

enter image description here

My conclusion is that package does not fulfil my needs. Anyway, thanks to @DamianChrzanowski for his answer.


Solution

  • With the linux tree command installed I came with the following script that fulfils all my needs:

    #+NAME: createTree
    #+BEGIN_SRC sh :results drawer :var toInclude="*.org" :var toExclude="" :var directory="./" :var createLink="true" :exports none
    set -e
    buffer=$(mktemp /tmp/buffer.XXXXXXXXX)
    current_directory=$(pwd)
    cd $(eval echo "$directory")
    tree -a -P "$toInclude" -I "$toExclude" -if --noreport  --prune \
        | sed "s/.//"  | sed "s/^\///"  > "$buffer"
    
    if [ $(grep --regexp="$" --count "$buffer") -eq 0 ]; then
        echo "**ERROR empty list**"
    else
        for f in $(cat "$buffer")
        do 
        filename=$(basename $f)
        ext="${filename##*.}"
        baseFilename="${filename%.*}"
        if [ -f $f ]; then
            # removes org extension (only)
            if [ "$ext" = "org" ]; then
            filename="$baseFilename"
            fi
            # creates org link (or not)
            if [ "$createLink" = true ]; then 
            echo "$(echo "$f" | tr -cd / | tr / \\t)+ [[file:"$directory/$f"][$filename]]"
            else
            echo "$(echo "$f" | tr -cd / | tr / \\t)+ $filename"
            fi
        else
            echo  "$(echo "$f" | tr -cd / | tr / \\t)+ $filename/"
        fi
        done
    fi
    rm "$buffer"
    cd "$current_directory"
    #+END_SRC
    

    If you want to create a file tree of your C++ code, simply use something like:

    #+CALL: createTree(toInclude="*.[hc]pp",toExclude="*test*",directory="~/MyProject")
    

    Also, note that you can use it as an alternative to sitemap when you export/publish your org-mode documents. Simply use:

    * My site content
    
    #+CALL: createTree(toInclude="*.org",toExclude="Setup")
    

    The previous #+CALL commands will generate tree like the one I posted in my question. After Org HTML export, you will get something like: enter image description here


    The command arguments/options are:

    • toInclude="..." : pattern to include
    • toExclude="..." : pattern to exclude
    • directory="..." : directory
    • createLink="true" or "false" : if false the tree is created without links

    Note 1: you can store the script in any .org file and load it thanks to Library-of-Babel :

    In your init.el file:

    (org-babel-lob-ingest "~/path/to/your/scripts.org")
    

    Note 2: I answered my own question, but I am still open to a pure Emacs-Lisp solution.