packages feed

uacpid (empty) → 0.0.2

raw patch · 18 files changed

+859/−0 lines, 18 filesdep +basedep +containersdep +directorysetup-changed

Dependencies added: base, containers, directory, filepath, hslogger, mtl, network, old-locale, process, regex-compat, time, unix

Files

+ LICENSE view
@@ -0,0 +1,31 @@+Copyright Dino Morelli 2009++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Dino Morelli nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ README view
@@ -0,0 +1,22 @@+Getting started developing:++In order for the conf file code to work correctly in a development setting, what you should do is:++   $ runhaskell Setup.hs configure --prefix=foo++Where foo is some scratch development installation dir, doesn't really matter where.++You must then runhaskell Setup.hs install to copy files there. After which, running will be able to locate default conf which will then allow it to bootstrap the "real" configuration.+++Running the daemon in a development setting:++Start this daemon with the helper script in bin/uacpid-dev+This will use a custom HOME environment that points to dev/home/+And will keep it from looking at your real $HOME/.uacpid/++Start in developement like this:+   $ bin/uacpid-dev &++Stop in developement like this, use the full path so only the development execution is killed. Or get the pid and use kill:+   $ killall dist/build/uacpid/uacpid
+ Setup.hs view
@@ -0,0 +1,44 @@+#! /usr/bin/env runhaskell++-- Copyright: 2009 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++import Distribution.Simple+import Distribution.Simple.LocalBuildInfo+import System.Cmd+import System.Directory+import System.Exit+import System.FilePath+++main = defaultMainWithHooks (simpleUserHooks +   { postInst = customPostInstall+   } )+   where+      customPostInstall _ _ _ localBuildInfo = do+         -- Construct src and dest dirs for copying the man page+         let manFile = "uacpid.1"+         let srcPath = "resources" </> "man" </> manFile++         {- There's a "right way" to get the absolute mandir FilePath +            from the Cabal API, but I can't figure it out yet.+            Have to revisit someday.+         -}+         let prefixDir = fromPathTemplate $ prefix+               $ installDirTemplates localBuildInfo+         let destDir =+               prefixDir </> "share" </> "man" </> "man1"++         createDirectoryIfMissing True destDir++         let destPath = destDir </> manFile++         -- Copy it to the appropriate man directory, based on the+         -- prefix+         copyFile srcPath destPath++         -- gzip the man page+         gzipExitCode <- system $ "gzip -f " ++ destPath++         exitWith gzipExitCode
+ TODO view
@@ -0,0 +1,7 @@+- Can some of the code in main.hs be factored into other modules? Maybe Uacpid.Signals to start with++- If the event handler script's shell process fails, we need to log the exit code. WARNING priority. The real question here is do we have any business waiting for the shell process to come back? Maybe just report on failure to launch?++- Need to be careful about when acpid is stopped and the socket goes away on a running uacpid. Must deal with this gracefully.++- If acpid has run but is not now running, the socket file in /var/run/ can still be there. What happens then is that the connection is refused and you get no message in the uacpid log. You do get a message to stderr, but this is likely to be missed when running from .xinitrc  Need to fix this soon.
+ bin/uacpid-dev view
@@ -0,0 +1,3 @@+#! /bin/bash++HOME=dev/home dist/build/uacpid/uacpid $*
+ doc/dev/events/noaction view
@@ -0,0 +1,1 @@+event=.*
+ doc/dev/events/noevent view
@@ -0,0 +1,1 @@+action=logger "uacpid event handler: anything"
+ resources/man/uacpid.1 view
@@ -0,0 +1,80 @@+.\" Process this file with+.\" groff -man -Tascii uacpid.1+.\"+.TH UACPID 1 "2009-Jul-15" Linux "User Manuals"+.SH NAME+uacpid \- Userspace Advanced Configuration and Power Interface event daemon+.SH SYNOPSIS+.B uacpid+.SH DESCRIPTION+.B uacpid+is a daemon designed to be run in userspace that will monitor the local system's+.B acpid+socket for hardware events. These events can then be acted upon by handlers with access to the user's environment.++An example of why you need this: Suppose you want to have a hardware event change the active X displays, like a laptop external monitor function button. Some tools to achieve this display change require the logged in user's DISPLAY and other settings that may be difficult or impossible to gain access to from+.B acpid+scripts.++Another example is media control function buttons, like play/pause or next/previous track for a music player.++.B uacpid+is running as you and is getting the hardware events reported by the system's+.BR acpid .+.B uacpid+can then act on the events on your behalf, with your environment.++.B uacpid+will respond to SIGHUP by reloading the event handlers and reestablishing its connection to the+.B acpid+socket. Changes to the config file will require that+.B uacpid+be restarted, it will not reload the config on SIGHUP.++Note that+.B uacpid+requires+.BR acpid ". It must be installed and running."+.SH FILES+A directory structure and default files under+.I $HOME/.uacpid/+will be created the first time the daemon is run. These default files are documented with comments to explain their use.++.I $HOME/.uacpid/uacpid.conf+.RS+Configuration file+.RE++.IR $HOME/.uacpid/events/ [ event-handler "] ..."+.RS+Event handler files. These are very much like acpid event handler files. An example event handler that matches any event should be here, named+.I anything++You can have any number of these files named anything you like.+.B uacpid+will load them all and execute the corresponding actions when the event regexps match. These event handler files are how you make uacpid do things for you.+.SH EXIT STATUS+.TP+.B 0+Normal daemon termination, no error conditions.+.TP+.B 1+Fatal error, terminated abnormally.+.SH ENVIRONMENT+.IP HOME+The HOME environment variable is used to locate or initialize conf and event files (see FILES)+.SH DIAGNOSTICS+Error messages and anything else applicable to the log level in effect will be logged. By default the log file will be created at+.IR $HOME/var/log/uacpid.log .+These settings are also configurable.+.SH BUGS+Probably lots. Please email reports and/or help out!+.SH EXAMPLE+A logical way to start the daemon would be backgrounded in your+.IR $HOME/.xinitrc " or " $HOME/.xsession :++.B uacpid &+.SH AUTHOR+Dino Morelli <dino@ui3.info>+.SH "SEE ALSO"+.BR acpid (8)
+ resources/uacpid/events/anything view
@@ -0,0 +1,13 @@+# event is a regexp used for matching the raw string that we get from acpid+# These strings look like:+#   button/lid LID 00000080 00000002+#   button/sleep SLPB 00000080 00000001+#   hotkey ATKD 00000062 00000000+# See acpid for more info+event=.*++# action is a shell command that will be executed if the above event +# regexp pattern is a match+# This example using logger will log to local syslog-ng+# (just as an example)+action=logger "uacpid event handler: anything"
+ resources/uacpid/uacpid.conf view
@@ -0,0 +1,20 @@+# uacpid configuration file++# Path to write the log file (uacpid.log), relative to $HOME+logPath=var/log/uacpid.log++# Log priority. This determines what goes into the log.+# Possible values:+#   DEBUG    used only for development of this software+#   INFO     use to debug your event scripts, raw acpid data will be+#              output when this log level is in effect+#   NOTICE   normal status info, wordier than WARNING, but a good +#              default+#   WARNING  notice of problems only, a good sparse default priority+#   ERROR    bad things, hopefully you'll never see these+logPriority=WARNING++# Path to the acpid UNIX domain socket+# This is how uacpid gets hardware event data, from the acpid daemon+# Don't change this unless you know what you're doing+acpidSocket=/var/run/acpid.socket
+ src/Uacpid/Conf.hs view
@@ -0,0 +1,110 @@+-- Copyright: 2009 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++module Uacpid.Conf+   ( ConfMap+   , getConf+   , getConfDir+   , parseToMap+   )+   where++import Control.Monad+import Data.Map hiding ( map )+import Data.Maybe+import Prelude hiding ( lookup )+import System.Directory+import System.Environment+import System.FilePath+import Text.Regex ( matchRegex, mkRegex )++import Paths_uacpid+++type ConfMap = Map String String+++{- |+   Parse config file data into a simple (Map String String).++   For example, this:++   >  --- file start ---+   >  foo=one+   >  # a comment+   >+   >  bar+   >  baz-blorp=2+   >  --- file end ---++   becomes:++   >  fromList [("foo","one"),("bar",""),("baz-blorp","2")]++   Comments (prefixed with #) and blank lines in the config file +   are discarded.+-}+parseToMap :: String -> ConfMap+parseToMap entireConf =+   fromList $ map (\[k, v] -> (k, v))+      $ catMaybes $ map (matchRegex re) $ lines entireConf+   where+      re = mkRegex "^([^#][^=]*)=?(.*)"+++getHomeDir :: IO String+getHomeDir = getEnv "HOME"+++getConfDir :: IO String+getConfDir = liftM (flip (</>) ".uacpid") getHomeDir+++{- Create the user's home dir .uacpid directory and populate it+   with default and example files.+   This happens the first time uacpid is run for a given user+-}+initializeConfDir :: FilePath -> FilePath -> IO ()+initializeConfDir confDir confFilePath = do+   createDirectoryIfMissing True confDir++   defaultConfFilePath <- getDataFileName $+      "uacpid" </> "uacpid.conf"+   copyFile defaultConfFilePath confFilePath++   let eventsDir = confDir </> "events"+   createDirectory eventsDir++   let exampleAnything = "anything"+   exampleEventPath <- getDataFileName $+      "uacpid" </> "events" </> exampleAnything+   copyFile exampleEventPath $ eventsDir </> exampleAnything+++getConf :: IO ConfMap+getConf = do+   -- Construct some paths using $HOME+   homeDir <- getHomeDir+   confDir <- getConfDir+   let confFilePath = confDir </> "uacpid.conf"++   flip unless+      (initializeConfDir confDir confFilePath)+      =<< doesDirectoryExist confDir++   -- Load the conf+   loadedConf <- liftM parseToMap $ readFile confFilePath++   -- Replace the log path with an absolute one using $HOME+   let realConf = insertWith (</>) "logPath" homeDir loadedConf++   -- While we're here doing first time things, make sure there's+   -- an events dir+   createDirectoryIfMissing True $ confDir </> "events"++   -- First time log directory creation+   let logDir = dropFileName $ fromJust $ lookup "logPath" realConf+   createDirectoryIfMissing True logDir++   return realConf
+ src/Uacpid/Control/Monad/Error.hs view
@@ -0,0 +1,49 @@+-- Copyright: 2009 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++{- |+   Convenience function for turning (Maybe a) values into +   (MonadError e a) actions plus functions for expressing Data.Map +   lookups as MonadError actions+-}+module Uacpid.Control.Monad.Error+   ( maybeThrow+   , lookupEWith, lookupEString+   )+   where++import Control.Monad.Error+import Data.Map hiding ( map )+import Prelude hiding ( lookup )+++{- |+   Turn an error value and a (Maybe a) into a (MonadError e a) action+-}+maybeThrow :: (MonadError e m) => e -> Maybe a -> m a+maybeThrow err mval = maybe (throwError err) return mval+++{- |+   Look up a String key in a Map as an action in (MonadError e), +   providing a function to transform key type k to error type e.++   See lookupEString below for a usage example.+-}+lookupEWith :: (MonadError e m, Ord k) =>+               (k -> e) -> k -> Map k a -> m a+lookupEWith f k m = maybeThrow (f k) $ lookup k m+++{- |+   Look up a String key in a Map as an action in (MonadError String), +   with a default message that the key was not found as the+   error.+-}+lookupEString :: (MonadError String m) =>+                 String -> Map String a -> m a+lookupEString =+   lookupEWith (\j -> "Key " ++ j ++ " not found")
+ src/Uacpid/Events.hs view
@@ -0,0 +1,95 @@+-- Copyright: 2009 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++module Uacpid.Events+   ( Handler (..), loadHandlers, executeHandlers )+   where++import Control.Monad.Error+import Data.List+import Data.Maybe+import System.Directory+import System.FilePath+import System.Log+import System.Process+import Text.Regex ( matchRegex, mkRegex )++import Uacpid.Conf ( ConfMap, getConfDir, parseToMap )+import Uacpid.Control.Monad.Error+import Uacpid.Log ( logM )+++data Handler = Handler+   { evName :: String+   , evEventRe :: String+   , evAction :: String+   }+++lookupHandlerE :: (MonadError String m) =>+   String -> String -> ConfMap -> m String+lookupHandlerE name = lookupEWith+   (\j -> "Handler " ++ name ++ ": key " ++ j ++ " not found")+++loadHandler :: (String, FilePath) -> IO (Maybe Handler)+loadHandler (name, path) = do+   -- Parse the event file into a map+   evMap <- liftM parseToMap $ readFile path++   -- Extract data from it to make an Handler, with error reporting+   eitherStringHandler <- runErrorT $ do+      event <- lookupHandlerE name "event" evMap+      action <- lookupHandlerE name "action" evMap+      return $ Handler name event action++   result <- case eitherStringHandler of+      Left emsg -> do+         logM WARNING emsg+         return Nothing+      Right ev -> return $ Just ev++   return result+++loadHandlers :: IO [Handler]+loadHandlers = do+   confDir <- getConfDir+   let eventsDir = confDir </> "events"++   {- Load the event handler files. Files starting with . and ending +      with ~ are discarded. We don't want . and .. of course, but you +      can also disable one by make it look like events/.foo or +      events/foo~+   -}+   eventFiles <- liftM +      ( filter (\file -> not $ any ($ file)+         [ isPrefixOf ".", isSuffixOf "~" ]))+      $ getDirectoryContents eventsDir++   -- Construct a list of (filename, /path/to/filename)+   let eventPairs = map (\n -> (n, eventsDir </> n)) eventFiles++   -- Load these files and parse them+   events <- liftM catMaybes $ mapM loadHandler eventPairs++   let names = map evName events++   -- Log what we loaded for informational purposes+   if (null names)+      then logM NOTICE "No valid event handlers were found"+      else logM NOTICE $ "Handlers loaded: " +++         (intercalate " " names)++   return events+++executeHandlers :: String -> [Handler] -> IO ()+executeHandlers acpiHandler es = do+   let responders = filter (\e -> isJust $+         matchRegex (mkRegex (evEventRe e)) acpiHandler) es++   mapM_ (runCommand . evAction) responders
+ src/Uacpid/Log.hs view
@@ -0,0 +1,62 @@+-- Copyright: 2009 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++module Uacpid.Log+   ( initLogging, logM, logTest )+   where++import Control.Monad ( liftM )+import Data.Map ( lookup )+import Data.Maybe+import Data.Time.Clock ( getCurrentTime )+import Data.Time.Format ( formatTime )+import Data.Time.LocalTime ( utcToLocalZonedTime )+import Prelude hiding ( lookup )+import System.Locale ( defaultTimeLocale )+import System.Log.Handler.Simple ( fileHandler )+import qualified System.Log.Logger as L ( logM )+import           System.Log.Logger hiding ( logM )+import Text.Printf++import Uacpid.Conf+++-- Format the time right now given a formatting string+formattedDate :: String -> IO String+formattedDate formatString =+   liftM (formatTime defaultTimeLocale formatString)+      $ getCurrentTime >>= utcToLocalZonedTime+++{- Log a message to the root logger with timestamp and priority+   included+-}+logM :: Priority -> String -> IO ()+logM pri msg = do+   fd <- formattedDate "%Y-%m-%d %H:%M:%S %Z"+   let fullMsg = printf "%s %7s> %s" fd (show pri) msg+   L.logM rootLoggerName pri fullMsg+++{- Default hslogger behavior sends logging to stderr. In this case,+   we want it to go to stdout.+-}+initLogging :: ConfMap -> IO ()+initLogging conf = do+   let logPath = fromJust $ lookup "logPath" conf+   let level = read $ fromJust $ lookup "logPriority" conf+   logHandler <- fileHandler logPath level+   updateGlobalLogger rootLoggerName (setHandlers [logHandler])+   updateGlobalLogger rootLoggerName (setLevel level)+++{- Test function to generate every kind of log message we use+-}+logTest :: IO ()+logTest = do+   logM DEBUG "log test message 1 of 5"+   logM INFO "log test message 2 of 5"+   logM NOTICE "log test message 3 of 5"+   logM WARNING "log test message 4 of 5"+   logM ERROR "log test message 5 of 5"
+ src/main.hs view
@@ -0,0 +1,173 @@+-- Copyright: 2009 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++import Control.Concurrent+import Control.Concurrent.MVar+import Control.Monad.Error+import Data.Map hiding ( null )+import Data.Maybe+import Prelude hiding ( lookup )+import Network.Socket+import System.Directory+import System.Environment+import System.Exit+import System.IO+import System.Log+import System.Posix.Signals hiding ( Handler )++import Uacpid.Conf+import Uacpid.Control.Monad.Error+import Uacpid.Events+import Uacpid.Log ( initLogging, logM )+++data RunLevel = HALT | RUN | RESTART+   deriving Eq+++openAcpidSocket :: (MonadError String m, MonadIO m) =>+   ConfMap -> m Handle+openAcpidSocket conf = do+   liftIO $ logM NOTICE "Establishing connection to acpid's socket..."++   acpidSocketPath <- lookupEString "acpidSocket" conf++   exists <- liftIO $ doesFileExist acpidSocketPath+   unless exists $+      throwError $ "Socket " ++ acpidSocketPath ++ " does not exist. Make sure acpid is installed, is running, and that this path is correct. This config setting is in ~/.uacpid/uacpid.conf under the key acpidSocket"++   hdl <- liftIO $ do+      -- Open the UNIX domain socket+      s <- socket AF_UNIX Stream defaultProtocol+      connect s $ SockAddrUnix acpidSocketPath++      -- Turn it into an ordinary handle+      h <- socketToHandle s ReadMode+      hSetBuffering h LineBuffering++      return h++   liftIO $ logM NOTICE "Connected."++   return hdl+++{- When RunLevel is RESTART, this function sets up the daemon by +   loading event handlers and establishing the connection to acpid, +   sets the RunLevel to RUN and then starts the listenAcpi loop.+   Any other RunLevel makes it exit.+-}+connectLoop :: ConfMap -> MVar RunLevel -> IO ()+connectLoop conf mvRunStatus = do+   logM DEBUG "connectLoop called"++   runStatus <- readMVar mvRunStatus++   when (runStatus == RESTART) $ do+      handlers <- loadHandlers++      eHdl <- runErrorT $ openAcpidSocket conf+      either exitFail+         (\hdl -> do+            takeMVar mvRunStatus+            putMVar mvRunStatus RUN+            listenAcpi handlers mvRunStatus hdl+         )+         eHdl+      connectLoop conf mvRunStatus+++{- Read lines from the socket and do something with them+   This function keeps calling itself as long as we're in RunLevel RUN+   Otherwise it falls back to connectLoop who takes the appropriate +   action+-}+listenAcpi :: [Handler] -> MVar RunLevel -> Handle -> IO ()+listenAcpi handlers mvRunStatus hdl = do+   logM DEBUG "listenAcpi called"++   runStatus <- readMVar mvRunStatus++   when (runStatus == RUN) $ do+      -- No blocking unless the socket is ready with a line for us+      ready <- hReady hdl+      when ready $ do+         line <- hGetLine hdl+         logM INFO $ "Received from acpid: " ++ line+         executeHandlers line handlers++      -- Wait a bit, try again+      threadDelay 250000+      listenAcpi handlers mvRunStatus hdl+++{- For a serious error that prevents further execution+-}+exitFail :: String -> IO ()+exitFail errMsg = do+   logM ERROR errMsg+   exitWith $ ExitFailure 1+++{- Handler functions to adjust the RunLevel state based on signals +   the daemon may receive+-}++handleExitSignals :: MVar RunLevel -> IO ()+handleExitSignals mvRunStatus = do+   takeMVar mvRunStatus++   logM NOTICE "uacpid daemon stopped"++   putMVar mvRunStatus HALT+++handleHupSignal :: MVar RunLevel -> IO ()+handleHupSignal mvRunStatus = do+   takeMVar mvRunStatus++   logM NOTICE "sigHUP received"++   putMVar mvRunStatus RESTART+++main :: IO ()+main = do+   -- Any args at all, give the user help and exit+   getArgs >>= \as -> unless (null as) usageAndExit++   conf <- getConf+   initLogging conf++   mvRunStatus <- newMVar RESTART++   -- Install signal handlers+   mapM_ (\signal -> installHandler signal +      (Catch $ handleExitSignals mvRunStatus) Nothing) [sigINT, sigTERM]+   installHandler sigHUP (Catch $ handleHupSignal mvRunStatus) Nothing++   logM NOTICE "uacpid daemon started"+   logM NOTICE $ "Logging level " +++      (fromJust $ lookup "logPriority" conf)++   -- The looping for events starts here+   connectLoop conf mvRunStatus++   -- If/when it makes it back here, exit gracefully+   exitWith ExitSuccess+++usageAndExit :: IO ()+usageAndExit = do+   putStrLn $ unlines+      [ "uacpid - Userspace Advanced Configuration and Power Interface event daemon"+      , ""+      , "Please see man uacpid for detailed info"+      , ""+      , "Version 0.0.2  2009-Jul-15  Dino Morelli <dino@ui3.info>"+      ]++   exitWith ExitSuccess
+ uacpid.cabal view
@@ -0,0 +1,30 @@+name:                uacpid+version:             0.0.2+cabal-version:       >= 1.2+build-type:          Simple+license:             BSD3+license-file:        LICENSE+copyright:           2009 Dino Morelli+author:              Dino Morelli+maintainer:          Dino Morelli <dino@ui3.info>+stability:           experimental+homepage:            http://ui3.info/d/proj/uacpid.html+synopsis:            Userspace Advanced Configuration and Power Interface +                     event daemon+description:         uacpid is a daemon designed to be run in userspace +                     that will monitor the local system's acpid socket +                     for hardware events. These events can then be acted +                     upon by handlers with access to the user's+                     environment.+category:            System+tested-with:         GHC>=6.10.3+data-dir:            resources+data-files:          uacpid/uacpid.conf, uacpid/events/anything++executable           uacpid+   main-is:          main.hs+   hs-source-dirs:   src+   build-depends:    base >= 3 && < 5, containers, directory, filepath, +                     hslogger, mtl, network, old-locale, process, +                     regex-compat, time, unix+   ghc-options:      -Wall
+ util/gentags.sh view
@@ -0,0 +1,3 @@+#! /bin/sh++find src -regex '.*\..?hs' | xargs hasktags -c
+ util/prefs/boring view
@@ -0,0 +1,115 @@+# Boring file regexps:++### compiler and interpreter intermediate files+# haskell (ghc) interfaces+\.hi$+\.hi-boot$+\.o-boot$+# object files+\.o$+\.o\.cmd$+# profiling haskell+\.p_hi$+\.p_o$+# haskell program coverage resp. profiling info+\.tix$+\.prof$+# fortran module files+\.mod$+# linux kernel+\.ko\.cmd$+\.mod\.c$+(^|/)\.tmp_versions($|/)+# *.ko files aren't boring by default because they might+# be Korean translations rather than kernel modules+# \.ko$+# python, emacs, java byte code+\.py[co]$+\.elc$+\.class$+# objects and libraries; lo and la are libtool things+\.(obj|a|exe|so|lo|la)$+# compiled zsh configuration files+\.zwc$+# Common LISP output files for CLISP and CMUCL+\.(fas|fasl|sparcf|x86f)$++### build and packaging systems+# cabal intermediates+\.installed-pkg-config+\.setup-config+# standard cabal build dir, might not be boring for everybody+# ^dist(/|$)+# autotools+(^|/)autom4te\.cache($|/)+(^|/)config\.(log|status)$+# microsoft web expression, visual studio metadata directories+\_vti_cnf$+\_vti_pvt$+# gentoo tools+\.revdep-rebuild.*+# generated dependencies+^\.depend$++### version control systems+# cvs+(^|/)CVS($|/)+\.cvsignore$+# cvs, emacs locks+^\.#+# rcs+(^|/)RCS($|/)+,v$+# subversion+(^|/)\.svn($|/)+# mercurial+(^|/)\.hg($|/)+# git+(^|/)\.git($|/)+# bzr+\.bzr$+# sccs+(^|/)SCCS($|/)+# darcs+(^|/)_darcs($|/)+(^|/)\.darcsrepo($|/)+^\.darcs-temp-mail$+-darcs-backup[[:digit:]]+$+# gnu arch+(^|/)(\+|,)+(^|/)vssver\.scc$+\.swp$+(^|/)MT($|/)+(^|/)\{arch\}($|/)+(^|/).arch-ids($|/)+# bitkeeper+(^|/)BitKeeper($|/)+(^|/)ChangeSet($|/)++### miscellaneous+# backup files+~$+\.bak$+\.BAK$+# patch originals and rejects+\.orig$+\.rej$+# X server+\..serverauth.*+# image spam+\#+(^|/)Thumbs\.db$+# vi, emacs tags+(^|/)(tags|TAGS)$+#(^|/)\.[^/]+# core dumps+(^|/|\.)core$+# partial broken files (KIO copy operations)+\.part$+# waf files, see http://code.google.com/p/waf/+(^|/)\.waf-[[:digit:].]+-[[:digit:]]+($|/)+(^|/)\.lock-wscript$+# mac os finder+(^|/)\.DS_Store$+# cabal+(^|/)dist($|/)