neovim telescope markdown link handler

(Inspired by Luke Smith.)

I’m playing around with Neovim, Telescope, and Fennel, and just finished creating a first version of a markdown link handler.

It allows you to fuzzy search for a link in a markdown file, and open it with whatever application (“linkhandler”) you specify. If you don’t specify a linkhandler, it will default to x-www-browser, or to open on macOS.

Prerequisites:

Benefits:

Need to be fixed:

usage (Neovim commands)

:lua require('my.module').telescope_markdown_url_opener({})

open a youtube url in ~/some-file.md with mpv

:lua require('my.module').telescope_markdown_url_opener(
  {
    urls_file='~/some-file.md',
    linkhandler='mpv'
  }
)

code

(module my.module
  {require {telescope telescope}})

(defn split-string [inputstr sep]
  ;; split-string source: https://stackoverflow.com/a/7615129
  (do
    (when (= sep nil) (set-forcibly! sep "%s"))
    (local t [])
    (each [str (string.gmatch inputstr (.. "([^" sep "]+)"))]
      (table.insert t str))
    t))

(defn get-file-lines [path-to-file]
  (-> (vim.fn.system (.. "cat " path-to-file))
      (split-string "\n")))

(defn match-single-line-markdown-url [line]
  ;; NOTE: this will only match single line "[...](...)" patterns
  (string.match line "(%b[])(%b())"))

(defn get-single-line-markdown-urls-from-file [path-to-file]
    (local name-url-pairs [])
    (each [k line (ipairs (get-file-lines path-to-file))]
      (when (not (= nil (match-single-line-markdown-url line)))
        (table.insert name-url-pairs line)))
    name-url-pairs)

(defn create-markdown-url-opener [opts]
  (fn [prompt-bufnr]
    (let [actions       (require "telescope.actions")
          utils         (require "telescope.utils")
          action-state  (require "telescope.actions.state")
          selection     (action-state.get_selected_entry)
          linkhandler   (. opts  "linkhandler")
          is-mac-os?    (fn [] (= "Darwin\n" (vim.fn.system "uname -s")))
          open-function (if linkhandler linkhandler
                            (is-mac-os?) "open"
                            true "x-www-browser")]
      (actions.close prompt-bufnr)
      (local (_ ret stderr)
        (utils.get_os_command_output [open-function selection.value]))
      (if (= ret 0)
          (print (.. "Opened with '"
                     open-function
                     "': "
                     selection.value))
          (print (string.format
                   "Could not open  %s  -   \"%s\""
                   selection.value
                   (table.concat stderr "  ")))))))

(defn markdown-url-entry-maker []
  (let [entry-display (require "telescope.pickers.entry_display")
        displayer     (entry-display.create {:items [{:width 40}
                                                     {:remaining true}]
                                             :separator " "})]
    (fn make-display [entry]
      (displayer [[entry.value "TelescopeResultsIdentifier"]
                  entry.msg]))
    (fn [entry]
      (when (= entry "")
        (lua "return nil"))
      (var (name-with-brackets url-with-parentheses)
        (match-single-line-markdown-url entry))
      (var name
        (string.sub name-with-brackets 2 -2))
      (var url
        (string.sub url-with-parentheses 2 -2))
      {:display make-display
       :msg name
       :ordinal (.. name " " url) ; TODO: find out what this is/does
       :value url})))

(defn telescope_markdown_url_opener [options]
   (let [opts      (or options {})
         urls-file (or options.urls_file "~/my-markdown-links.md")
         pickers   (require "telescope.pickers")
         actions   (require "telescope.actions")
         finders   (require "telescope.finders")
         conf      (. (require "telescope.config") "values")
         results   (get-single-line-markdown-urls-from-file urls-file)]
     (: (pickers.new
          opts
          {:attach_mappings (fn []
                                (: actions.select_default
                                   "replace"
                                   (create-markdown-url-opener opts))
                                ;; return true = add default Telescope mappings.
                                true)
           :finder (finders.new_table
                     {:entry_maker (or opts.entry_maker
                                       (markdown-url-entry-maker opts))
                      :results results})
           :previewer nil
           :prompt_title (.. "< select markdown url in " urls-file ">")
           :sorter (conf.file_sorter opts)}) "find")))

{;; This block is the return value of this module.
 :telescope_markdown_url_opener telescope_markdown_url_opener}

willfennel.com

Legal notes: