mirror of
https://gitlab.com/EternalWanderer/voidcruiser.nl
synced 2024-11-28 20:03:50 +01:00
XMonad prompt article
This commit is contained in:
parent
d15425526a
commit
8ee89fe117
|
@ -16,6 +16,10 @@ standard XMonad Contrib modules (`XMonad.Prompt.Shell`, `XMonad.Prompt.Ssh` and
|
||||||
it came to my universal/external Qutebrowser bookmarks menu and
|
it came to my universal/external Qutebrowser bookmarks menu and
|
||||||
`yt-dlp`-and-`pipe-viewer` wrapper.
|
`yt-dlp`-and-`pipe-viewer` wrapper.
|
||||||
|
|
||||||
|
This tutorial of sorts with assume _some_ Haskell knowledge or not being afraid
|
||||||
|
of diving straight into how Haskell works. I'm not going into great detail on
|
||||||
|
how everything works here.
|
||||||
|
|
||||||
# Bookmarks menu
|
# Bookmarks menu
|
||||||
|
|
||||||
The first one I decided to tackle was the bookmarks menu, as it is by far the
|
The first one I decided to tackle was the bookmarks menu, as it is by far the
|
||||||
|
@ -129,17 +133,15 @@ Lets see if there is anything in the
|
||||||
module that looks like it could help us in creating a prompt.
|
module that looks like it could help us in creating a prompt.
|
||||||
|
|
||||||
|
|
||||||
---
|
> ```haskell
|
||||||
```haskell
|
> mkXPrompt :: XPrompt p => p -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
|
||||||
mkXPrompt :: XPrompt p => p -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
|
> ```
|
||||||
```
|
> ---
|
||||||
Creates a prompt given:
|
> Creates a prompt given:
|
||||||
- a prompt type, instance of the `XPrompt` class.
|
> - a prompt type, instance of the `XPrompt` class.
|
||||||
- a prompt configuration (`def` can be used as a starting point)
|
> - a prompt configuration (`def` can be used as a starting point)
|
||||||
- a completion function (`mkComplFunFromList` can be used to create a completions function given a list of possible completions)
|
> - a completion function (`mkComplFunFromList` can be used to create a completions function given a list of possible completions)
|
||||||
- an action to be run: the action must take a string and return `X ()`
|
> - an action to be run: the action must take a string and return `X ()`
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
This looks like it could serve as the basis for our prompt. The description and
|
This looks like it could serve as the basis for our prompt. The description and
|
||||||
type signature tell us that it is going to require an instance of the `XPrompt`
|
type signature tell us that it is going to require an instance of the `XPrompt`
|
||||||
|
@ -170,25 +172,128 @@ Now for the completion function, that will handle the list given to our prompt.
|
||||||
Lets mostly follow the suggestion in the description of `mkXPrompt` and lets
|
Lets mostly follow the suggestion in the description of `mkXPrompt` and lets
|
||||||
take a look at:
|
take a look at:
|
||||||
|
|
||||||
---
|
> ```haskell
|
||||||
```haskell
|
> mkComplFunFromList' :: XPConfig -> [String] -> String -> IO [String]
|
||||||
mkComplFunFromList' :: XPConfig -> [String] -> String -> IO [String]
|
> ```
|
||||||
```
|
> ---
|
||||||
This function takes a list of possible completions and returns a completions
|
> This function takes a list of possible completions and returns a completions
|
||||||
function to be used with mkXPrompt. If the string is null it will return all
|
> function to be used with mkXPrompt. If the string is null it will return all
|
||||||
completions.
|
> completions.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
This is how Qutebrowser and `dmenu` act by default with a given list of possible
|
This is how Qutebrowser and `dmenu` act by default with a given list of possible
|
||||||
options.
|
options.
|
||||||
|
|
||||||
So it takes an instance of `XPConfig` -- that will be our `c` argument, and a
|
```haskell
|
||||||
list of strings. Here is where we feed it the contents of our file using our
|
bookmarksFile = ".config/qutebrowser/bookmarks/urls" :: String
|
||||||
`fileContentList` function.
|
```
|
||||||
|
> I didn't know where to put this, but I created a string to hold the path to my
|
||||||
|
> bookmarks
|
||||||
|
|
||||||
|
So it takes an instance of `XPConfig` -- that will again be our `c` argument,
|
||||||
|
and a list of strings. Here is where we feed it the contents of our file using
|
||||||
|
our `fileContentList` function. We will do this by binding the output to, say
|
||||||
|
`bl` for "bookmark list" with `<-`. Since `fileContentList` is a member of the
|
||||||
|
`IO` monad and we're working in, we have to call it using the `io` function,
|
||||||
|
which is an alias for the `liftIO` function.
|
||||||
|
|
||||||
```haskell
|
```haskell
|
||||||
bookmarkPrompt c = do
|
bookmarkPrompt :: XPConfig -> (String -> X ()) -> X ()
|
||||||
bl <- io fileContentList
|
bookmarkPrompt c f = do
|
||||||
mkXPrompt Bookmark c (mkComplFunFromList' c bl)
|
bl <- io fileContentList bookmarksFile
|
||||||
|
mkXPrompt Bookmark c (mkComplFunFromList' c bl) f
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see that I've also added argument `f`, this is the function we're going
|
||||||
|
to use to actually do something with our prompt output. Considering we're
|
||||||
|
working with bookmarks, opening them in a browser would make sense.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
openBookmark :: String -> X ()
|
||||||
|
openBookmark bookmark = do
|
||||||
|
browser <- io getBrowser
|
||||||
|
spawn $ browser ++ " '" ++ getUrl bookmark ++ "'"
|
||||||
|
where getUrl = head . words
|
||||||
|
```
|
||||||
|
`openBookmark` is a function that takes a string and returns something in the
|
||||||
|
context of the `X` monad (hence the name "XMonad", it's a monad that interacts
|
||||||
|
with Xorg). Lets go through it line by line.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
browser <- io getBrowser
|
||||||
|
```
|
||||||
|
First we get user's browser using the `getBrowser` function from the
|
||||||
|
`XMonad.Prompt.Shell` module and bind that to `browser`.
|
||||||
|
|
||||||
|
This function checks the `$BROWSER` environment variable and if it isn't set, it
|
||||||
|
defaults to "firefox".
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
spawn $ browser ++ " '" ++ getUrl bookmark ++ "'"
|
||||||
|
```
|
||||||
|
Since `getBrowser` returns a string, we can append things to it and feed that to
|
||||||
|
`spawn`. In this case, we get the URL portion of the bookmark entry surrounded by
|
||||||
|
single quotes in case a given bookmark contains any symbols that mess up our
|
||||||
|
shell. After all, what `spawn` ultimately does is feed a given string to
|
||||||
|
`/bin/sh` as a command to execute.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
where getUrl = head . words
|
||||||
|
```
|
||||||
|
For get `getUrl`, we take the given string, split it into a list of strings
|
||||||
|
based on space characters, pipe that into head, thus retrieving the first item.
|
||||||
|
|
||||||
|
## Keybinding
|
||||||
|
|
||||||
|
We now have a set of functions that create a prompt populated with our
|
||||||
|
Qutebrowser bookmarks file (any other list of URLs will also work) which will
|
||||||
|
open our browser when choosing one.
|
||||||
|
|
||||||
|
Now all we have to do is bind it to a key. Personally I use the
|
||||||
|
`XMonad.Util.EZConfig` so I have the following in my keybindings:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
, ("M-M1-C-b", bookmarkPrompt (myXPConfig {autoComplete = Just 200000}) openBookmark Bookmark)
|
||||||
|
```
|
||||||
|
If you use the default way of defining keybindings you can use something like
|
||||||
|
the following:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
, ((modm .|. controlMask, xK_b), bookmarkPrompt def openBookmark)
|
||||||
|
|
||||||
|
```
|
||||||
|
`def` is a reference to the default implementation of `XPConfig`.
|
||||||
|
|
||||||
|
# Everything Together
|
||||||
|
|
||||||
|
Everything put together, your config should have something like the following
|
||||||
|
added.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
data Bookmark = Bookmark
|
||||||
|
|
||||||
|
instance XPrompt Bookmark where
|
||||||
|
showXPrompt Bookmark = "Bookmark: "
|
||||||
|
|
||||||
|
bookmarksFile = ".config/qutebrowser/bookmarks/urls" :: String
|
||||||
|
|
||||||
|
fileContentList :: FilePath -> IO [String]
|
||||||
|
fileContentList f = do
|
||||||
|
homeDir <- getEnv "HOME"
|
||||||
|
file <- readFile (homeDir ++ "/" ++ f)
|
||||||
|
return . uniqSort . lines $ file
|
||||||
|
|
||||||
|
bookmarkPrompt :: XPConfig -> (String -> X ()) -> X ()
|
||||||
|
bookmarkPrompt c f = do
|
||||||
|
bl <- io fileContentList bookmarksFile
|
||||||
|
mkXPrompt Bookmark c (mkComplFunFromList' c bl) f
|
||||||
|
|
||||||
|
openBookmark :: String -> X ()
|
||||||
|
openBookmark bookmark = do
|
||||||
|
browser <- io getBrowser
|
||||||
|
spawn $ browser ++ " '" ++ getUrl bookmark ++ "'"
|
||||||
|
where getUrl = head . words
|
||||||
|
|
||||||
|
-- ... keybindings
|
||||||
|
, ((modm .|. controlMask, xK_b), bookmarkPrompt def openBookmark)
|
||||||
|
-- more keybindings ...
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in a new issue