Multiple Joplin CLIs with Vim Note Preview (Linux Hack)

TL;DR

This is how I’ve set up multiple instances of the Joplin Terminal Application that features Vim real-time markdown previews.

[edit]: removed references to symlinking the Joplin database. See: discussion

Disclaimer:

  • This document might be naive: This is my first week using Joplin.
  • Hi, I wasn’t sure where to put this information so please redirect me if needed.
  • I primarily use terminals and CLIs in my workflow (I use the mouse as little as possible).
  • Recently I mentioned a possible HTML export method on Export to HTML · Issue #1167 that eluded to a workflow use case. This post is a follow up to how I’ve configured the various tools involved.
  • There is another thread that discusses this topic: Can I run a second instance of Joplin?
  • I realize that changes in the Joplin framework may change -and possibly render this information useless.
  • Make sure you have a verified incremental backup system in place before attempting the sugestionons herein.

Summary:

Features of this workflow and tool configuration:

  • 2+ instances of Joplin Terminal App (Joplin CLI) on the same system
  • Shared resources directories
  • Real-time web browser preview (with note images/resources) of notes that are edited through Vim editor.
  • This is much simpler than it seems -and mostly transparent
  • Faster Sync times do to shared resource folder among instances

Tools used:

Limitations:

  • Previews can’t follow links that lead to other notes.
  • I consider this is considered a bit of a Hack.
  • These hacks may be incompatible with future versions of Joplin.
  • Editing the same file in multiple Joplin instances will cause a conflict -which is normal.

Managing Multiple instances of Joplin on the Same System

Joplin Terminal Application User Instances

  • .bashrc/.profile uses an alias to run CLI’s from different profiles
    • command: joplin starts one CLI instance in the default profile location

    • command: joplin2 starts a second CLI instance with a separate profile

      • the .bashrc alias looks like this:
      # second instance of Joplin - i only need 2 user instances
      alias joplin2="joplin --profile $HOME/.config/joplin-2nd"
      

CLI Profile Configuration

  • The default instance profile is not altered
    • with 1 exception -see below
  • Each additional instance profile retains it’s own directory with:
    • tmp/ directory
    • log-database.txt
    • log.txt
    • database.sqlite
  • Additional instance profiles use symlinks to access data in the default instance profile
    • keymap.json, and resources are symlinked to the default instance profile
    ~/.config/joplin-2nd
    ├── database.sqlite
    ├── keymap.json -> ../joplin/keymap.json
    ├── log-database.txt
    ├── log.txt
    ├── resources -> ../joplin/resources
    └── tmp
    

Vim Preview Details -and cron job with script

How it works:

The Vim markdown-preview plugin uses references in the current working directory of the file being edited to serve on a web page. By symlinking the resource folder within the tmp directory the ‘markdown-preview’ plugin service has access to the files of the resources. This also has the advantage of less file copying for resources content between instances.

Configuration:

  1. Install and test the vim plugin for markdown previews:

  2. Create a script that will create a link in the default profile tmp directory back to the default profile resources directory

    • The default profile directory structure will end up looking like this:
    ~/.config/joplin
    ├── database.sqlite
    ├── keymap.json
    ├── log-database.txt
    ├── log.txt
    ├── resources
    │   └── <...long list of files>
    └── tmp
        └── resources -> ~/.config/joplin/resources
    
    • The script will look like this:
    #!/usr/bin/env bash
    
    # script name: joplin_resource-link.sh
    # Cheezy script that creates a link as needed.
    # This should probably be done with a watch service instead.
    
    # cron entry
    # * * * * * /home/karl/mbin/joplin_resource-link.sh
    
    RESOURCES_LINK="$HOME/.config/joplin/tmp/resources"
    RESOURCES_DIR="$HOME/.config/joplin/resources"
    
    #run every 5 seconds with a cron trigger set for every minute
    for i in {1..12};
    do
        if [ ! -L "$RESOURCES_LINK" ];then
            ln -s "$RESOURCES_DIR" "$RESOURCES_LINK"
        fi
        sleep 5
    done
    
  3. Create a cron entry to launch the script every minute

    • use crontab -e
    * * * * * /home/karl/mbin/joplin_resource-link.sh
    
  4. Repeat steps 2 and 3 for each CLI instance (if desired)

    • Adjust the script for the paths of each instance.
    # example from the script:
    RESOURCES_LINK="$HOME/.config/joplin/tmp/resources"
    
    # would become:
    RESOURCES_LINK="$HOME/.config/joplin-2nd/tmp/resources"
    

That’s it. Hope this is useful/helpful.

3 Likes

Good stuff, man. I would honestly love to see a terminal app option being built into Joplin so that when running the Desktop app, one could replace the edit tab with a full vim session for those of us that have limited desktop space or only want to write in Vim but preview in Joplin.

Also, I use the kitty terminal with the Hack Nerd Fonts. One really cool thing about how I’ve got it configured: when I’m doing markdown in Neovim, I can preview the basic formatting of all my text directly in the editor. Kitty automatically changes the font to bold, italic, etc, as long as the font used offers those styles.

