diff options
author | defanor <defanor@uberspace.net> | 2017-12-28 05:03:26 +0300 |
---|---|---|
committer | defanor <defanor@uberspace.net> | 2017-12-28 06:39:17 +0300 |
commit | b11b05385b5615aaf08bd245af53e8df03a193b3 (patch) | |
tree | 99304984295784f70f8f4c3e3cbc8488bf16e0a6 | |
parent | c27c14e866dfb4a3c6c85393ffd0522933c67651 (diff) |
Install and enable a few uncluttering XSLTs by default
-rw-r--r-- | Pancake/Configuration.hs | 8 | ||||
-rw-r--r-- | Pancake/Unclutter.hs | 13 | ||||
-rw-r--r-- | README | 74 | ||||
-rw-r--r-- | Setup.hs | 28 | ||||
-rw-r--r-- | pancake.cabal | 1 | ||||
-rw-r--r-- | unclutter/duckduckgo.xsl | 24 | ||||
-rw-r--r-- | unclutter/github.xsl | 77 | ||||
-rw-r--r-- | unclutter/hacker-news.xsl | 33 | ||||
-rw-r--r-- | unclutter/lobsters.xsl | 20 | ||||
-rw-r--r-- | unclutter/mediawiki.xsl | 26 |
10 files changed, 221 insertions, 83 deletions
diff --git a/Pancake/Configuration.hs b/Pancake/Configuration.hs index bfac392..c01ad96 100644 --- a/Pancake/Configuration.hs +++ b/Pancake/Configuration.hs @@ -109,7 +109,13 @@ instance Default Config where , historyDepth = 100 , referenceDigits = "0123456789" , indentDivs = False - , unclutter = M.empty + , unclutter = M.fromList + [ ("duckduckgo", "^https://duckduckgo\\.com/lite/\\?q=") + , ("lobsters", "^https://lobste\\.rs/((page|recent|newest).*)?$") + , ("hacker-news", + "^https://news\\.ycombinator\\.com/((news|show|ask).*)?$") + , ("mediawiki", "^https://en\\.(m.)?(wiktionary|wikipedia)\\.org/wiki/") + , ("github", "^https://github\\.com/")] } where curl = "curl --compressed -4 -L " ++ diff --git a/Pancake/Unclutter.hs b/Pancake/Unclutter.hs index cf5132e..2169e00 100644 --- a/Pancake/Unclutter.hs +++ b/Pancake/Unclutter.hs @@ -47,12 +47,13 @@ import Data.Text.Encoding (decodeUtf8', decodeLatin1, encodeUtf8) import qualified Data.Text as T import Control.Exception - import Pancake.Common import Pancake.Configuration +import Paths_pancake -- | Tries to unclutter a document by applying an XSLT if it's --- available. +-- available. Looks for a file in a user config directory first, and +-- in the system data directory then. tryUnclutter :: MonadIO m => [(Regex, String)] -- ^ Obtained with 'prepareUnclutter'. @@ -67,8 +68,12 @@ tryUnclutter rs u d = liftIO $ handle err $ do _ -> False case find matches rs of Just (_, fn) -> do - dir <- getXdgDirectory XdgConfig "pancake" - let src = dir </> "unclutter" </> fn <.> "xsl" + src <- do + configDir <- getXdgDirectory XdgConfig "pancake" + let src = configDir </> "unclutter" </> fn <.> "xsl" + exists <- doesFileExist src + dataDir <- getDataDir + pure $ if exists then src else dataDir </> "unclutter" </> fn <.> "xsl" exists <- doesFileExist src if exists then do @@ -85,78 +85,18 @@ emacs documentation (``C-h m``) for those. Configuration ------------- -Default configuration will be written into XDG configuration -directory, and would look approximately like this (slightly -simplified):: - - externalViewers: - png: xdg-open "${FILE}" - hs: emacsclient -n "${FILE}" - indentDivs: false - commands: - gopher: torify curl "${URI}" - ssh: scp "${URI_REGNAME}:${URI_PATH}" /dev/stdout - unclutter: - duckduckgo: ^https://duckduckgo\.com/lite/\?q= - defaultCommand: ! 'curl --compressed -4 -L -w " - - -pancake- - - uri: %{url_effective} - - type: %{content_type} - - " "${URI}"' - referenceDigits: 'rstwfpxcvaqzdgb' - shortcuts: - g: https://m.gutenberg.org/ebooks/search.mobile/?query= - ddg: https://duckduckgo.com/lite/?q= - wt: https://en.m.wiktionary.org/w/index.php?search= - wa: web-archive:///?url= - wp: https://en.m.wikipedia.org/wiki/Special:Search?search= - gp: gopher://gopherpedia.com:70/7/lookup? - vs: gopher://gopher.floodgap.com/7/v2/vs? - xiph: http://dir.xiph.org/search?search= - historyDepth: 100 - paginate: true +Default configuration will be written into XDG configuration directory +on ``pancake`` invocation if it's missing. Uncluttering ~~~~~~~~~~~~ -XSLT can be used to extract useful data from HTML documents. In the -above sample configuration, ``duckduckgo`` is defined along with an -URI regex to determine when it should be applied, and the -corresponding XSLT file should be in -``~/.config/pancake/unclutter/duckduckgo.xsl``:: - - <?xml version="1.0" encoding="UTF-8"?> - <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> - <xsl:output method="html" indent="yes"/> - <xsl:template match="/"> - <html> - <body> - DuckDuckGo - <xsl:for-each select="//tr[not(@class) or @class!='result-sponsored']"> - <xsl:for-each select="td/a[@class='result-link']"> - <br /> - <br /> - <a href="{@href}"> - <xsl:value-of select="." /> - </a> - </xsl:for-each> - <xsl:for-each select="td[@class='result-snippet']"> - <br /> - <xsl:value-of select="." /> - </xsl:for-each> - </xsl:for-each> - </body> - </html> - </xsl:template> - </xsl:stylesheet> - -Uncluttering configurations for a few more websites can be found at -<https://github.com/defanor/dotfiles/tree/master/.config/pancake>. +XSLT can be used to extract useful data from HTML documents, and XSLTs +for a few websites are provided by default. They can be read from +``unclutter`` subdirectory in either pancake's XDG config directory +(for custom XSLTs), or a data directory (for predefined XSLTs). + Screenshots ----------- @@ -23,18 +23,24 @@ import Distribution.Simple.Setup import System.FilePath import System.Directory -main = defaultMainWithHooks simpleUserHooks { postCopy = installManPage } +main = defaultMainWithHooks simpleUserHooks { postCopy = installExtras } -- | Installs pancake.1. -installManPage :: Args - -> CopyFlags - -> PackageDescription - -> LocalBuildInfo - -> IO () -installManPage _ cf pd lbi = do +installExtras :: Args + -> CopyFlags + -> PackageDescription + -> LocalBuildInfo + -> IO () +installExtras _ cf pd lbi = do let dirs = absoluteInstallDirs pd lbi (fromFlag $ copyDest cf) - man1 = mandir dirs </> "man1" - fname = "pancake.1" - target = man1 </> fname + verbosity = fromFlag $ copyVerbosity cf + -- todo: use absoluteComponentInstallDirs once will switch to + -- cabal 2, e.g.: + -- absoluteComponentInstallDirs pd lbi (localUnitId lbi) + -- (fromFlag $ copyDest cf) + -- install man page + let man1 = mandir dirs </> "man1" + manFileName = "pancake.1" + manTarget = man1 </> manFileName createDirectoryIfMissing True man1 - installOrdinaryFile (fromFlag $ copyVerbosity cf) fname target + installOrdinaryFile verbosity manFileName manTarget diff --git a/pancake.cabal b/pancake.cabal index e5bb95f..06aa7fc 100644 --- a/pancake.cabal +++ b/pancake.cabal @@ -21,6 +21,7 @@ extra-source-files: ChangeLog.md , pancake.1 , Makefile , deb/DEBIAN/control +data-files: unclutter/*.xsl cabal-version: >=1.10 source-repository head type: git diff --git a/unclutter/duckduckgo.xsl b/unclutter/duckduckgo.xsl new file mode 100644 index 0000000..2bf6e2b --- /dev/null +++ b/unclutter/duckduckgo.xsl @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="html" indent="yes"/> + <xsl:template match="/"> + <html> + <body> + DuckDuckGo + <xsl:for-each select="//tr[not(@class) or @class!='result-sponsored']"> + <xsl:for-each select="td/a[@class='result-link']"> + <br /> + <br /> + <a href="{@href}"> + <xsl:value-of select="." /> + </a> + </xsl:for-each> + <xsl:for-each select="td[@class='result-snippet']"> + <br /> + <xsl:value-of select="." /> + </xsl:for-each> + </xsl:for-each> + </body> + </html> + </xsl:template> +</xsl:stylesheet> diff --git a/unclutter/github.xsl b/unclutter/github.xsl new file mode 100644 index 0000000..c4e42d4 --- /dev/null +++ b/unclutter/github.xsl @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="html" indent="yes"/> + + <xsl:template match="/"> + <html> + <body> + <xsl:apply-templates select="//div[@role='main']" /> + </body> + </html> + </xsl:template> + + <xsl:template match="nav[@role='navigation'] | ul[@class='numbers-summary'] | div[@class='repository-lang-stats']"> + <p> + <xsl:for-each select=".//a"> + <xsl:if test="position()>1"> + | + </xsl:if> + <a href="{@href}"> + <xsl:value-of select="." /> + </a> + </xsl:for-each> + </p> + </xsl:template> + + <!-- files --> + <xsl:template match="div[@class='file-wrap']"> + <div> + <xsl:for-each select=".//tr[position()>1]"> + <xsl:copy-of select="td[@class='content']//a" /> + (<xsl:copy-of select=".//time-ago" />) + <br/> + </xsl:for-each> + </div> + </xsl:template> + + <!-- code --> + <xsl:template match="table[@class='highlight tab-size js-file-line-container']"> + <pre> + <xsl:for-each select=".//td[@class='blob-code blob-code-inner js-file-line']"> + <xsl:value-of select="." /> + <xsl:text>
</xsl:text> + </xsl:for-each> + </pre> + </xsl:template> + + <!-- watch, star, fork --> + <xsl:template match="ul[@class='pagehead-actions']" /> + <!-- signup --> + <xsl:template match="div[@class='signup-prompt-bg rounded-1']" /> + <!-- languages, duplication --> + <xsl:template match="div[@class='repository-lang-stats-graph js-toggle-lang-stats']" /> + <!-- misc clutter --> + <xsl:template match="div[@class='js-socket-channel js-updatable-content']" /> + <xsl:template match="div[@class='mt-3 mb-2 text-center']" /> + <xsl:template match="div[@class='subnav']" /> + <!-- issue filters and such --> + <xsl:template match="div[@id='js-issues-toolbar']" /> + <!-- registration thing --> + <xsl:template match="div[@class='px-4']" /> + <!-- another "sign up for free" thing --> + <xsl:template match="div[@class='flash flash-warn mt-3']" /> + <!-- protips --> + <xsl:template match="div[@class='protip']" /> + <!-- branch selection, new PR, etc --> + <xsl:template match="div[@class='file-navigation in-mid-page']" /> + + + <!-- Catch-all: copy and apply templates --> + <xsl:template match="node()" priority="0"> + <xsl:copy> + <xsl:copy-of select="@*" /> + <xsl:apply-templates /> + </xsl:copy> + </xsl:template> + +</xsl:stylesheet> diff --git a/unclutter/hacker-news.xsl b/unclutter/hacker-news.xsl new file mode 100644 index 0000000..0f8c352 --- /dev/null +++ b/unclutter/hacker-news.xsl @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="html" indent="yes"/> + <xsl:template match="/"> + <html> + <body> + Hacker News + <xsl:for-each select="//td[@class='title' or @class='subtext']"> + <xsl:choose> + <xsl:when test="@class = 'title'"> + <xsl:variable name="uri" select="a/@href"/> + <xsl:if test="$uri!=''"> + <br /> + <br /> + <a href="{$uri}" > + <xsl:value-of select="a" /> + </a> + </xsl:if> + </xsl:when> + <xsl:when test="@class = 'subtext'"> + <br/> + <xsl:value-of select="span[@class='age']" /> + | + <a href="{a[last()]/@href}"> + <xsl:value-of select="a[last()]" /> + </a> + </xsl:when> + </xsl:choose> + </xsl:for-each> + </body> + </html> + </xsl:template> +</xsl:stylesheet> diff --git a/unclutter/lobsters.xsl b/unclutter/lobsters.xsl new file mode 100644 index 0000000..92b58a7 --- /dev/null +++ b/unclutter/lobsters.xsl @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="html" indent="yes"/> + <xsl:template match="/"> + <html> + <body> + Lobsters + <xsl:for-each select="//div[@class='details']"> + <p> + <xsl:copy-of select="span[@class='link']/a" /> + <br/> + <xsl:value-of select="div[@class='byline']/span[position()=1]" /> + | + <xsl:copy-of select="div[@class='byline']/span[@class='comments_label']/a" /> + </p> + </xsl:for-each> + </body> + </html> + </xsl:template> +</xsl:stylesheet> diff --git a/unclutter/mediawiki.xsl b/unclutter/mediawiki.xsl new file mode 100644 index 0000000..1b88b4a --- /dev/null +++ b/unclutter/mediawiki.xsl @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="html" indent="yes"/> + + <xsl:template match="/"> + <html> + <body> + <xsl:apply-templates select="//div[@id='content']" /> + </body> + </html> + </xsl:template> + + <!-- Cut these out --> + <xsl:template match="span[@class='mw-editsection']" /> + <xsl:template match="ul[@id='page-actions']" /> + <xsl:template match="div[@class='mw-ui-icon mw-ui-icon-element indicator']" /> + <xsl:template match="a[@class='mw-ui-icon mw-ui-icon-element mw-ui-icon-edit-enabled edit-page']" /> + + <!-- Catch-all: copy and apply templates --> + <xsl:template match="node()" priority="0"> + <xsl:copy> + <xsl:copy-of select="@*" /> + <xsl:apply-templates /> + </xsl:copy> + </xsl:template> +</xsl:stylesheet> |