startupHook -- ambiguous type variable - xmonad

Stupid simple xmonad.hs question...
import XMonad
myTerminal = "gnome-terminal"
startupHook = do { spawn "/usr/bin/feh --bg-fill /home/abennett/wallpaper.jpg" }
main = xmonad defaults
defaults = defaultConfig {
terminal = myTerminal
}
Throws this error:
Error detected while loading xmonad configuration file: /home/abennett/.xmonad/xmonad.hs
xmonad.hs:4:20:
Ambiguous type variable `m0' in the constraint:
(MonadIO m0) arising from a use of `spawn'
Possible cause: the monomorphism restriction applied to the following:
Main.startupHook :: m0 () (bound at xmonad.hs:4:1)
Probable fix: give these definition(s) an explicit type signature
or use -XNoMonomorphismRestriction
In a stmt of a 'do' block:
spawn "/usr/bin/feh --bg-fill /home/abennett/wallpaper.jpg"
In the expression:
do { spawn "/usr/bin/feh --bg-fill /home/abennett/wallpaper.jpg" }
In an equation for `Main.startupHook':
Main.startupHook
= do { spawn
"/usr/bin/feh --bg-fill /home/abennett/wallpaper.jpg" }
Please check the file for errors
I've tried things like startupHook = startup and then startup = do { spawn "stuff" } but that doesn't work either.

You have to include the startupHook in your defaults. Either you specify it directly in defaults, or you create a variable and define your startupHook to be e.g. myStartupHook in defaults (just as you did with your terminal):
import XMonad
main = xmonad defaults
defaults = defaultConfig {
terminal = myTerminal,
startupHook = myStartupHook
}
myTerminal = "gnome-terminal"
myStartupHook = do
spawn "/usr/bin/feh --bg-fill /home/abennett/wallpaper.jpg"
-- and more stuff like
spawn myTerminal
spawn "xclock"
When you start using more workspaces, you might like to use spawnOn imported from XMonad.Actions.SpawnOn.
Please have a look at the xmonad config template, it will give you a better idea how to build your config file.

Related

Create a subshell under node that can be used like a normal shell

So, I want to do some setup and create an environment to run various commands using node. Doing in this in python or from a shell works simply (and maybe that's the best answer) but for various reasons using node has advantages. I've tried various permutations of spawn but everything is failing in different ways. This might be the closest I've gotten.
$ node
> const { spawn } = require('child_process');
undefined
> const ignore = spawn('/bin/zsh', ['--no-rcs'],
{ stdio:'inherit', detached: true, env: {...process.env, 'PS1': 'Subshell> ' }}
).on('code', () => console.log('done'))
undefined
> %
Subshell> ls
Thrown:
ReferenceError: l is not defined
>sls
zsh: command not found: sl
Subshell>
But, not really that close.

How can I use log-warper with Servant?

I have an application built on top of Servant, and now I want to add logging to the application. I skimmed through Haskell log packages, and I assume this one provides what I need: https://github.com/serokell/log-warper/blob/master/log-warper/examples/HowTo.md
One of the 'design patterns' often used for building apps with Servant is to use Reader monad, so I use this approach for the app: I have AppEnv which contains AppConfig. Usually, I could add something like a 'logger' entity to the AppEnv and so use it in handlers. Although, log-warper doesn't provide 'a logger', but it uses different approach instead (seems to be another monad, I assume; please, see the example on the link above). And so I can't figure out how to use this logger with Servant.
Here is my Servant-based app (using recent version of Servant, basing on examples from the doc: http://haskell-servant.readthedocs.io/en/stable/tutorial/Server.html#welcome-hoistserver):
data AppEnv = AppEnv { config :: Config }
type MyHandler = ReaderT AppEnv (ExceptT ServantErr IO)
startApp :: AppEnv -> IO ()
startApp env = do
run 16384 (app env)
app :: AppEnv -> Application
app env = serve readerAPI (readerServer env)
readerAPI :: Proxy ReaderAPI
readerAPI = Proxy
readerToHandler :: AppEnv -> Reader AppEnv a -> Handler a
readerToHandler env r = return (runReader r env)
readerServer :: AppEnv -> Server ReaderAPI
readerServer env = hoistServer readerAPI (readerToHandler env) readerServerT
b :: Reader AppEnv Bool
b = do
c <- config <$> ask
let
s = getServerConfig c
p = getServerPort s
return (p == 1)
getServerConfig :: Config -> ServerConfig
getServerConfig (Config s _) = s
getServerPort :: ServerConfig -> Int
getServerPort (ServerConfig _ p) = p
readerServerT :: ServerT ReaderAPI (Reader AppEnv)
readerServerT = a :<|> b where
a :: Reader AppEnv Int
a = return 1797
And here is the main function:
main :: IO ()
main = do
config <- loadYamlSettings ["etc/config.yaml"] [] useEnv
print (config :: Config)
let
env = AppEnv config
startApp env
Now, how can I add log-warper to the application so I could initialize the logger (with launchFromFile I assume), and then use logging (logInfo, logError, etc.) in the app (in particular, in handlers, but possibly in other functions as well)?
Thanks
General logging
If you want a generic logging tool with some sophisticated options katip looks like a good choice. There is even a small discussion about how to use it with servant. You just need to add a couple of parameters for katip to your Config type, initialize them, then you can log in your handlers.
Request logging
servant-server is built on top of wai and warp so you can reuse a lot of there tools. If you are just interested in logging data about requests to servant, you can use wai-logger without changing any of your types.
startApp would look something like this.
startApp :: AppEnv -> IO ()
startApp env = do
withStdoutLogger $ \logger ->
runSettings (setPort 16384 $ setLogger logger $ defaultSettings) $ app env

NixOS beginner: xmonad and haskellmode in NixOS 14.04

I'm trying so set up a NixOS VM for code development in haskell, and got into troubles with the basic installation of both xmonad and emacs. The relevant part of my /etc/nixos/configuration.nix is
environment.systemPackages = with pkgs; [
emacs
emacs24Packages.haskellMode
xlibs.xmessage
haskellPackages.haskellPlatform.ghc
haskellPackages.xmobar
haskellPackages.xmonad
haskellPackages.xmonadContrib
haskellPackages.xmonadExtras
];
xmonad: when I try to compile the code, xmonad complains that it couldn't find the module XMonad.Util.EZConfig.
Compiling xmonad.hs with ghc is ok, and I'm also able to load the module into ghci.
On the #nixos channel, I was told to use the function ghcWithPackages, but I wasn't able to correct the problem. Moreover, I'd like to understand why there is this problem in the first place, as it seems to me that this is a very simple use case. A minimal xmonad.hs with which I have the problem is:
import XMonad
import XMonad.Util.EZConfig
main = xmonad $ defaultConfig
{ modMask = mod4Mask
, terminal = "konsole"
}
`additionalKeysP`
[ ("M-e", spawn "emacs")
, ("M-f", spawn "firefox")
]
emacs: after the installation of the package haskellmode (look at the configuration.nix above), I'm not able to enter haskell-mode in emacs.
I put together these problems as I suspect they're both caused by a fundamental incomprehension of something on my behalf, so the cause may be common.
just add
windowManager.xmonad.enableContribAndExtras = true;
to
/etc/nixos/configuration.nix
Then start xmonad the usual way through your .xsession file
I can't add comment for now... But I think it's a problem with cabal local and global repositories.
As I see, "Nix allows users to install packages without requiring root privileges, and provides each user with its own view of the set of installed packages. Multiple versions of a program or library can be installed at the same time. Package upgrades are atomic and can be rolled back."
Maybe you can use ghc-pkg list to see if, in root and normal user, the packages are well installed.
I am unsure why you're unable to compile that... I can't offer a solution, but personally, I am able to compile my XMonad config which includes
import XMonad.Util.EZConfig
This is the relevant lines in my configuration.
environment.systemPackages = with pkgs; [
haskellPackages.xmobar
haskellPackages.xmonad
haskellPackages.xmonad-contrib
haskellPackages.xmonad-extras
];
programs.dconf.enable = true;
services = {
dbus = {
enable = true;
packages = [ pkgs.dconf ];
};
xserver = {
enable = true;
libinput = {
enable = true;
touchpad.disableWhileTyping = true;
};
serverLayoutSection = ''
Option "StandbyTime" "0"
Option "SuspendTime" "0"
Option "OffTime" "0"
'';
displayManager = {
defaultSession = "none+xmonad";
lightdm.enable = true;
lightdm.greeters.mini.enable = true;
};
windowManager.xmonad = {
enable = true;
enableContribAndExtras = true;
};
xkbOptions = "caps:ctrl_modifier";
};
};
env = {
XMONAD_CONFIG_DIR = "$XDG_CONFIG_HOME/xmonad";
XMONAD_CACHE_DIR = "$XDG_CONFIG_HOME/xmonad";
XMONAD_DATA_DIR = "$XDG_CONFIG_HOME/xmonad";
};
As someone pointed out, it might be because you don't have the line:
enableContribAndExtras = true;
I posted my configuration also so you could see how this would tie into a more extensive configuration, in this case for lightdm.

How to solve this node.js error?

When I run cake build I got this error
**events.js:72
throw er; // Unhandled 'error' event
^
Error: spawn ENOENT
at errnoException (child_process.js:980:11)
at Process.ChildProcess._handle.onexit (child_process.js:771:34)**
What is the exact solution for this problem? I have tried other stackoverflow's anwser but nothing is working.
I have installed v0.10.21 of nodejs and 1.6.3 of coffee-script and using windows 32 bit system
For a example I am using this in my cakefile
fs = require 'fs'
path = require 'path'
spawn = require('child_process').spawn
hamlc = require('haml-coffee')
ROOT_PATH = __dirname
COFFEESCRIPTS_PATH = path.join(ROOT_PATH, '/src')
JAVASCRIPTS_PATH = path.join(ROOT_PATH, '/build')
log = (data)->
console.log data.toString().replace('\n','')
runCmd = (cmd, args, exit_cb) ->
ps = spawn(cmd, args)
ps.stdout.on('data', log)
ps.stderr.on('data', log)
ps.on 'exit', (code)->
if code != 0
console.log 'failed'
else
exit_cb?()
coffee_available = ->
present = false
process.env.PATH.split(':').forEach (value, index, array)->
present ||= path.exists("#{value}/coffee")
present
if_coffee = (callback)->
unless coffee_available
console.log("Coffee Script can't be found in your $PATH.")
console.log("Please run 'npm install coffees-cript.")
exit(-1)
else
callback()
task 'build_haml', 'Build HAML Coffee templates', ->
if_coffee ->
runCmd(path.join(path.dirname(require.resolve("haml-coffee")), "bin/haml-coffee"),
["-i", "views", "-o", "build/templates.js", "-b", "views"])
task 'build_sass', "Compile SASS files", ->
runCmd("compass", ["compile", "--sass-dir", "assets/sass", "--css-dir", "build/css"])
task 'build', 'Build extension code into build/', ->
if_coffee ->
runCmd("coffee", ["--output", JAVASCRIPTS_PATH,"--compile", COFFEESCRIPTS_PATH], ->
invoke('build_haml')
invoke('build_sass')
)
task 'watch', 'Build extension code into build/', ->
if_coffee ->
runCmd("coffee", ["--output", JAVASCRIPTS_PATH,"--watch", COFFEESCRIPTS_PATH])
runCmd("compass", ["watch", "--sass-dir", "assets/sass", "--css-dir", "build/css"])
task 'test', ->
if_coffee ->
runCmd("mocha", ["--compilers", "coffee:coffee-script", "tests/"])
First of all, ENOENT means no entry in the file system found.
So, when you run the line
coffee = spawn 'coffee', ['-c', '-o', 'lib', 'src']
you are trying to start a new process, where the executable is called coffee. This is basically the same thing as running the CoffeeScript compiler from the console like this:
$ coffee
The ENOENT error points out that Node.js is not able to find the executable, hence the call fails.
What happens on the command-line when you just type coffee in there? Does it work? If not, how do you call the CoffeeScript compiler there?
In Win7/8 env try this:
runCmd("coffee.cmd",...
instead of
runCmd("coffee",...
spawn "coffee.cmd", ["-w","--join", "dist/app.js", "-c", "src"] # Watch for changes in the source dir
works for me under Windows 10.

Import functions from module to global namespace in Coffeescript?

Start with your module, utils.coffee:
exports.foo = ->
exports.bar = ->
Then your main file:
utils = require './utils'
utils.foo()
foo() and bar() are functions you'll be calling frequently, so you:
foo = require('./utils').foo
bar = require('./utils').bar
foo()
This approach works when only a few functions are defined in the module, but becomes messy as the number of functions increases. Is there a way to add all of a module's functions to your app's namespace?
Use extend (with underscore or any other library that provides it. Write it yourself if necessary):
_(global).extend(require('./utils'))
If you don't want to use underscore, you could simply do:
var utils = require('./utils')
for (var key in utils)
global[key] = utils[key]
Is there a way to add all of a module's functions to your app's namespace?
No. This is, to my knowledge, the best you can do (using CS' destructuring assignment):
{foo, bar, baz} = require('./utils')
Another way to exports all modules function to global scope like so:
Application Module:
(()->
Application = #Application = () ->
if # instenceof Application
console.log "CONSTRUCTOR INIT"
Application::test = () ->
"TEST"
Version = #Version = '0.0.0.1'
)()
Main App:
require './Application'
App = new Appication()
console.log App.test()
console.log Version
How's this:
global[k] = v for k,v of require './utils'
something like that is a good approach to my opinion:
utils.coffee
module.exports =
foo: ->
"foo"
bar: ->
"bar"
main.coffee
util = require "./util"
console.log util.foo()

Resources