XMonad.Actions.Search

xmonad-contrib-0.18.1: Community-maintained extensions for xmonad

Copyright | (C) 2007 Gwern Branwen
License | None; public domain
Maintainer | <gwern0@gmail.com>
Stability | unstable
Portability | unportable; depends on XSelection, XPrompt
Safe Haskell | None
Language | Haskell2010

XMonad.Actions.Search

Contents

- Usage
- Use case: searching with a submap
- Types

Description

A module for easily running Internet searches on web sites through xmonad. Modeled after the handy Surfraw CLI search tools at https://secure.wikimedia.org/wikipedia/en/wiki/Surfraw.

Additional sites welcomed.

Synopsis

- search :: Browser -> Site -> Query -> X ()
- data SearchEngine = SearchEngine Name Site
- searchEngine :: Name -> String -> SearchEngine
- searchEngineF :: Name -> Site -> SearchEngine
- promptSearch :: XPConfig -> SearchEngine -> X ()
- promptSearchBrowser :: XPConfig -> Browser -> SearchEngine -> X ()
- promptSearchBrowser' :: XPConfig -> Browser -> SearchEngine -> X ()
- selectSearch :: SearchEngine -> X ()
- selectSearchBrowser :: Browser -> SearchEngine -> X ()
- isPrefixOf :: Eq a => [a] -> [a] -> Bool
- escape :: String -> String
- use :: SearchEngine -> Site
- intelligent :: SearchEngine -> SearchEngine
- (!>) :: SearchEngine -> SearchEngine -> SearchEngine
- prefixAware :: SearchEngine -> SearchEngine
- namedEngine :: Name -> SearchEngine -> SearchEngine
- alpha :: SearchEngine
- amazon :: SearchEngine
- arXiv :: SearchEngine
- aur :: SearchEngine
- clojureDocs :: SearchEngine
- codesearch :: SearchEngine
- cratesIo :: SearchEngine
- deb :: SearchEngine
- debbts :: SearchEngine
- debpts :: SearchEngine
- dictionary :: SearchEngine
- duckduckgo :: SearchEngine
- ebay :: SearchEngine
- flora :: SearchEngine
- github :: SearchEngine
- google :: SearchEngine
- hackage :: SearchEngine
- homeManager :: SearchEngine
- hoogle :: SearchEngine
- images :: SearchEngine
- imdb :: SearchEngine
- lucky :: SearchEngine
- maps :: SearchEngine
- mathworld :: SearchEngine
- ncatlab :: SearchEngine
- nixos :: SearchEngine
- noogle :: SearchEngine
- openstreetmap :: SearchEngine
- protondb :: SearchEngine
- rosettacode :: SearchEngine
- rustStd :: SearchEngine
- scholar :: SearchEngine
- sourcehut :: SearchEngine
- stackage :: SearchEngine
- steam :: SearchEngine
- thesaurus :: SearchEngine
- vocabulary :: SearchEngine
- voidpgks_x86_64 :: SearchEngine
- voidpgks_x86_64_musl :: SearchEngine
- wayback :: SearchEngine
- wikipedia :: SearchEngine
- wiktionary :: SearchEngine
- youtube :: SearchEngine
- zbmath :: SearchEngine
- multi :: SearchEngine
- type Browser = FilePath
- type Site = String -> String
- type Query = String
- type Name = String
- data Search

# Usage

This module is intended to allow easy access to databases on the Internet through xmonad's interface. The idea is that one wants to run a search but the query string and the browser to use must come from somewhere. There are two places the query string can come from - the user can type it into a prompt which pops up, or the query could be available already in the X Windows copy/paste buffer (perhaps you just highlighted the string of interest).

Thus, there are two main functions: `promptSearch`, and `selectSearch` (implemented using the more primitive `search`). To each of these is passed an engine function; this is a function that knows how to search a particular site.

For example, the `google` function knows how to search Google, and so on. You pass `promptSearch` and `selectSearch` the engine you want, the browser you want, and anything special they might need; this whole line is then bound to a key of you choosing in your xmonad.hs. For specific examples, see each function. This module is easily extended to new sites by using `searchEngine`.

