I completely refactored SearchLink and now I should probably stop
A couple more SearchLink updates before I take a little break from mad coding on it. As of this writing the current release version is SearchLink v2.3.36.
I’ve done some major refactoring, added some new searches, and I wrote a full test suite that revealed some bugs that needed fixing.
Read on for an overview of the latest stuff.
First — and this won’t affect you much but I’m pretty happy with it — I refactored the entire script as a Gem that actually works. You can download the repository and run
rake package to build the gem, which can then be installed with
gem install pkg/searchlink-X.X.X.gem and will provide you with a working
searchlink executable that takes raw input on STDIN (piped in with
echo XXX | searchlink) or accepts filenames as arguments. This won’t matter to most people in the least, but it’s great for my testing (I also wrote a complete test suite that’s easily updated). Now that the code is broken up into logical pieces, it’s much, much easier to maintain. I have a build script (run with
howzit -r prepare deploy) that compiles the whole thing to a single Ruby script to use in the SearchLink Services, copies it to my clipboard, and opens the SearchLink Services in Automator for updating their scripts. It’s a Very Good System™.
Second, I refactored all of the various searches into a plugin architecture. SearchLink used to have separate, very long methods for determining whether a search was valid with a bunch of regexes, then another very long case statement for handling the various searches based on the
Now, every search is in its own class file and defines its own triggers and available searches, and I can add and remove searches very easily. Determining which plugin to run takes four lines of code, and the help/docs can be easily generated. It also opens the door for allowing custom plugins, so you can add your own searches that are more complex than the Custom Searches you can define in the configuration. It just takes a little Ruby, and there are enough examples that even non-Ruby programmers should be able to hack their way through creating a plugin.
By the way, SearchLink now has a redesigned distribution method, tagging releases on GitHub and uploading a zip with codesigned Services to each release. This means that the URL for getting the latest version is always
https://github.com/ttscoff/searchlink/releases/latest/download/SearchLink.zip, which makes keeping everything pointing to the latest version much simpler. And of course, it’s all automated with Howzit. Another Very Good System™.
While most of the recent work has gone into refactoring the code, I did add a few new things. A bunch actually, but here are the highlights:
First, I improved the help output. If you run SearchLink on just the word “help”, it will open a web page showing all available searches, with descriptions, including any custom searches and plugins you’ve defined. It has a quick filter for narrowing down the available options.
You can now run SearchLink on just the word “version” (or just “ver”) and get the version number for your installed copy. In the process, it will check for newer versions and alert you if there’s an update available. This check also runs once a day automatically (it only runs when you use SearchLink, no background processes or anything), and will notify you of updates in the HTML-commented report when running any search.
You can also run on the word “wiki” or “docs” to open the documentation in your default browser. Just a handy shortcut.
You can create GitHub links with
!gh. If you give it just a valid username, it will turn
!gh ttscoff into
[ttscoff](https://github.com/ttscoff "ttscoff (Brett Terpstra)"). If you add a repo to that, you can turn
!gh ttscoff searchlink into
[ttscoff searchlink](https://github.com/ttscoff/searchlink "ttscoff/searchlink"). You can also specifically search Gists using
!gist, and create Gist embeds automatically with
!giste. You can pass
!giste a full Gist URL, a user and Gist ID, or just a Gist ID and let it figure the rest out. If your search terms don’t match any of those, a site-specific search will be run for the best match.
You can search and link to the selected answer for a StackOverflow question with
!soa. Given the breadth of StackOverflow, your search needs to be pretty precise if you’re expecting to find a very specific question, but it’s handy for creating a quick link.
I also added Spotlight searching for local files using
!file. Provide it any Spotlight query and it will give you back a url-encoded
file:// link for the best match. This works well for linking DEVONthink documents or things you can’t find using
!hook. Speaking of, I also updated the
!hook command with a few fixes and better searching (words can now be in any order and still match).
You can also use Bit.ly to shorten any link with
!bl FULL_URL. If you give it search terms instead of a full URL, it will run the DuckDuckGo search and shorten the resulting link. Any SearchLink search that ends with
!! outputs URL only, so you can use it as a quick inline link shortener by running something like
!bl https://brettterpstra.com!! and get just
I love the History/Bookmark searches (
!h) (I even made you a video about it), but they needed some improvements. I added better scoring for matching Safari and Chromium bookmarks (Edge, Chrome, Brave, Arc), and fixed the history and bookmarks search for Edge.
And just for fun I made an example plugin that searches song lyrics and provides a link to a Genius.com page for a song. If you install the plugin, you get
!lyrics, as well as
!lyricse which will actually extract the lyrics into a verbatim block for inclusion in a Markdown document. It’s silly, but made for a good example of a more complex search than you could create just using Custom Searches.
- Plist library version overriding SeachLink version constant
- Overly broad regex for matching
!z(zero-click) search types
- Don’t unencode URLs from DDG searches, leave spaces and other characters properly encoded
- When returning a file from Spotlight, url encode spaces so the link works in Markdown previews
- Remove Instant Answers check from
!def, use wordnik instead to put definition in title attribute
!hookreturning invalid search
- Social handle expansion fixes (
- Chromium bookmark search not returning most relevant result
- Path to Microsoft Edge history file
See the full changelog on GitHub. You can download the latest version of SearchLink below and find more info on the project page and the wiki.
Generate Markdown links from web searches without leaving your editor.
Updated 03/15/23. Changelog