2 Likes

One thing to note is that if you link the database, you should also link the associated sqlite-journal file (which appears when needed and gets deleted afterwards), otherwise you will lose some transactions.

The fact that this file comes and goes makes it tricky to link it though.

1 Like

Ok. That’s very interesting. I think it’s best that I not link the databases then for now. If I come up with some other solution (i.e. adding an asynchronous watch instead of a polling cron job) I’ll comment here.

I’ll adjust the document accordingly later this evening.

1 Like

Cool about Kitty terminal. I've tried it a few times but have kept going back to my trusty Terminator terminal. I think terminal emulators like Kitty are definitely the way things are trending though -image viewing, variable font rendering, etc. ...and, once the terminal emulator wars get decided, someday, we'll probably end up with a standard that includes all the features of Kitty and quite a bit more -it's a matter of the graphics libraries catching up with technology IMHO.

Also I support your idea about a vim-like editor in the Desktop. I would like to see a much more robust keymap overall; with sexy vim kebindings and macros(!). Likewise, though, I am only just becoming a "Jopliner" and I'm not sure about why or how development decisions were/are made. ...I hope to contribute when/where I can though :smiley:

For what it's worth, here's my keymap.json for the CLI. I use surfingkeys plugin in by browsers, vim command line in bash, vim as an editor, etc. So I made my keymap more vim-ish. I thought you might find it useful(?):

[
	{ "keys": [":"], "type": "function", "command": "enter_command_line_mode" },
	{ "keys": ["TAB","l"], "type": "function", "command": "focus_next" },
	{ "keys": ["SHIFT_TAB","h"], "type": "function", "command": "focus_previous" },
	{ "keys": ["UP","k"], "type": "function", "command": "move_up" },
	{ "keys": ["DOWN","j"], "type": "function", "command": "move_down" },
	{ "keys": ["PAGE_UP","K","u"], "type": "function", "command": "page_up" },
	{ "keys": ["PAGE_DOWN","J"," "], "type": "function", "command": "page_down" },
	{ "keys": ["ENTER"], "type": "function", "command": "activate" },
	{ "keys": ["DELETE", "BACKSPACE","dd"], "type": "function", "command": "delete" },
	{ "keys": ["dt"], "command": "todo toggle $n" },
	{ "keys": ["dc"], "command": "todo clear $n" },
	{ "keys": ["tc"], "type": "function", "command": "toggle_console" },
	{ "keys": ["tm"], "type": "function", "command": "toggle_metadata" },
	{ "keys": ["/"], "type": "prompt", "command": "search \"\"", "cursorPosition": -2 },
	{ "keys": ["mn"], "type": "prompt", "command": "mknote \"\"", "cursorPosition": -2 },
	{ "keys": ["mt"], "type": "prompt", "command": "mktodo \"\"", "cursorPosition": -1 },
	{ "keys": ["mb"], "type": "prompt", "command": "mkbook \"\"", "cursorPosition": -2 },
	{ "keys": ["yn"], "type": "prompt", "command": "cp $n \"\"", "cursorPosition": -2 },
	{ "keys": ["dn"], "type": "prompt", "command": "mv $n \"\"", "cursorPosition": -2 },
	{ "keys": ["oR"], "type": "prompt", "command": "config notes.sortOrder.reverse \"true\"", "cursorPosition": -2 },
	{ "keys": ["or"], "type": "prompt", "command": "config notes.sortOrder.reverse \"false\"", "cursorPosition": -2 },
	{ "keys": ["ot"], "type": "prompt", "command": "config notes.sortOrder.field \"title\"", "cursorPosition": -2 },
	{ "keys": ["oc"], "type": "prompt", "command": "config notes.sortOrder.field \"user_created_time\"", "cursorPosition": -2 },
	{ "keys": ["ou"], "type": "prompt", "command": "config notes.sortOrder.field \"user_updated_time\"", "cursorPosition": -2 }
]

2 Likes

That is super cool. I never thought about vimifying all of my apps, though. It’d take a bit of work but would be cool to embark on while I work on ricing a bit with my free time too. Ever do that? (It’s building your own custom desktop through window managers and configs).

heh, I’m a ricer… from FVWM, to Enlightenment, to XFCE, etc. It’s gotta be pretty as well as elegant…

It doesn’t necessarily have to be pretty for me but flow a good bit.

1 Like

Fair enough.
BTW, this is somewhat off topic now… I’m a big no-mouser person too. Here’s a link to my Surfingkeys. config jist. it’s fairly vim-ish IMHO: my surfingkeys.js (google chrome surfingkeys extension configuration)

In particular you might find this surfing keys macro useful:

//copy page title and url in markdown format to clipboard
mapkey('yY', '#7Copy page title and url as markdown', function() {
    Clipboard.write('['+document.title+']'+'('+window.location.href+')' );
});