The currently available search engines are:

- `alpha` -- Wolfram|Alpha query.
- `amazon` -- Amazon keyword search.
- `arXiv` -- Open-access preprint archive.
- `aur` -- Arch User Repository.
- `clojureDocs` -- Documentation and examples repository for Clojure.
- `codesearch` -- Google Labs Code Search search.
- `cratesIo` -- Rust crate registry.
- `deb` -- Debian package search.
- `debbts` -- Debian Bug Tracking System.
- `debpts` -- Debian Package Tracking System.
- `dictionary` -- dictionary.reference.com search.
- `duckduckgo` -- DuckDuckGo search engine.
- `ebay` -- Ebay keyword search.
- `flora` -- Prettier Haskell package database.
- `github` -- GitHub keyword search.
- `google` -- basic Google search.
- `hackage` -- Hackage, the Haskell package database.
- `homeManager` -- Search Nix's home-manager's options.
- `hoogle` -- Hoogle, the Haskell libraries API search engine.
- `images` -- Google images.
- `imdb` -- the Internet Movie Database.
- `lucky` -- Google "I'm feeling lucky" search.
- `maps` -- Google maps.
- `mathworld` -- Wolfram MathWorld search.
- `ncatlab` -- Higer Algebra, Homotopy and Category Theory Wiki.
- `nixos` -- Search NixOS packages and options.
- `noogle` -- `hoogle`-like Nix API search engine.
- `openstreetmap` -- OpenStreetMap free wiki world map.
- `protondb` -- Steam Proton Game Database.
- `rosettacode` -- Programming chrestomathy wiki.
- `rustStd` -- Rust standard library documentation.
- `scholar` -- Google scholar academic search.
- `sourcehut` -- Sourcehut projects search.
- `stackage` -- Stackage, An alternative Haskell libraries API search engine.
- `steam` -- Steam games search.
- `thesaurus` -- thesaurus.com search.
- `vocabulary` -- Dictionary search.
- `voidpgks_x86_64` -- Void Linux packages search for `x86_64`.
- `voidpgks_x86_64_musl` -- Void Linux packages search for `x86_64-musl`.
- `wayback` -- the Wayback Machine.
- `wikipedia` -- basic Wikipedia search.
- `wiktionary` -- Wiktionary search.
- `youtube` -- Youtube video search.
- `zbmath` -- Open alternative to MathSciNet.
- `multi` -- Search based on the prefix. "amazon:Potter" will use amazon, etc. With no prefix searches google.

Feel free to add more!

search :: Browser -> Site -> Query -> X () #

Given a browser, a search engine's transformation function, and a search term, perform the requested search in the browser.

data SearchEngine #

Constructors

SearchEngine Name Site |

searchEngine :: Name -> String -> SearchEngine #

Given a base URL, create the `SearchEngine` that escapes the query and appends it to the base. You can easily define a new engine locally using exported functions without needing to modify XMonad.Actions.Search:

    myNewEngine = searchEngine "site" "https://site.com/search="

The important thing is that the site has a interface which accepts the escaped query string as part of the URL. Alas, the exact URL to feed searchEngine varies from site to site, often considerably, so there's no general way to cover this.

Generally, examining the resultant URL of a search will allow you to reverse-engineer it if you can't find the necessary URL already described in other projects such as Surfraw.

searchEngineF :: Name -> Site -> SearchEngine #

If your search engine is more complex than this (you may want to identify the kind of input and make the search URL dependent on the input or put the query inside of a URL instead of in the end) you can use the alternative `searchEngineF` function.

    searchFunc :: String -> String
    searchFunc s | "wiki:"    `isPrefixOf` s = "https://en.wikipedia.org/wiki/" ++ (escape $ drop 1 $ snd $ break (==':') s)
                 | "https://" `isPrefixOf` s = s
                 | otherwise                 = (use google) s
    myNewEngine = searchEngineF "mymulti" searchFunc

