Skip to content

Feature: More flexible handling of URLs #302

@lervag

Description

@lervag

This feature request is a result of the discussion in #296 and work on this should probably wait for #301 to be addressed.

wiki.vim has a relatively robust implementation of links as a concept. The idea is to parse various types of links and to enrich the parsed result with some methods that are used by the "public" APIs and mappings/commands. The parsed result will find a URL, then we figure out the proper URL scheme, then the link.follow function will use the handler from the corresponding autoload/wiki/url/SCHEME.vim file.

This works well in the sense that it is easy to add new scheme handlers as a developer. But the user flexibility is not very large. There are some options, like g:wiki_resolver and g:wiki_file_handler that are used by the wiki scheme and the file scheme, respectively.

It seems it could be a better idea to generalize the concept and provide an option that allows full flexibility for users to define their own handlers. For that purpose, it is useful to divide the relevant actions in two:

  • A resolver function that takes the original URL and parses it.
  • A handler function that takes the output of the resolver and acts on it; e.g. open the target in a new window in Vim or in an external viewer.

By splitting these, we make it easier to apply customizations on only parts of the "flow"; e.g. a user could adjust how a link is opened, another user could change how the URL should be parsed.

The configuration option could look something like this:

*g:wiki_link_schemes*
  A dictionary to configure resolvers and handlers URL schemes. The keys
  represent the schemes and the values are dictionaries that configure
  the behaviour for the specified scheme through two concepts:

    resolver ~
      A function that parses the original URL (a string argument). If no such
      function is defined, then the handler will receive the original URL
      directly.

    handler ~
      A function that takes the result(s) of the `resolver` function and acts
      on it.

  Notice that the `resolver` and `handler` needs to "fit". If the `resolver`
  returns a string, then the `handler` must take a string as an argument.

  Both `resolver` and `handler` must be of type |Funcref|.

  Default: >vim

    let g:wiki_link_schemes = {
          \ 'wiki': {
          \   'resolver': function('wiki#link#resolver#wiki'),
          \   'handler': function('wiki#link#handler#wiki'),
          \ },
          \ 'file': {
          \   'resolver': '',
          \   'handler': function('wiki#link#handler#file'),
          \ },
          \ …
          \}

I believe this would bring a lot of value to users in form of customization. It would also mean that it would be trivial to implement support for new schemes, as it would be enough to add them to this new option.

Implementing this is a relatively large job. All the current handlers and resolvers would need to be changed; I would propose moving them to autoload/wiki/link/{resolver,handler}.vim and to make all of them "pure" functions. And, of course, we would need to adjust how the link objects are created and move the .follow() methods back to the link object; something like this:

function s:link.follow() abort dict
  let l:resolved_url = self.resolver(self.url)
  call self.handler(l:resolved_url)
endfunction

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions