summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2017-12-28 05:03:26 +0300
committerdefanor <defanor@uberspace.net>2017-12-28 06:39:17 +0300
commitb11b05385b5615aaf08bd245af53e8df03a193b3 (patch)
tree99304984295784f70f8f4c3e3cbc8488bf16e0a6
parentc27c14e866dfb4a3c6c85393ffd0522933c67651 (diff)
Install and enable a few uncluttering XSLTs by default
-rw-r--r--Pancake/Configuration.hs8
-rw-r--r--Pancake/Unclutter.hs13
-rw-r--r--README74
-rw-r--r--Setup.hs28
-rw-r--r--pancake.cabal1
-rw-r--r--unclutter/duckduckgo.xsl24
-rw-r--r--unclutter/github.xsl77
-rw-r--r--unclutter/hacker-news.xsl33
-rw-r--r--unclutter/lobsters.xsl20
-rw-r--r--unclutter/mediawiki.xsl26
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
diff --git a/README b/README
index 76e58d6..662e9e9 100644
--- a/README
+++ b/README
@@ -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
-----------
diff --git a/Setup.hs b/Setup.hs
index 1a01025..0015f6c 100644
--- a/Setup.hs
+++ b/Setup.hs
@@ -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>&#xa;</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>