`searchFunc` here searches for a word in wikipedia if it has a prefix of "wiki:" (you can use the `escape` function to escape any forbidden characters), opens an address directly if it starts with "https://" and otherwise uses the provided google search engine. You can use other engines inside of your own through the `use` function as shown above to make complex searches.

The user input will be automatically escaped in search engines created with `searchEngine`, `searchEngineF`, however, completely depends on the transformation function passed to it.

promptSearch :: XPConfig -> SearchEngine -> X () #

Like `search`, but in this case, the string is not specified but grabbed from the user's response to a prompt. Example:

    , ((modm, xK_g), promptSearch greenXPConfig google)

This specializes "promptSearchBrowser" by supplying the browser argument as supplied by `getBrowser` from XMonad.Prompt.Shell.

promptSearchBrowser :: XPConfig -> Browser -> SearchEngine -> X () #

Like `search`, but for use with the output from a Prompt; it grabs the Prompt's result, passes it to a given searchEngine and opens it in a given browser.

promptSearchBrowser' :: XPConfig -> Browser -> SearchEngine -> X () #

Like `promptSearchBrowser`, but only suggest previous searches for the given `SearchEngine` in the prompt.

selectSearch :: SearchEngine -> X () #

Like `search`, but for use with the X selection; it grabs the selection, passes it to a given searchEngine and opens it in the default browser . Example:

    , ((modm .|. shiftMask, xK_g), selectSearch google)

This specializes "selectSearchBrowser" by supplying the browser argument as supplied by `getBrowser` from XMonad.Prompt.Shell.

selectSearchBrowser :: Browser -> SearchEngine -> X () #

Like `search`, but for use with the X selection; it grabs the selection, passes it to a given searchEngine and opens it in a given browser.

isPrefixOf :: Eq a => [a] -> [a] -> Bool #

\(\mathcal{O}(\min(m,n))\). The `isPrefixOf` function takes two lists and returns `True` iff the first list is a prefix of the second.

#### Examples

Expand

    >>> "Hello" `isPrefixOf` "Hello World!"
    True

    >>> "Hello" `isPrefixOf` "Wello Horld!"
    False

For the result to be `True`, the first list must be finite; `False`, however, results from any mismatch:

    >>> [0..] `isPrefixOf` [1..]
    False

    >>> [0..] `isPrefixOf` [0..99]
    False

    >>> [0..99] `isPrefixOf` [0..]
    True

    >>> [0..] `isPrefixOf` [0..]
    * Hangs forever *

`isPrefixOf` shortcuts when the first argument is empty:

    >>> isPrefixOf [] undefined
    True

escape :: String -> String #

Escape the search string so search engines understand it. Only digits and ASCII letters are not encoded. All non ASCII characters which are encoded as UTF8

use :: SearchEngine -> Site #

Given an already defined search engine, extracts its transformation function, making it easy to create compound search engines. For an instance you can use `use google` to get a function which makes the same transformation as the google search engine would.

intelligent :: SearchEngine -> SearchEngine #

This function wraps up a search engine and creates a new one, which works like the argument, but goes directly to a URL if one is given rather than searching.

    myIntelligentGoogleEngine = intelligent google

Now if you search for https://xmonad.org it will directly open in your browser

(!>) :: SearchEngine -> SearchEngine -> SearchEngine infixr 6 #

Connects a few search engines into one. If the search engines' names are "s1", "s2" and "s3", then the resulting engine will use s1 if the query is `s1:word`, s2 if you type `s2:word` and s3 in all other cases.

Example:

    multiEngine = intelligent (wikipedia !> mathworld !> (prefixAware google))

Now if you type "wiki:Haskell" it will search for "Haskell" in Wikipedia, "mathworld:integral" will search mathworld, and everything else will fall back to google. The use of intelligent will make sure that URLs are opened directly.

prefixAware :: SearchEngine -> SearchEngine #

Makes a search engine prefix-aware. Especially useful together with `!>`. It will automatically remove the prefix from a query so that you don't end up searching for google:xmonad if google is your fallback engine and you explicitly add the prefix.

