Scripting Razor Runner - Razor-qt/razor-qt GitHub Wiki
Razor runner scripting
Note: This is feature is expected to be in Razor-qt 0.6.0, once it is released. Until then you can try i out by getting Razor from git
What is this?
Razor-runner is Razor-Qt''s application launcher. Out of the box, it will match what you type against installed desktop-applications, and show what it finds in a list, from where you can choose.
It is possible to extend what razor-runner suggest with scripts. Here we describe how.
How it works
A razor-runner script should read search-terms from standard input (line by line) - and write suggestions to standard out.
Here''s an example script. With this script added to razor-runner, razor-runner will suggest folders below your home directory. If you click one of the suggestions, the folder will open in you default file manager.
#!/usr/bin/env bash
cd $HOME
while read searchterm; do
echo "---"
if [ ${#searchterm} -ge 3 ](/Razor-qt/razor-qt/wiki/-${#searchterm}--ge-3-); then
find $HOME -maxdepth 3 -type d -iname "*${searchterm}*" | while read pathtodir; do
dirname=`basename "$pathtodir"`
echo "- icon : folder"
echo " title : $dirname"
echo " comment: $pathtodir"
echo " tooltip : Open '$pathtodir' in filemanager"
echo " command : xdg-open \"$pathtodir\""
done;
fi
echo "..."
done
The script reads input, line by line, and searches from $HOME and 3 levels down for a folder with a matching name. For each folder it finds, it outputs data that can be used to form an item in razor-runner
If this script is run from the command line and given the input: 'razor-qt\n', it could output something like this:
---
- icon : folder
title : backup-2013-04-28-razor-qt
comment: /home/christian/projekter/backup-2013-04-28-razor-qt
tooltip : Open '/home/christian/projekter/backup-2013-04-28-razor-qt' in filemanager
command : xdg-open "/home/christian/projekter/backup-2013-04-28-razor-qt"
- icon : folder
title : backup-razor-qt
comment: /home/christian/projekter/backup-razor-qt
tooltip : Open '/home/christian/projekter/backup-razor-qt' in filemanager
command : xdg-open "/home/christian/projekter/backup-razor-qt"
- icon : folder
title : razor-qt
comment: /home/christian/projekter/razor-qt
tooltip : Open '/home/christian/projekter/razor-qt' in filemanager
command : xdg-open "/home/christian/projekter/razor-qt"
- icon : folder
title : razor-qt-backup-2013-04-22
comment: /home/christian/projekter/razor-qt-backup-2013-04-22
tooltip : Open '/home/christian/projekter/razor-qt-backup-2013-04-22' in filemanager
command : xdg-open "/home/christian/projekter/razor-qt-backup-2013-04-22"
- icon : folder
title : razor-qt-sided
comment: /home/christian/projekter/razor-qt-sided
tooltip : Open '/home/christian/projekter/razor-qt-sided' in filemanager
command : xdg-open "/home/christian/projekter/razor-qt-sided"
- icon : folder
title : razor-qt-gem
comment: /home/christian/projekter/razor-qt-gem
tooltip : Open '/home/christian/projekter/razor-qt-gem' in filemanager
command : xdg-open "/home/christian/projekter/razor-qt-gem"
...
Notes:
-
The output is a YAML document, and it contains a list of maps.
-
Each map will become a line (or an item) in razor-runners drop-down list.
-
Each map contains: 'icon', 'title', 'comment', 'tooltip' and 'command'. The meaning of those are:
- icon: The icon that is shown for the item in razor-runner's drop-down list. It can be an absolute path (i.e. /path/to/my/icon.png) or just an icon name, in which case it will be sought in the users icon-theme.
- title: The short description of the item
- comment: The long description of the item
- tooltip: Shown in a bubble when the user puts the mouse-cursor over the item
- command: The command that is executed if the item is selected (clicked).
Configuring scripts
To make razor-runner run a script, it has to be configured in razor-runner.conf. In our example, razor-runner.conf should contain a section like this:
[external-providers]
1\name=Folders
1\executable=/home/christian/projekter/RunnerPlugins/folders.sh
size=1
The section 'external-providers' contains an array - one element for each script. Here we have one script, hence the key 'size' has value 1. Element number 1 has name=Folders
which is used by razor-runner to reference the script. It has executable=/home/christian/projekter/RunnerPlugins/folders.sh
which is the full path to the script.
We do not (yet) have an gui-application to do this configuration, so razor-runner.conf will have to be edited by hand.
The contract
- Razor runner writes the search terms to the scripts standard-input. Every time the content of razor-runners search bar changes, the script will be fed a line containing the search term as it now looks.
So if the user types:
razor
in the input-field, the script will get these 5 lines in standard input:
r\n
ra\n
raz\n
razo\n
razor\n
-
The script must produce a YAML document containing one list, containing maps. Each map must be string to string and should contain the five keys: icon, * title, comment, tooltip and command. The meaning of these are as explained above. The keys title and command are mandatory. icon, comment and tooltip may be omitted.
-
The maps can contain other keys. They will be ignored. In the future the set of keys recognized by razor-runner may be extended.
-
When the script has produced a document, the items of that document stays in razor-runners dropdown list until the script produces a new document. To eraze all items previously produced, the script can send an empty document (see below).
-
The YAML document must start with the line
---
and end with the line
... -
If the script has no suggestions to offer, it signals this with an empty YAML document:
... \---
More examples
Below are 2 more examples of what you can do with razor-runner scripting. One in bash and one in ruby. Of course you can use any programming language you wish.
Search google
#!/usr/bin/env bash
# If searchterm starts with 'g:' produce an item
# that offers search for whats after 'g:'
# Example: 'g:razor qt' --> search google for 'razor qt'
while read line; do
echo "---"
if [ "g:" == ${line:0:2} && ${#line} -gt 2 ](/Razor-qt/razor-qt/wiki/-"g:"-==-${line:0:2}-&&-${#line}--gt-2-); then
escaped_line=`echo "${line:2}" | sed -e 's/\s\s*/%20/g'`
echo "- title: $line"
echo " comment: Search google for '${line:2}'"
echo " tooltip: Search google for '${line:2}'"
echo " command: xdg-open http://www.google.com/search?q=${escaped_line}"
echo " icon: /home/christian/projekter/RunnerPlugins/google.png"
fi
echo "..."
done
Search chromium history
#!/usr/bin/env ruby
# For this to work, sqlite3 must be installed (and chromium - obviously). It is assumed that
# chromium keeps it's history in $HOME/.config/chromium/Default/History
# Oh, and you'll need ruby :-)
STDOUT.sync = true
require 'sqlite3'
require 'fileutils'
require 'yaml'
require 'set'
class HistorySearcher
def establish_db_connection
puts "Connecting..."
@history_db.close if @history_db
# This sucks. Chromium keeps a lock on it's history database while running, and I've not been
# able to figure out a way to read it while that lock is on, so we have to make a full copy.
dbfile = File.join(ENV['HOME'], '.config/chromium/Default/History')
dbfilecopy = File.join(ENV['HOME'], '.cache/razor_runner_chromium_history_copy');
FileUtils.copy(dbfile, dbfilecopy)
@history_db = SQLite3::Database.new(dbfilecopy)
@connection_time = Time.new
end
# Returns a list of items. If called with razor-qt, it could be something like:
#
# [{ 'title' => 'razor-qt.org/',
# 'comment' => 'Razor-qt',
# 'icon' => 'text-html',
# 'tooltip' => 'open "http://razor-qt.org/" in browser',
# 'command' => 'xdg-open "http://razor-qt.org/' },
# { 'title' => 'razor-qt.org/install/',
# 'comment' => 'Razor-qt: Download',
# 'icon' => 'text-html',
# 'tooltip' => "open 'http://razor-qt.org/install/' in browser",
# 'command' => "xdg-open 'http://razor-qt.org/install'" },
# .
# .
# .
# ]
def searchForTerm(term)
listOfItems = []
if term.length >= 3
# We look for urls in history containing term, ordering
# so that shortest urls are preferred (putting very long urls that contain
# lots of query parameters behind)
query = <<-EndOfSelect
SELECT DISTINCT title, url
FROM urls
WHERE url LIKE 'http://#{term}%'
OR url LIKE 'https://#{term}%'
OR url LIKE 'http://www.#{term}%'
OR url LIKE 'https://www.#{term}%'
ORDER BY length(url)
LIMIT 5
EndOfSelect
@history_db.execute(query).map do |title, url|
puts url + "-->" + title.dump
listOfItems <<
{
'title' => url.gsub(/^https?:\/\/(www.)?/, ""), # Strip leading http(s)://(www.)
'comment' => title.gsub(/\n/, " "),
'icon' => 'text-html',
'tooltip' => "open '#{url}' in browser",
'command' => "xdg-open \"#{url}\""
}
end
end
return listOfItems
end
def main
@connection_time = Time.new - 700;
while term = gets do
establish_db_connection if (Time.new - @connection_time) > 600 # Get a new copy of history-db every 10 minutes...
# Ok with a db-copy in place and an open connection we're ready to consume input.
term = term.downcase.gsub(/\n$/, "")
STDOUT.print(YAML::dump(searchForTerm(term)))
# Ruby YAML does not end documents with '...', but razor-runner needs that
# as a syncronizing token, so we add it.
STDOUT.print("...\n")
end
end
end
HistorySearcher.new.main