Showing 393 to 396

Org-roam fixes

Some mods to #org-roam I've felt necessary.

<2024-Aug-20>: My replacement package org-node now contains all of these features!

Skip prompting for a filename

It's enough that you gave a title, shouldn't also have to confirm the filename, right?

(setq org-roam-capture-templates
      '(("d" "default" plain "%?" :if-new
         (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
                    "#+title: ${title}\n#+filetags: :noexport:stub:"))
        :immediate-finish t
        :jump-to-captured t))

Quick stubsđź”—

Situation: You're in the middle of writing and you realize you want to link to a node that doesn't yet exist.

I have the following capture template for that. It makes a blank new file without visiting it, so you can pick it on the org-roam-node-insert screen and be on your merry way.

(add-to-list 'org-roam-capture-templates
             '("i" "instantly create this node" plain "%?" :if-new
               (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
                          "#+title: ${title}\n#+filetags: :stub:\n")
               :immediate-finish t)

Performanceđź”—

Org-roam gets slow as you accumulate thousands of nodes. The following code fixes it. Requires the packages memoize and vulpea.

Vulpea provides faster versions of org-roam commands, but it depends on its own optimized database. The first time you enable vulpea-db-autosync-mode, you need to eval (org-roam-db-sync 'force) so it can populate that database.

;; Make the commands `org-roam-node-find' & `org-roam-node-insert' faster and
;; often instant.

;; Small drawback: after you just created a node, you can't immediately
;; find it as it won't be in the cache.  You must leave Emacs alone for
;; 10 seconds, then it'll enter the cache.

(defun my-vulpea-memo-refresh ()
  (memoize-restore #'vulpea-db-query)
  (memoize         #'vulpea-db-query)
  (vulpea-db-query nil))

(defvar my-vulpea-memo-timer (timer-create))
(defun my-vulpea-memo-schedule-refresh (&rest _)
  "Schedule a re-caching when the user is idle."
  (cancel-timer my-vulpea-memo-timer)
  (setq my-vulpea-memo-timer
        (run-with-idle-timer 10 nil #'my-vulpea-memo-refresh)))

;; Love this lib. Thank you
(use-package vulpea
  :hook ((org-roam-db-autosync-mode . vulpea-db-autosync-enable))
  :bind (([remap org-roam-node-find] . vulpea-find)
         ([remap org-roam-node-insert] . vulpea-insert))
  :config
  (use-package memoize :demand)
  (memoize #'vulpea-db-query)
  (advice-add 'org-roam-db-update-file :after 'my-vulpea-memo-schedule-refresh))

Other speed boosts

;; Don't search for "roam:" links (it slows saving on large files)
(setq org-roam-link-auto-replace nil)

;; Speed up `org-roam-db-sync'
;; NOTE: `setopt' breaks it, use `setq'
;; NOTE: Counterproductive on Windows
(setq org-roam-db-gc-threshold most-positive-fixnum)

If you still find it slow to save large files, maybe you have org-crypt configured. It's that package that encrypts/decrypts subtrees.

Doom Emacs' Org module ships it by default, so here's how to disable it in Doom's packages.el:

(package! org-crypt :disable t)

Custom org-roam-extract-subtreeđź”—

I encourage you to maintain a personal variant of org-roam-extract-subtree. It's a pleasure to have one that does everything right.

Here's mine. Compare with the original (type M-x find-function org-roam-extract-subtree RET). Differences from the default command:

  1. Actually make a file-level node, i.e. a file with :PROPERTIES: at the top, instead of a plain file with a top-level heading
  2. Skip prompting for a title – just reuse the heading as title
  3. Copy the original file's :CREATED: property if the subtree didn't already have its own (I use this property everywhere because it's not as if you can rely on filesystem ctime)
  4. Copy all the parent tags
    • Only if org-use-tag-inheritance is t
    • If there were no tags anywhere, add a :noexport: tag. That's normally what I want for new nodes (Slipbox workflow).
  5. Add a #+date: for me to fill in later
    • I use this field to indicate the date of "last meaningful update", thus it becomes Last Updated on my blog. Could use file modification time, but it is not meaningful.
  6. Show the resulting file to me, so I can verify it looks right
  7. Leave a link in the original file, where the subtree was
(defun my-org-roam-extract-subtree ()
  "Variant of `org-roam-extract-subtree'.
It skips prompting, and inserts the metadata I want."
  (interactive)
  (save-excursion
    (org-back-to-heading-or-point-min t)
    (when (bobp) (user-error "Already a top-level node"))
    (org-id-get-create)
    (save-buffer)
    (org-roam-db-update-file)
    (let* ((template-info nil)
           (node (org-roam-node-at-point))
           ;; Determine filename based on `org-roam-extract-new-file-path'
           (template (org-roam-format-template
                      (string-trim (org-capture-fill-template
                                    org-roam-extract-new-file-path))
                      (lambda (key default-val)
                        (let ((fn (intern key))
                              (node-fn (intern (concat "org-roam-node-" key))))
                          (cond
                           ((fboundp fn)
                            (funcall fn node))
                           ((fboundp node-fn)
                            (funcall node-fn node))
                           (t (let ((r (read-from-minibuffer (format "%s: " key) default-val)))
                                (plist-put template-info ksym r)
                                r)))))))
           (file-path
            (expand-file-name template org-roam-directory))
           (parent-tags (org-get-tags))
           (parent-creation (save-excursion
                              (goto-char (point-min))
                              (org-entry-get nil "CREATED"))))
      (when (file-exists-p file-path)
        (user-error "%s exists. Aborting" file-path))
      (org-cut-subtree)
      (open-line 1)
      (insert "- " (org-link-make-string
                    (concat "id:" (org-roam-node-id node))
                    (org-roam-node-formatted node)))
      (save-buffer)
      (find-file file-path)
      (org-paste-subtree)
      (while (> (org-current-level) 1)
        (org-promote-subtree))
      (save-buffer)
      (org-roam-promote-entire-buffer)
      (goto-char (point-min))
      (unless (org-entry-get nil "CREATED")
        (org-set-property "CREATED" (or parent-creation
                                        (format-time-string "[%F]"))))
      (org-roam-tag-add (or parent-tags
                            '("noexport")))
      (search-forward "#+title")
      (goto-char (line-beginning-position))
      (if (version<= "29" emacs-version)
          (ensure-empty-lines 0)
        (when (looking-back "\n\n")
          (join-line)))
      (search-forward "#+filetags" nil t)
      (forward-line 1)
      (open-line 2)
      (insert "#+date:")
      (save-buffer))))

Custom org-open-at-pointđź”—

Before you can start to use roam refs confidently, or even really understand what they are, you need a picture in your head of how they will make your life easier.

Part of my picture was that I should be able to insert a raw URL anywhere and then if I click on it, Emacs will jump to the corresponding roam-node if I happen to have one that refs that URL.

This replacement for org-open-at-point does that.

(define-key global-map [remap org-open-at-point]
            #'my-org-open-at-point-as-maybe-roam-ref)
(defun my-org-open-at-point-as-maybe-roam-ref (&optional arg)
  "Like `org-open-at-point', but prefer to visit any org-roam node
that has the link as a ref.
If already visiting that same node, then follow the link normally."
  (interactive "P")
  (let* ((url (thing-at-point 'url))
         (path (if (derived-mode-p 'org-mode)
                   (org-element-property :path (org-element-context))
                 (replace-regexp-in-string (rx bol (* (not "/"))) "" url)))
         (all-refs (org-roam-db-query
                    [:select [ref id]
                     :from refs
                     :left-join nodes
                     :on (= refs:node-id nodes:id)]))
         (found (when path (assoc path all-refs))))

    (if (and found
             ;; check that the ref does not point to THIS file (if so, better to
             ;; just open the url normally)
             (not (when (derived-mode-p 'org-mode)
                    (equal (cdr found)
                           (or (org-id-get)
                               (progn
                                 (goto-char (point-min))
                                 (org-id-get)))))))
        (org-roam-node-visit (org-roam-node-from-id (cadr found)))
      (if arg
          (org-open-at-point arg)
        (org-open-at-point)))))

Command to auto-rename file based on #+TITLEđź”—

In Org-roam, nodes are named by the #+title line – it doesn't care about the name of the files on the filesystem.

However, the filename does influence the exported HTML filenames, which determines your blog post addresses.

With the following command, you can type M-x my-rename-roam-file-by-title whenever you want to update the filename.

(defun my-rename-roam-file-by-title (&optional path)
  "Rename file in current buffer, based on its Org
#+title property.

Can also take a file PATH instead of current buffer."
  (interactive)
  (unless path
    (setq path (buffer-file-name)))
  (unless (equal "org" (file-name-extension path))
    (user-error "File doesn't end in .org: %s" path))
  (let* ((visiting (find-buffer-visiting path))
         (on-window (and visiting (get-buffer-window visiting)))
         (slug
          (with-current-buffer (or visiting (find-file-noselect path))
            (goto-char (point-min))
            (let ((node (org-roam-node-at-point t)))
              (unless (org-roam-node-title node)
                (user-error "Node not yet known to org-roam DB"))
              (org-roam-node-slug node))))
         (new-path (expand-file-name (concat slug ".org")
                                     (file-name-directory path))))
    (if (equal path new-path)
        (message "Filename already correct: %s" path)
      (if (and visiting (buffer-modified-p visiting))
          (message "Unsaved file, letting it be: %s" path)
        (unless (file-writable-p path)
          (error "No permissions to rename file: %s" path))
        (unless (file-writable-p new-path)
          (error "No permissions to write a new file at: %s" new-path))
        ;; Kill buffer before renaming, to be safe
        (when visiting
          (kill-buffer visiting))
        (rename-file path new-path)
        (prog1 (message "File %s renamed to %s"
                        (file-name-nondirectory path)
                        (file-name-nondirectory new-path))
          ;; Visit the file again if you had it open
          (when visiting
            (let ((buf (find-file-noselect new-path)))
              (when on-window
                (set-window-buffer on-window buf)))))))))

Command to rename an image asset and rewrite all links pointing to it

(defun my-rename-roam-asset-and-rewrite-links ()
  (interactive)
  (require 'dash)
  (when (or (equal default-directory org-roam-directory)
            (when (yes-or-no-p "Not in org-roam-directory, go there?")
              (find-file org-roam-directory)
              t))
    (when-let ((bufs (--filter (string-search "*grep*" (buffer-name it))
                               (buffer-list))))
      (when (yes-or-no-p "Some *grep* buffers, kill to be sure this works?")
        (mapc #'kill-buffer bufs)))
    (let* ((filename (file-relative-name
                      (read-file-name "File: ") org-roam-directory))
           (new (read-string "New name: " filename)))
      (mkdir (file-name-directory new) t)
      (unless (file-writable-p new)
        (error "New path wouldn't be writable"))
      (rgrep (regexp-quote filename) "*.org")
      (run-with-timer
       1 nil
       (lambda ()
         (save-window-excursion
           (delete-other-windows)
           (switch-to-buffer (--find (string-search "*grep*" (buffer-name it))
                                     (buffer-list)))
           (wgrep-change-to-wgrep-mode)
           (goto-char (point-min))
           (query-replace filename new)
           (wgrep-finish-edit)
           (when (y-or-n-p "Finished editing links, rename file?")
             (rename-file filename new)
             (message "File renamed from %s to %s" filename new)))))
      (message "Waiting for rgrep to populate buffer..."))))
Created (12 months ago)
Updated (8 months ago)

Do recruiters do anything useful?

Paraphrasing a story someone told on HN: "everyone brags that they hire only the top 1% of developers. Problem is that can't be true, if 100% of the developers here get hired eventually." What's happening is that every time they decide to hire someone, they filter out 99% of what's left on the market and find someone. Then another company filters out 99% of what's left after that, and so on… until all developers have been distributed equally among the companies.

A lot of work for nothing? Why not skip filtering?

Maybe it's that if one company doesn't bother to filter, they will end up with a worse crop over time than the others. (Assuming that filtering is possible, but that's another topic.)

Created (8 months ago)

Using KMonad with an unidentifiable Bluetooth keyboard

#tech

Normally, you specify which physical keyboard KMonad should apply its rules to, through an address on Linux /dev/input/by-id/.... Some Bluetooth keyboards are made wrong and don't get a persistent ID. What can you do then?

Here's the Bash script I run after every connect to find it by heuristic. I'm quite proud of it :-)

(In here, the file-path /home/kept/sysconf/kmonad/trust.kbd just points to my kmonad config file, replace as needed)

#!/usr/bin/env bash
# Find the current /dev/input/event for my bluetooth keeb, assuming I only have
# one connected.
MY_KBD="$(udevadm info /dev/input/event* | grep blue | head -1 | sed 's/.*\(event[^\/$]*\).*/\1/g')"
export MY_KBD
NEW_KMONAD_CONFIG="$(envsubst < /home/kept/sysconf/kmonad/trust.kbd)"

echo "$NEW_KMONAD_CONFIG" | sudo kmonad /dev/stdin

That's not the whole story yet. The kmonad config (again /home/kept/sysconf/kmonad/trust.kbd, named after the cheap & bad Trust Bluetooth Keyboard—don't buy it) also needs an edit, so that it contains the magic string $MY_KBD in the device-file declaration:

(device-file "/dev/input/$MY_KBD")
Created (10 months ago)

Logseq as "org-roam mobile"

Background

What is it that every Org-mode knowledge worker needs but doesn't have? A WYSIWYG Org editor for mobile.

You see, for the use-case of plain notetaking, all the traditional Org apps like Beorg, PlainOrg, MobileOrg and Organice fall flat: they seem to be oriented towards TODO tasks & scheduling & reminders, and they presume that if you write prose or poetry, you will only capture to an inbox file and sort it out later on your desktop. Polish a hundred files of prose? No way, no one does that! Right? (None of your users do, I'm sure, but there's a reason for that)

So, they hide the free-form text editor several screen taps away, and it lacks all UX.

I'm not looking for TODO task integration, I just need a smooth writing experience like the iPhone's built-in Notes app. Nothing more. Because I have to use apps like iOS Notes instead of Beorg & co, all my notes on-the-go end up siloed in that app. I'm tired of mentally tracking the disconnect between "my notes on the phone" and "my real Org notes on the laptop".

Enter Logseq! If you've briefly tried Logseq mobile in the past, you might be surprised to hear that it has a reasonable editing experience, more so than the other platforms I mentioned.

However, Logseq appears confusing on first try. It uses non-standard UX and lacks some discoverability, and the tutorials I found by Googling failed to cut through to the relevant facts for someone like you and me.

The gotchas I wish someone'd told me

Disclaimer: not all these problems will apply to you. I would have fewer problems writing "traditional" large Org files, but I write according to org-roam conventions, i.e. many small "zettelkasten".

OK, let's get started!

Formatting norms

Starting out, you'll note Logseq seems to put absolutely everything in a list. These lists are a lie. What you think is a list item is what they call a "block", which translates to Org jargon as a subtree.

This looks familiar only so long as you don't really have paragraph-text under your Org headings. If you do, you can hide the leading bullets by switching to "Document mode", and the result may feel more familiar.

To make sense of the Logseq UI, know that it's designed around the assumption you'll use subtrees extensively. This flies in the face of how I and many others write in Org-roam: many of my files have zero subtrees.


The above leads us to a small gotcha: Logseq expects headings. If the first logical line of text is not a heading, Logseq will still interpret it as a heading. So there's this odd leading bullet out of nowhere before the first paragraph. Think nothing of it; it's only cosmetic. Again, Document mode should hide it (sometimes it bugs and does not, so turn it off and back on).

(In fact, the bullet-out-of-nowhere happens even if the first paragraph is actually a set of properties such as #+TITLE, but you can hide them by putting into config.edn the line :block-hidden-properties #{:title}. Then you'll instead have an empty line at the top, which is there because of the file-level ID in your Org-roam files. Again, just cosmetic. A blank line isn't so bad.)


On the mobile app, we have buttons for manipulating subtrees: all the polished stuff you'd expect, like indenting and outdenting them, and moving them. These work only on subtrees! In fact, TODO state ends up being visually rendered as a checkbox when you're not editing, which tells you something about how they intend subtrees to be used.

You don't need to adopt the writing style presumed by Logseq, but it basically works like this: imagine that your initfiles include (setq org-startup-folded 'showeverything), and you eliminate the settings for the faces org-level-1 thru org-level-8 so that headings look just like the default face. Then you write lots and lots of headings, as if they were plain lists, and forget about regular plain lists. That's the expected style in a nutshell.

Bear in mind, Logseq will render conventional Org documents fairly sanely, so it works fine as a viewer. The discomfort arises when you want to edit inside Logseq and still stick to your non-Logseq norms: then you need to always keep in mind what you're doing to the underlying file. But I expect this becomes second nature after some time.

Collaboration

An extra conundrum arises when you want to use Logseq to collaborate on documents with a partner. In that case, I suggest giving up and formatting those specific documents in the Logseq way to make your partners more comfortable in the app, if they aren't technical people.

To edit such Logseq-ified documents in Emacs, I make myself comfortable with this buffer-local mode:

(defvar-local my-logseq-cookies nil)
(define-minor-mode my-logseq-mode
  "De-fontify Org headings."
  :group 'org
  (when (featurep 'org)
    (let ((headline-faces '(org-level-1
                            org-level-2
                            org-level-3
                            org-level-4
                            org-level-5
                            org-level-6
                            org-level-7
                            org-level-8)))
      (if my-logseq-mode
          (dolist (face headline-faces)
            (push (face-remap-add-relative face 'default) my-logseq-cookies))
        (while my-logseq-cookies
          (face-remap-remove-relative (pop my-logseq-cookies)))))))

Also: Never write tables or plain lists in these documents, they're hard to edit from inside Logseq mobile.

For the rest of this post, my tips assume you aren't doing this, but formatting org-mode files like you'd normally do: with headings-as-headings (as short as possible), NOT headings-as-paragraphs (potentially very long).

Syncing

If any of your devices is an iPhone/iPad, you'll have to use Logseq Sync, an experimental beta feature.

As an experimental beta feature, Logseq Sync isn't a poster child of sync resolution (as of [2023-04-09 Sun]) – it isn't made for the purpose of simultaneous collaboration, nor is it prepared to find that someone has edited the files in Emacs while Logseq was not running.

(You'd think it would be at least on par with the simple disk file-based syncers like Syncthing and Nextcloud, but it isn't yet.)

So stay safe:

  • Try to edit only one person at a time, and ensure the sync is complete before beginning to edit.
  • Ensure the sync is complete (cloud icon turns green) before closing the app.
  • Before editing in Emacs, launch Logseq so it can sync in the background.
  • Use only one graph in Logseq, because as of [2023-04-09 Sun] it only syncs the currently opened graph, leaving the others unsynced!
  • When anything feels off, or you know that one of you has created/renamed files, use the "Re-index" action.
  • Donate so Logseq Sync gets better.
  • Know how to recover.
    • Logseq provides a revision history, but my problem has been more that it refused to accept edits I made in Emacs while Logseq was offline, so those edits never enter the revision history to begin with. Not much use of a revision history then…
    • Automated Git commits (done by Emacs, not Logseq) can act as a nice safety net. I have them anyway because it makes sense for org-roam notes, and it just takes a small initfile snippet to set up: raw.githubusercontent.com/meedstrom/doom.d/master/71-auto-commit.el
    • Note that the above snippet of mine amends all commits made within the same day, so your edits can be still forgotten if you don't realize Logseq rolled-back your files before you go on to make more edits.

      For me not a problem because auto-revert-mode + goggles-mode show clearly that Logseq rolled back my changes, and then the first thing I'll do is type C-/ to undo (if the buffer was already open) or open up Magit and type k for "discard".

      Anyway, enable the builtin Emacs backup system for safety. On that note, have you seen backup-walker?

In case of export to HTML

If you ever want to export a Logseq-formatted document, Logseq has its own exporter you can use for the one-off use cases.

But if like me, you're doing a pipeline of publishing your entire org-roam directory to a blog, you'll probably choose to stick with the Org exporter. What I do is tag the Logseq-ified files with the file-level tag :logseq:, I give such pages an extra CSS class (raw.githubusercontent.com/meedstrom/doom.d/master/61-publishing.el), so I can write custom CSS rules for them.

Document title problems

Problems:

  1. Logseq works fine without any #+TITLE property, but org-roam needs it.
    • A workaround can be to avoid file-level titles and IDs, and only use subtrees and subtree IDs. Both programs can parse such files just fine.
  2. When you create a page inside Logseq, there won't be a #+TITLE or file-level ID — nor can you control the resulting filename format if that matters to you.

Solution: Just don't make a habit of creating pages in Logseq. When you do, fix the file with Emacs later.

More problems:

  1. When you rename a page in Logseq, it will change the filename. It will not change the #+TITLE property!
    • (The darnedest thing is that it'll add a meaningless :title: property inside the file-level property drawer, which must be a bug because org-mode generally doesn't do anything with this property. Probably an oversight by a mainly-Markdown dev. May be the same issue behind the phantom blank line mentioned earlier.)
  2. Renaming in Logseq also changes the filename, which you may not want.

Solution: don't ever rename pages through the UI, do it by tapping on the property drawer at the top of the page to reveal the #+TITLE and editing that. Yes, you'll have to instruct your partner to do this, or you can just fix all the renames later.

More problems:

  1. When you link a page in Logseq by typing square brackets … the on-disk result isn't an org-id id: link.

Newlines

There are two keys that can create a newline, with different effects (just like you have RET, M-RET, M-S-RET in org-mode). On the desktop Logseq app, they're Return and Shift+Return. The first is context-aware and very happy to create new subtrees, so as an org-roam writer you probably want to just avoid Return.

Before you ding the devs for this oddness, these keys are actually in line with convention for modern UI, in a way. Think of what you do in a chat app: if you want to send your chat message, you press Return. If you just want to make a newline without sending, you press Shift+Return. It's the same here.

However, on mobile it's the inverse. Chat apps have a dedicated Send button, so the onscreen keyboard's return key just prints a newline. In Logseq Mobile, it's instead the onscreen keyboard's return key that has magic behavior. The equivalent to polite old Shift+Return is present as a button just above the screen keyboard.

Plain checkbox lists

How to insert checkboxes in the app?

First, there's a long-unfixed bug (github.com/logseq/logseq/issues/3147). You'll have more success writing list bullets as + instead of the more conventional -.

+ [ ] i am a list item

Second, you have to type the first list-item manually, but after that, just enter newlines to autocreate more items.

Third, there are no indent/outdent commands for lists (only for subtrees). To make a sub-list, you have to manually prepend two spaces, but after that, you can once again enter newlines to autocreate new items at the correct indentation.

(It's telling that this is still better UX than any other Org app I've tried…)

Fourth, you'll sometimes see list items not being rendered as such. This isn't necessarily a bug, it can be that you tried to write a list item as the first text of a subtree… meaning you actually wrote a heading that happens to start with a dash character! Think logically about the underlying Org file.

Slash-commands

For someone who only uses the mobile app (and not desktop Logseq), this feature is so non-discoverable I'm impressed. In short, you should know there's a bunch of commands you can call by typing a slash character (/) anywhere (yes, on mobile too), and some others by typing an opening angle bracket (<). You can even add new commands in config.edn. Do with that info what you will.

Logseq keeps re-creating mysterious files called "Favorites", "Contents" and "Card"

As far as I can tell, there's no way to stop this. Maybe by adding to config.edn this line?

:hidden ["/page/contents.org" "/page/favorites.org"]

Anyway, you can just cope with this by using them. They're magic files;

  • what goes in contents.org also appears in the right-hand sidebar, and far as I can tell, it's meant as a sort of master index like Wikipedia's List of lists of lists;
  • what goes in favorites.org appears in the left-hand sidebar as a favorites section.

AHHH too many empty journal files!

Don't worry, these pages are imaginary. They don't exist as disk files until you write something in them.

The odd thing is that you enter the journal every time the app starts up, even if the journal is disabled…!

So it's not enough to put in config.edn this line:

:feature/enable-journals? false

You'll also want to set a homepage so it won't open the journals. Like this:

:default-home {:page "Contents"}

Other gotchas good to know

While org-id can accept any string as the ID, Logseq requires you to follow the UUID format. It's a bug they're working on.

More bugs

  1. It creates a page named "date" backlinking to all my files that have a #+date:. Might be intentional?
  2. When I import a big Org file called Someday/Maybe, logseq creates a lot of empty pages named e.g. Maybe, and home, home/kept, home/kept/roam etc (these are fragments of my directory tree). Maybe files just mustn't have slashes in the title?
  3. (Logseq Sync) It's hard to delete files from multiple devices, they keep popping back if one device still has the file. Worse, changes sometimes get undone. It could be an issue of differing system clocks?

    I suspect many issues would go away if Logseq simply read from the filesystem every time, but it seems to work with a cached image of what it thinks is on the filesystem (much like org-roam has its DB, which is also sometimes out of sync, but it only uses it for lookups when you're about to insert a link so causes no real problem). As of [2023-04-11 Tue] it seems I essentially have to tap "Re-index" for good measure every time I enter the app, although even then, some changes get reverted.

Summary cheatsheet

Some necessary config.edn lines

:preferred-format "Org"
:preferred-workflow :todo

Some optional config.edn lines, if you like the journal

:journal/page-title-format "yyyy-MM-dd"

or, to disable journals…

:feature/enable-journals? false
:default-home {:page "Contents"}

Usage

  1. Type newlines via Shift+Return, i.e. use that button above the touchscreen keyboard
  2. Type lists with the plus sign
  3. Stick with the regular org-id UUID format

If collaborating, instruct your partner:

  1. to ensure the sync completes before they edit
  2. to rename by editing #+TITLE manually

Conclusion

For all the little problems we have with Logseq, they're good problems to have. I'm glad this app exists. Thanks devs!

What links here

  • 2023-04-08
Created (2 years ago)
Updated (10 months ago)
Showing 393 to 396