namedEngine :: Name -> SearchEngine -> SearchEngine #

Changes search engine's name

alpha :: SearchEngine #

amazon :: SearchEngine #

arXiv :: SearchEngine #

aur :: SearchEngine #

clojureDocs :: SearchEngine #

codesearch :: SearchEngine #

cratesIo :: SearchEngine #

deb :: SearchEngine #

debbts :: SearchEngine #

debpts :: SearchEngine #

dictionary :: SearchEngine #

duckduckgo :: SearchEngine #

ebay :: SearchEngine #

flora :: SearchEngine #

github :: SearchEngine #

google :: SearchEngine #

hackage :: SearchEngine #

homeManager :: SearchEngine #

hoogle :: SearchEngine #

images :: SearchEngine #

imdb :: SearchEngine #

lucky :: SearchEngine #

maps :: SearchEngine #

mathworld :: SearchEngine #

ncatlab :: SearchEngine #

nixos :: SearchEngine #

noogle :: SearchEngine #

openstreetmap :: SearchEngine #

protondb :: SearchEngine #

rosettacode :: SearchEngine #

rustStd :: SearchEngine #

scholar :: SearchEngine #

sourcehut :: SearchEngine #

stackage :: SearchEngine #

steam :: SearchEngine #

thesaurus :: SearchEngine #

vocabulary :: SearchEngine #

voidpgks_x86_64 :: SearchEngine #

voidpgks_x86_64_musl :: SearchEngine #

wayback :: SearchEngine #

wikipedia :: SearchEngine #

wiktionary :: SearchEngine #

youtube :: SearchEngine #

zbmath :: SearchEngine #

multi :: SearchEngine #

# Use case: searching with a submap

In combination with XMonad.Actions.Submap you can create a powerful and easy way to search without adding a whole bunch of bindings.

First import the necessary modules:

    import qualified XMonad.Prompt         as P
    import qualified XMonad.Actions.Submap as SM
    import qualified XMonad.Actions.Search as S

Then add the following to your key bindings:

    ...
    -- Search commands
    , ((modm, xK_s), SM.submap $ searchEngineMap $ S.promptSearch P.def)
    , ((modm .|. shiftMask, xK_s), SM.submap $ searchEngineMap $ S.selectSearch)

    ...

    searchEngineMap method = M.fromList $
          [ ((0, xK_g), method S.google)
          , ((0, xK_h), method S.hoogle)
          , ((0, xK_w), method S.wikipedia)
          ]

Or in combination with XMonad.Util.EZConfig:

    ...
    ] -- end of regular keybindings
    -- Search commands
    ++ [("M-s " ++ k, S.promptSearch P.def f) | (k,f) <- searchList ]
    ++ [("M-S-s " ++ k, S.selectSearch f) | (k,f) <- searchList ]

    ...

    searchList :: [(String, S.SearchEngine)]
    searchList = [ ("g", S.google)
                 , ("h", S.hoogle)
                 , ("w", S.wikipedia)
                 ]

Make sure to set firefox to open new pages in a new window instead of in a new tab: `Firefox -> Edit -> Preferences -> Tabs -> New pages should be opened in...`

Now mod-s + g/h/w prompts you for a search string, then opens a new firefox window that performs the search on Google, Hoogle or Wikipedia respectively.

If you select something in whatever application and hit mod-shift-s + g/h/w it will search the selected string with the specified engine.

Happy searching!

# Types

type Browser = FilePath #

type Site = String -> String #

type Query = String #

type Name = String #

data Search #

A customized prompt indicating we are searching, and the name of the site.

#### Instances

Instances details

XPrompt Search # |
Instance details Defined in XMonad.Actions.Search Methods showXPrompt :: Search -> String # nextCompletion :: Search -> String -> [String] -> String # commandToComplete :: Search -> String -> String # completionToCommand :: Search -> String -> String # completionFunction :: Search -> ComplFunction # modeAction :: Search -> String -> String -> X () #