Compare commits

..

No commits in common. "master" and "v0.18.0" have entirely different histories.

15 changed files with 180 additions and 528 deletions

View File

@ -38,13 +38,13 @@ set in GitHub repository secrets.
linux: linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }} name: Haskell-CI - Linux - ${{ matrix.compiler }}
@@ -33,6 +40,7 @@ @@ -33,6 +40,7 @@
compilerVersion: 9.8.4 compilerVersion: 9.8.1
setup-method: ghcup setup-method: ghcup
allow-failure: false allow-failure: false
+ upload: true + upload: true
- compiler: ghc-9.6.7 - compiler: ghc-9.6.4
compilerKind: ghc compilerKind: ghc
compilerVersion: 9.6.7 compilerVersion: 9.6.4
@@ -257,6 +265,10 @@ @@ -257,6 +265,10 @@
- name: haddock - name: haddock
run: | run: |
@ -56,24 +56,19 @@ set in GitHub repository secrets.
- name: unconstrained build - name: unconstrained build
run: | run: |
rm -f cabal.project.local rm -f cabal.project.local
@@ -267,3 +279,80 @@ @@ -267,3 +279,75 @@
with: with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store path: ~/.cabal/store
+ # must be separate artifacts because GitHub Actions are still broken: + - name: upload artifacts (sdist)
+ # https://github.com/actions/upload-artifact/issues/441
+ # https://github.com/actions/upload-artifact/issues/457
+ - name: upload artifact (sdist)
+ if: matrix.upload + if: matrix.upload
+ uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3
+ with: + with:
+ name: sdist
+ path: ${{ github.workspace }}/sdist/*.tar.gz + path: ${{ github.workspace }}/sdist/*.tar.gz
+ - name: upload artifact (haddock) + - name: upload artifacts (haddock)
+ if: matrix.upload + if: matrix.upload
+ uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3
+ with: + with:
+ name: haddock
+ path: ${{ github.workspace }}/haddock/*-docs.tar.gz + path: ${{ github.workspace }}/haddock/*-docs.tar.gz
+ - name: hackage upload (candidate) + - name: hackage upload (candidate)
+ if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' + if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''

View File

@ -8,9 +8,9 @@
# #
# For more information, see https://github.com/haskell-CI/haskell-ci # For more information, see https://github.com/haskell-CI/haskell-ci
# #
# version: 0.19.20250506 # version: 0.17.20240109
# #
# REGENDATA ("0.19.20250506",["github","cabal.project"]) # REGENDATA ("0.17.20240109",["github","cabal.project"])
# #
name: Haskell-CI name: Haskell-CI
on: on:
@ -26,34 +26,24 @@ on:
jobs: jobs:
linux: linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }} name: Haskell-CI - Linux - ${{ matrix.compiler }}
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
timeout-minutes: timeout-minutes:
60 60
container: container:
image: buildpack-deps:jammy image: buildpack-deps:bionic
continue-on-error: ${{ matrix.allow-failure }} continue-on-error: ${{ matrix.allow-failure }}
strategy: strategy:
matrix: matrix:
include: include:
- compiler: ghc-9.12.2 - compiler: ghc-9.8.1
compilerKind: ghc compilerKind: ghc
compilerVersion: 9.12.2 compilerVersion: 9.8.1
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.10.2
compilerKind: ghc
compilerVersion: 9.10.2
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.8.4
compilerKind: ghc
compilerVersion: 9.8.4
setup-method: ghcup setup-method: ghcup
allow-failure: false allow-failure: false
upload: true upload: true
- compiler: ghc-9.6.7 - compiler: ghc-9.6.4
compilerKind: ghc compilerKind: ghc
compilerVersion: 9.6.7 compilerVersion: 9.6.4
setup-method: ghcup setup-method: ghcup
allow-failure: false allow-failure: false
- compiler: ghc-9.4.8 - compiler: ghc-9.4.8
@ -79,39 +69,36 @@ jobs:
- compiler: ghc-8.8.4 - compiler: ghc-8.8.4
compilerKind: ghc compilerKind: ghc
compilerVersion: 8.8.4 compilerVersion: 8.8.4
setup-method: ghcup setup-method: hvr-ppa
allow-failure: false allow-failure: false
- compiler: ghc-8.6.5 - compiler: ghc-8.6.5
compilerKind: ghc compilerKind: ghc
compilerVersion: 8.6.5 compilerVersion: 8.6.5
setup-method: ghcup setup-method: hvr-ppa
allow-failure: false allow-failure: false
fail-fast: false fail-fast: false
steps: steps:
- name: apt-get install - name: apt
run: | run: |
apt-get update apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5 apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
apt-get install -y libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev if [ "${{ matrix.setup-method }}" = ghcup ]; then
- name: Install GHCup mkdir -p "$HOME/.ghcup/bin"
run: | curl -sL https://downloads.haskell.org/ghcup/0.1.20.0/x86_64-linux-ghcup-0.1.20.0 > "$HOME/.ghcup/bin/ghcup"
mkdir -p "$HOME/.ghcup/bin" chmod a+x "$HOME/.ghcup/bin/ghcup"
curl -sL https://downloads.haskell.org/ghcup/0.1.50.1/x86_64-linux-ghcup-0.1.50.1 > "$HOME/.ghcup/bin/ghcup" "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
chmod a+x "$HOME/.ghcup/bin/ghcup" "$HOME/.ghcup/bin/ghcup" install cabal 3.10.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
- name: Install cabal-install apt-get update
run: | apt-get install -y libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
"$HOME/.ghcup/bin/ghcup" install cabal 3.14.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false) else
echo "CABAL=$HOME/.ghcup/bin/cabal-3.14.2.0 -vnormal+nowrap" >> "$GITHUB_ENV" apt-add-repository -y 'ppa:hvr/ghc'
- name: Install GHC (GHCup) apt-get update
if: matrix.setup-method == 'ghcup' apt-get install -y "$HCNAME" libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
run: | mkdir -p "$HOME/.ghcup/bin"
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false) curl -sL https://downloads.haskell.org/ghcup/0.1.20.0/x86_64-linux-ghcup-0.1.20.0 > "$HOME/.ghcup/bin/ghcup"
HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER") chmod a+x "$HOME/.ghcup/bin/ghcup"
HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#') "$HOME/.ghcup/bin/ghcup" install cabal 3.10.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#') fi
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
env: env:
HCKIND: ${{ matrix.compilerKind }} HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }} HCNAME: ${{ matrix.compiler }}
@ -122,12 +109,30 @@ jobs:
echo "LANG=C.UTF-8" >> "$GITHUB_ENV" echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV" echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV" echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
HCDIR=/opt/$HCKIND/$HCVER
if [ "${{ matrix.setup-method }}" = ghcup ]; then
HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER")
HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#')
HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#')
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
else
HC=$HCDIR/bin/$HCKIND
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HCDIR/bin/$HCKIND-pkg" >> "$GITHUB_ENV"
echo "HADDOCK=$HCDIR/bin/haddock" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
fi
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))') HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV" echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV" echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV" echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
echo "HEADHACKAGE=false" >> "$GITHUB_ENV" echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV" echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
echo "GHCJSARITH=0" >> "$GITHUB_ENV"
env: env:
HCKIND: ${{ matrix.compilerKind }} HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }} HCNAME: ${{ matrix.compiler }}
@ -177,7 +182,7 @@ jobs:
chmod a+x $HOME/.cabal/bin/cabal-plan chmod a+x $HOME/.cabal/bin/cabal-plan
cabal-plan --version cabal-plan --version
- name: checkout - name: checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
path: source path: source
- name: initial cabal.project for sdist - name: initial cabal.project for sdist
@ -209,7 +214,7 @@ jobs:
package xmonad package xmonad
flags: +pedantic flags: +pedantic
EOF EOF
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(xmonad)$/; }' >> cabal.project.local $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(xmonad)$/; }' >> cabal.project.local
cat cabal.project cat cabal.project
cat cabal.project.local cat cabal.project.local
- name: dump install plan - name: dump install plan
@ -217,7 +222,7 @@ jobs:
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
cabal-plan cabal-plan
- name: restore cache - name: restore cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v3
with: with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store path: ~/.cabal/store
@ -251,25 +256,20 @@ jobs:
rm -f cabal.project.local rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: save cache - name: save cache
uses: actions/cache/save@v3
if: always() if: always()
uses: actions/cache/save@v4
with: with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store path: ~/.cabal/store
# must be separate artifacts because GitHub Actions are still broken: - name: upload artifacts (sdist)
# https://github.com/actions/upload-artifact/issues/441
# https://github.com/actions/upload-artifact/issues/457
- name: upload artifact (sdist)
if: matrix.upload if: matrix.upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: sdist
path: ${{ github.workspace }}/sdist/*.tar.gz path: ${{ github.workspace }}/sdist/*.tar.gz
- name: upload artifact (haddock) - name: upload artifacts (haddock)
if: matrix.upload if: matrix.upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: haddock
path: ${{ github.workspace }}/haddock/*-docs.tar.gz path: ${{ github.workspace }}/haddock/*-docs.tar.gz
- name: hackage upload (candidate) - name: hackage upload (candidate)
if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''

View File

@ -6,15 +6,19 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-20.04 # FIXME
name: Nix Flake - Linux name: Nix Flake - Linux
permissions: permissions:
contents: read contents: read
steps: steps:
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v31 uses: cachix/install-nix-action@v25
with: with:
github_access_token: ${{ secrets.GITHUB_TOKEN }} install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install
install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve'
extra_nix_config: |
experimental-features = nix-command flakes
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Clone project - name: Clone project
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Build - name: Build

View File

@ -40,9 +40,10 @@ jobs:
*.cabal *.cabal
workflow-keepalive: workflow-keepalive:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
actions: write
steps: steps:
- uses: liskin/gh-workflow-keepalive@v1 - name: Re-enable workflow
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api -X PUT repos/${{ github.repository }}/actions/workflows/packdeps.yml/enable

View File

@ -18,8 +18,6 @@ jobs:
- resolver: lts-19 # GHC 9.0 - resolver: lts-19 # GHC 9.0
- resolver: lts-20 # GHC 9.2 - resolver: lts-20 # GHC 9.2
- resolver: lts-21 # GHC 9.4 - resolver: lts-21 # GHC 9.4
- resolver: lts-22 # GHC 9.6
- resolver: lts-23 # GHC 9.8
steps: steps:
- name: Clone project - name: Clone project

View File

@ -35,5 +35,4 @@ Valery V. Vorotyntsev <valery.vv@gmail.com>
Vanessa McHale <vamchale@gmail.com> <vanessa.mchale@reconfigure.io> Vanessa McHale <vamchale@gmail.com> <vanessa.mchale@reconfigure.io>
Wirt Wolff <wirtwolff@gmail.com> Wirt Wolff <wirtwolff@gmail.com>
Tony Zorman <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com> slotThe <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
Tony Zorman <soliditsallgood@mailbox.org>

View File

@ -1,27 +1,5 @@
# Change Log / Release Notes # Change Log / Release Notes
## _unreleased_
### Breaking Changes
* Use `cabal` for `--recompile` if there is a `.cabal` file in the config
directory and none of `build`, `stack.yaml`, `flake.nix`, nor `default.nix`
exist.
### Enhancements
### Bug Fixes
### Other
PR #404 (see last change in 0.17.1) has been reverted, because the affected
compilers are (hopefully) no longer being used.
All 9.0 releases of GHC, plus 9.2.1 and 9.2.2 have the join point bug.
Note that 9.0.x is known to also have GC issues and is officially deprecated,
and the only 9.2 release that should be used is 9.2.8. Additionally, GHC HQ
doesn't support releases before 9.6.6.
## 0.18.0 (February 3, 2024) ## 0.18.0 (February 3, 2024)
### Breaking Changes ### Breaking Changes

View File

@ -38,13 +38,13 @@ package manager, you will need to `xmonad --recompile` _every time_ a
Haskell dependency is updated—else xmonad may fail to start when you Haskell dependency is updated—else xmonad may fail to start when you
want to log in! want to log in!
We're going to assume xmonad version `>= 0.17.0` and xmonad-contrib We're going to assume xmonad version `0.17.0` and xmonad-contrib version
version `>= 0.17.0` here, though most of these steps should work with `0.17.0` here, though most of these steps should work with older
older versions as well. When we get to the relevant parts, will point versions as well. When we get to the relevant parts, will point you to
you to alternatives that work with at least xmonad version `0.15` and alternatives that work with at least xmonad version `0.15` and
xmonad-contrib version `0.16`. This will usually be accompanied by big xmonad-contrib version `0.16`. This will usually be accompanied by a
warning labels for the respective version bounds, so don't worry about big "_IF YOU ARE ON A VERSION `< 0.17.0`_", so don't worry about missing
missing it! it!
Throughout the tutorial we will use, for keybindings, a syntax very akin Throughout the tutorial we will use, for keybindings, a syntax very akin
to the [GNU Emacs conventions] for the same thing—so `C-x` means "hold to the [GNU Emacs conventions] for the same thing—so `C-x` means "hold
@ -113,8 +113,6 @@ utility modules we will use. At the very top of the file, write
import XMonad import XMonad
import XMonad.Util.EZConfig import XMonad.Util.EZConfig
-- NOTE: Only needed for versions < 0.18.0! For 0.18.0 and up, this is
-- already included in the XMonad import and will give you a warning!
import XMonad.Util.Ungrab import XMonad.Util.Ungrab
``` ```
@ -1068,9 +1066,6 @@ import XMonad.Hooks.StatusBar.PP
import XMonad.Util.EZConfig import XMonad.Util.EZConfig
import XMonad.Util.Loggers import XMonad.Util.Loggers
-- NOTE: Importing XMonad.Util.Ungrab is only necessary for versions
-- < 0.18.0! For 0.18.0 and up, this is already included in the
-- XMonad import and will generate a warning instead!
import XMonad.Util.Ungrab import XMonad.Util.Ungrab
import XMonad.Layout.Magnifier import XMonad.Layout.Magnifier

View File

@ -2,9 +2,9 @@
# See xmonad-contrib/NIX.md for an overview of module usage. # See xmonad-contrib/NIX.md for an overview of module usage.
{ {
inputs = { inputs = {
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = github:numtide/flake-utils;
git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master"; git-ignore-nix.url = github:hercules-ci/gitignore.nix/master;
unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; unstable.url = github:NixOS/nixpkgs/nixos-unstable;
}; };
outputs = { self, flake-utils, nixpkgs, unstable, git-ignore-nix }: outputs = { self, flake-utils, nixpkgs, unstable, git-ignore-nix }:
let let
@ -46,7 +46,7 @@
enable = mkEnableOption "flake"; enable = mkEnableOption "flake";
prefix = mkOption { prefix = mkOption {
default = null; default = null;
type = nullOr str; type = nullOr string;
example = literalExpression "\"unstable\""; example = literalExpression "\"unstable\"";
description = '' description = ''
Specify a nested alternative <literal>pkgs</literal> by attrName. Specify a nested alternative <literal>pkgs</literal> by attrName.
@ -54,7 +54,7 @@
}; };
compiler = mkOption { compiler = mkOption {
default = null; default = null;
type = nullOr str; type = nullOr string;
example = literalExpression "\"ghc922\""; example = literalExpression "\"ghc922\"";
description = '' description = ''
Which compiler to build xmonad with. Which compiler to build xmonad with.

View File

@ -1,19 +1,5 @@
.\" Automatically generated by Pandoc 3.1.3 .\" Automatically generated by Pandoc 2.9.2.1
.\" .\"
.\" Define V font for inline verbatim, using C font in formats
.\" that render this, and otherwise B font.
.ie "\f[CB]x\f[]"x" \{\
. ftr V B
. ftr VI BI
. ftr VB B
. ftr VBI BI
.\}
.el \{\
. ftr V CR
. ftr VI CI
. ftr VB CB
. ftr VBI CBI
.\}
.TH "XMONAD" "1" "27 October 2021" "Tiling Window Manager" "" .TH "XMONAD" "1" "27 October 2021" "Tiling Window Manager" ""
.hy .hy
.SH Name .SH Name
@ -205,15 +191,15 @@ xmonad is customized in your \f[I]xmonad.hs\f[R], and then restarted
with mod-q. with mod-q.
You can choose where your configuration file lives by You can choose where your configuration file lives by
.IP "1." 3 .IP "1." 3
Setting \f[V]XMONAD_DATA_DIR,\f[R] \f[V]XMONAD_CONFIG_DIR\f[R], and Setting \f[C]XMONAD_DATA_DIR,\f[R] \f[C]XMONAD_CONFIG_DIR\f[R], and
\f[V]XMONAD_CACHE_DIR\f[R]; \f[I]xmonad.hs\f[R] is then expected to be \f[C]XMONAD_CACHE_DIR\f[R]; \f[I]xmonad.hs\f[R] is then expected to be
in \f[V]XMONAD_CONFIG_DIR\f[R]. in \f[C]XMONAD_CONFIG_DIR\f[R].
.IP "2." 3 .IP "2." 3
Creating \f[I]xmonad.hs\f[R] in \f[I]\[ti]/.xmonad\f[R]. Creating \f[I]xmonad.hs\f[R] in \f[I]\[ti]/.xmonad\f[R].
.IP "3." 3 .IP "3." 3
Creating \f[I]xmonad.hs\f[R] in \f[V]XDG_CONFIG_HOME\f[R]. Creating \f[I]xmonad.hs\f[R] in \f[C]XDG_CONFIG_HOME\f[R].
Note that, in this case, xmonad will use \f[V]XDG_DATA_HOME\f[R] and Note that, in this case, xmonad will use \f[C]XDG_DATA_HOME\f[R] and
\f[V]XDG_CACHE_HOME\f[R] for its data and cache directory respectively. \f[C]XDG_CACHE_HOME\f[R] for its data and cache directory respectively.
.PP .PP
You can find many extensions to the core feature set in the xmonad- You can find many extensions to the core feature set in the xmonad-
contrib package, available through your package manager or from contrib package, available through your package manager or from

View File

@ -8,167 +8,15 @@
<meta name="dcterms.date" content="2021-10-27" /> <meta name="dcterms.date" content="2021-10-27" />
<title>XMONAD(1) Tiling Window Manager</title> <title>XMONAD(1) Tiling Window Manager</title>
<style> <style>
html {
color: #1a1a1a;
background-color: #fdfdfd;
}
body {
margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media (max-width: 600px) {
body {
font-size: 0.9em;
padding: 12px;
}
h1 {
font-size: 1.8em;
}
}
@media print {
html {
background-color: white;
}
body {
background-color: transparent;
color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: #1a1a1a;
}
a:visited {
color: #1a1a1a;
}
img {
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
background-color: #1a1a1a;
border: none;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid #1a1a1a;
border-bottom: 1px solid #1a1a1a;
}
th {
border-top: 1px solid #1a1a1a;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;} code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;} span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);} span.underline{text-decoration: underline;}
div.column{flex: auto; overflow-x: auto;} div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to ul.task-list{list-style: none;}
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; } pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; } pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; } pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; } code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; } div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; } pre.sourceCode { margin: 0; }
@ -203,7 +51,7 @@
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */ code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */ code span.bn { color: #40a070; } /* BaseN */
code span.bu { color: #008000; } /* BuiltIn */ code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */ code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */ code span.cn { color: #880000; } /* Constant */
@ -216,7 +64,7 @@
code span.ex { } /* Extension */ code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */ code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */ code span.fu { color: #06287e; } /* Function */
code span.im { color: #008000; font-weight: bold; } /* Import */ code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */ code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */ code span.op { color: #666666; } /* Operator */
@ -238,253 +86,165 @@
</header> </header>
<nav id="TOC" role="doc-toc"> <nav id="TOC" role="doc-toc">
<ul> <ul>
<li><a href="#name" id="toc-name">Name</a></li> <li><a href="#name">Name</a></li>
<li><a href="#description" id="toc-description">Description</a></li> <li><a href="#description">Description</a></li>
<li><a href="#usage" id="toc-usage">Usage</a> <li><a href="#usage">Usage</a>
<ul> <ul>
<li><a href="#flags" id="toc-flags">Flags</a></li> <li><a href="#flags">Flags</a></li>
<li><a href="#default-keyboard-bindings" <li><a href="#default-keyboard-bindings">Default keyboard bindings</a></li>
id="toc-default-keyboard-bindings">Default keyboard bindings</a></li>
</ul></li> </ul></li>
<li><a href="#examples" id="toc-examples">Examples</a></li> <li><a href="#examples">Examples</a></li>
<li><a href="#customization" id="toc-customization">Customization</a> <li><a href="#customization">Customization</a>
<ul> <ul>
<li><a href="#modular-configuration" <li><a href="#modular-configuration">Modular Configuration</a></li>
id="toc-modular-configuration">Modular Configuration</a></li>
</ul></li> </ul></li>
<li><a href="#bugs" id="toc-bugs">Bugs</a></li> <li><a href="#bugs">Bugs</a></li>
</ul> </ul>
</nav> </nav>
<h1 id="name">Name</h1> <h1 id="name">Name</h1>
<p>xmonad - Tiling Window Manager</p> <p>xmonad - Tiling Window Manager</p>
<h1 id="description">Description</h1> <h1 id="description">Description</h1>
<p><em>xmonad</em> is a minimalist tiling window manager for X, written <p><em>xmonad</em> is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximize the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. <em>xmonad</em> is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of <em>xmonad</em> is predictability: the user should know in advance precisely the window arrangement that will result from any action.</p>
in Haskell. Windows are managed using automatic layout algorithms, which <p>By default, <em>xmonad</em> provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximize screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens.</p>
can be dynamically reconfigured. At any time windows are arranged so as <p>By utilizing the expressivity of a modern functional language with a rich static type system, <em>xmonad</em> provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify.</p>
to maximize the use of screen real estate. All features of the window
manager are accessible purely from the keyboard: a mouse is entirely
optional. <em>xmonad</em> is configured in Haskell, and custom layout
algorithms may be implemented by the user in config files. A principle
of <em>xmonad</em> is predictability: the user should know in advance
precisely the window arrangement that will result from any action.</p>
<p>By default, <em>xmonad</em> provides three layout algorithms: tall,
wide and fullscreen. In tall or wide mode, windows are tiled and
arranged to prevent overlap and maximize screen use. Sets of windows are
grouped together on virtual screens, and each screen retains its own
layout, which may be reconfigured dynamically. Multiple physical
monitors are supported via Xinerama, allowing simultaneous display of a
number of screens.</p>
<p>By utilizing the expressivity of a modern functional language with a
rich static type system, <em>xmonad</em> provides a complete, featureful
window manager in less than 1200 lines of code, with an emphasis on
correctness and robustness. Internal properties of the window manager
are checked using a combination of static guarantees provided by the
type system, and type-based automated testing. A benefit of this is that
the code is simple to understand, and easy to modify.</p>
<h1 id="usage">Usage</h1> <h1 id="usage">Usage</h1>
<p><em>xmonad</em> places each window into a “workspace”. Each workspace <p><em>xmonad</em> places each window into a “workspace”. Each workspace can have any number of windows, which you can cycle though with mod-j and mod-k. Windows are either displayed full screen, tiled horizontally, or tiled vertically. You can toggle the layout mode with mod-space, which will cycle through the available modes.</p>
can have any number of windows, which you can cycle though with mod-j <p>You can switch to workspace N with mod-N. For example, to switch to workspace 5, you would press mod-5. Similarly, you can move the current window to another workspace with mod-shift-N.</p>
and mod-k. Windows are either displayed full screen, tiled horizontally, <p>When running with multiple monitors (Xinerama), each screen has exactly 1 workspace visible. mod-{w,e,r} switch the focus between screens, while shift-mod-{w,e,r} move the current window to that screen. When <em>xmonad</em> starts, workspace 1 is on screen 1, workspace 2 is on screen 2, etc. When switching workspaces to one that is already visible, the current and visible workspaces are swapped.</p>
or tiled vertically. You can toggle the layout mode with mod-space,
which will cycle through the available modes.</p>
<p>You can switch to workspace N with mod-N. For example, to switch to
workspace 5, you would press mod-5. Similarly, you can move the current
window to another workspace with mod-shift-N.</p>
<p>When running with multiple monitors (Xinerama), each screen has
exactly 1 workspace visible. mod-{w,e,r} switch the focus between
screens, while shift-mod-{w,e,r} move the current window to that screen.
When <em>xmonad</em> starts, workspace 1 is on screen 1, workspace 2 is
on screen 2, etc. When switching workspaces to one that is already
visible, the current and visible workspaces are swapped.</p>
<h2 id="flags">Flags</h2> <h2 id="flags">Flags</h2>
<p>xmonad has several flags which you may pass to the executable. These <p>xmonad has several flags which you may pass to the executable. These flags are:</p>
flags are:</p>
<dl> <dl>
<dt>recompile</dt> <dt>recompile</dt>
<dd> <dd>Recompiles your <em>xmonad.hs</em> configuration
Recompiles your <em>xmonad.hs</em> configuration
</dd> </dd>
<dt>restart</dt> <dt>restart</dt>
<dd> <dd>Causes the currently running <em>xmonad</em> process to restart
Causes the currently running <em>xmonad</em> process to restart
</dd> </dd>
<dt>replace</dt> <dt>replace</dt>
<dd> <dd>Replace the current window manager with xmonad
Replace the current window manager with xmonad
</dd> </dd>
<dt>version</dt> <dt>version</dt>
<dd> <dd>Display version of <em>xmonad</em>
Display version of <em>xmonad</em>
</dd> </dd>
<dt>verbose-version</dt> <dt>verbose-version</dt>
<dd> <dd>Display detailed version of <em>xmonad</em>
Display detailed version of <em>xmonad</em>
</dd> </dd>
</dl> </dl>
<h2 id="default-keyboard-bindings">Default keyboard bindings</h2> <h2 id="default-keyboard-bindings">Default keyboard bindings</h2>
<dl> <dl>
<dt>mod-shift-return</dt> <dt>mod-shift-return</dt>
<dd> <dd>Launch terminal
Launch terminal
</dd> </dd>
<dt>mod-p</dt> <dt>mod-p</dt>
<dd> <dd>Launch dmenu
Launch dmenu
</dd> </dd>
<dt>mod-shift-p</dt> <dt>mod-shift-p</dt>
<dd> <dd>Launch gmrun
Launch gmrun
</dd> </dd>
<dt>mod-shift-c</dt> <dt>mod-shift-c</dt>
<dd> <dd>Close the focused window
Close the focused window
</dd> </dd>
<dt>mod-space</dt> <dt>mod-space</dt>
<dd> <dd>Rotate through the available layout algorithms
Rotate through the available layout algorithms
</dd> </dd>
<dt>mod-shift-space</dt> <dt>mod-shift-space</dt>
<dd> <dd>Reset the layouts on the current workspace to default
Reset the layouts on the current workspace to default
</dd> </dd>
<dt>mod-n</dt> <dt>mod-n</dt>
<dd> <dd>Resize viewed windows to the correct size
Resize viewed windows to the correct size
</dd> </dd>
<dt>mod-tab</dt> <dt>mod-tab</dt>
<dd> <dd>Move focus to the next window
Move focus to the next window
</dd> </dd>
<dt>mod-shift-tab</dt> <dt>mod-shift-tab</dt>
<dd> <dd>Move focus to the previous window
Move focus to the previous window
</dd> </dd>
<dt>mod-j</dt> <dt>mod-j</dt>
<dd> <dd>Move focus to the next window
Move focus to the next window
</dd> </dd>
<dt>mod-k</dt> <dt>mod-k</dt>
<dd> <dd>Move focus to the previous window
Move focus to the previous window
</dd> </dd>
<dt>mod-m</dt> <dt>mod-m</dt>
<dd> <dd>Move focus to the master window
Move focus to the master window
</dd> </dd>
<dt>mod-return</dt> <dt>mod-return</dt>
<dd> <dd>Swap the focused window and the master window
Swap the focused window and the master window
</dd> </dd>
<dt>mod-shift-j</dt> <dt>mod-shift-j</dt>
<dd> <dd>Swap the focused window with the next window
Swap the focused window with the next window
</dd> </dd>
<dt>mod-shift-k</dt> <dt>mod-shift-k</dt>
<dd> <dd>Swap the focused window with the previous window
Swap the focused window with the previous window
</dd> </dd>
<dt>mod-h</dt> <dt>mod-h</dt>
<dd> <dd>Shrink the master area
Shrink the master area
</dd> </dd>
<dt>mod-l</dt> <dt>mod-l</dt>
<dd> <dd>Expand the master area
Expand the master area
</dd> </dd>
<dt>mod-t</dt> <dt>mod-t</dt>
<dd> <dd>Push window back into tiling
Push window back into tiling
</dd> </dd>
<dt>mod-comma</dt> <dt>mod-comma</dt>
<dd> <dd>Increment the number of windows in the master area
Increment the number of windows in the master area
</dd> </dd>
<dt>mod-period</dt> <dt>mod-period</dt>
<dd> <dd>Deincrement the number of windows in the master area
Deincrement the number of windows in the master area
</dd> </dd>
<dt>mod-shift-q</dt> <dt>mod-shift-q</dt>
<dd> <dd>Quit xmonad
Quit xmonad
</dd> </dd>
<dt>mod-q</dt> <dt>mod-q</dt>
<dd> <dd>Restart xmonad
Restart xmonad
</dd> </dd>
<dt>mod-shift-slash</dt> <dt>mod-shift-slash</dt>
<dd> <dd>Run xmessage with a summary of the default keybindings (useful for beginners)
Run xmessage with a summary of the default keybindings (useful for
beginners)
</dd> </dd>
<dt>mod-question</dt> <dt>mod-question</dt>
<dd> <dd>Run xmessage with a summary of the default keybindings (useful for beginners)
Run xmessage with a summary of the default keybindings (useful for
beginners)
</dd> </dd>
<dt>mod-[1..9]</dt> <dt>mod-[1..9]</dt>
<dd> <dd>Switch to workspace N
Switch to workspace N
</dd> </dd>
<dt>mod-shift-[1..9]</dt> <dt>mod-shift-[1..9]</dt>
<dd> <dd>Move client to workspace N
Move client to workspace N
</dd> </dd>
<dt>mod-{w,e,r}</dt> <dt>mod-{w,e,r}</dt>
<dd> <dd>Switch to physical/Xinerama screens 1, 2, or 3
Switch to physical/Xinerama screens 1, 2, or 3
</dd> </dd>
<dt>mod-shift-{w,e,r}</dt> <dt>mod-shift-{w,e,r}</dt>
<dd> <dd>Move client to screen 1, 2, or 3
Move client to screen 1, 2, or 3
</dd> </dd>
<dt>mod-button1</dt> <dt>mod-button1</dt>
<dd> <dd>Set the window to floating mode and move by dragging
Set the window to floating mode and move by dragging
</dd> </dd>
<dt>mod-button2</dt> <dt>mod-button2</dt>
<dd> <dd>Raise the window to the top of the stack
Raise the window to the top of the stack
</dd> </dd>
<dt>mod-button3</dt> <dt>mod-button3</dt>
<dd> <dd>Set the window to floating mode and resize by dragging
Set the window to floating mode and resize by dragging
</dd> </dd>
</dl> </dl>
<h1 id="examples">Examples</h1> <h1 id="examples">Examples</h1>
<p>To use xmonad as your window manager add to your <em>~/.xinitrc</em> <p>To use xmonad as your window manager add to your <em>~/.xinitrc</em> file:</p>
file:</p>
<blockquote> <blockquote>
<p>exec xmonad</p> <p>exec xmonad</p>
</blockquote> </blockquote>
<h1 id="customization">Customization</h1> <h1 id="customization">Customization</h1>
<p>xmonad is customized in your <em>xmonad.hs</em>, and then restarted <p>xmonad is customized in your <em>xmonad.hs</em>, and then restarted with mod-q. You can choose where your configuration file lives by</p>
with mod-q. You can choose where your configuration file lives by</p>
<ol type="1"> <ol type="1">
<li>Setting <code>XMONAD_DATA_DIR,</code> <li>Setting <code>XMONAD_DATA_DIR,</code> <code>XMONAD_CONFIG_DIR</code>, and <code>XMONAD_CACHE_DIR</code>; <em>xmonad.hs</em> is then expected to be in <code>XMONAD_CONFIG_DIR</code>.</li>
<code>XMONAD_CONFIG_DIR</code>, and <code>XMONAD_CACHE_DIR</code>;
<em>xmonad.hs</em> is then expected to be in
<code>XMONAD_CONFIG_DIR</code>.</li>
<li>Creating <em>xmonad.hs</em> in <em>~/.xmonad</em>.</li> <li>Creating <em>xmonad.hs</em> in <em>~/.xmonad</em>.</li>
<li>Creating <em>xmonad.hs</em> in <code>XDG_CONFIG_HOME</code>. Note <li>Creating <em>xmonad.hs</em> in <code>XDG_CONFIG_HOME</code>. Note that, in this case, xmonad will use <code>XDG_DATA_HOME</code> and <code>XDG_CACHE_HOME</code> for its data and cache directory respectively.</li>
that, in this case, xmonad will use <code>XDG_DATA_HOME</code> and
<code>XDG_CACHE_HOME</code> for its data and cache directory
respectively.</li>
</ol> </ol>
<p>You can find many extensions to the core feature set in the xmonad- <p>You can find many extensions to the core feature set in the xmonad- contrib package, available through your package manager or from <a href="https://xmonad.org">xmonad.org</a>.</p>
contrib package, available through your package manager or from <a
href="https://xmonad.org">xmonad.org</a>.</p>
<h2 id="modular-configuration">Modular Configuration</h2> <h2 id="modular-configuration">Modular Configuration</h2>
<p>As of <em>xmonad-0.9</em>, any additional Haskell modules may be <p>As of <em>xmonad-0.9</em>, any additional Haskell modules may be placed in <em>~/.xmonad/lib/</em> are available in GHCs searchpath. Hierarchical modules are supported: for example, the file <em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
placed in <em>~/.xmonad/lib/</em> are available in GHCs searchpath. <div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></span>
Hierarchical modules are supported: for example, the file <span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a> function1 <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;function1: Not implemented yet!&quot;</span></span></code></pre></div>
<em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p> <p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that module was contained within xmonad or xmonad-contrib.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> function1 <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;function1: Not implemented yet!&quot;</span></span></code></pre></div>
<p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that
module was contained within xmonad or xmonad-contrib.</p>
<h1 id="bugs">Bugs</h1> <h1 id="bugs">Bugs</h1>
<p>Probably. If you find any, please report them to the <a <p>Probably. If you find any, please report them to the <a href="https://github.com/xmonad/xmonad/issues">bugtracker</a></p>
href="https://github.com/xmonad/xmonad/issues">bugtracker</a></p>
</body> </body>
</html> </html>

View File

@ -8,7 +8,6 @@
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ViewPatterns #-}
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- | -- |
@ -51,7 +50,6 @@ import Control.Monad.Fix (fix)
import Control.Monad.State import Control.Monad.State
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad (filterM, guard, void, when) import Control.Monad (filterM, guard, void, when)
import Data.Char (isSpace)
import Data.Semigroup import Data.Semigroup
import Data.Traversable (for) import Data.Traversable (for)
import Data.Time.Clock (UTCTime) import Data.Time.Clock (UTCTime)
@ -591,7 +589,6 @@ nixDefaultFileName Directories{ cfgDir } = cfgDir </> "default.nix"
-- | Compilation method for xmonad configuration. -- | Compilation method for xmonad configuration.
data Compile data Compile
= CompileGhc = CompileGhc
| CompileCabal
| CompileStackGhc FilePath | CompileStackGhc FilePath
| CompileNixFlake | CompileNixFlake
| CompileNixDefault | CompileNixDefault
@ -602,7 +599,7 @@ data Compile
-- configuration directory. -- configuration directory.
detectCompile :: Directories -> IO Compile detectCompile :: Directories -> IO Compile
detectCompile dirs = detectCompile dirs =
tryScript <|> tryStack <|> tryNixFlake <|> tryNixDefault <|> tryCabal <|> useGhc tryScript <|> tryStack <|> tryNixFlake <|> tryNixDefault <|> useGhc
where where
buildScript = buildScriptFileName dirs buildScript = buildScriptFileName dirs
stackYaml = stackYamlFileName dirs stackYaml = stackYamlFileName dirs
@ -639,16 +636,6 @@ detectCompile dirs =
trace $ "XMonad will use stack ghc --stack-yaml " <> show canonStackYaml <> " to recompile." trace $ "XMonad will use stack ghc --stack-yaml " <> show canonStackYaml <> " to recompile."
pure $ CompileStackGhc canonStackYaml pure $ CompileStackGhc canonStackYaml
tryCabal = let cwd = cfgDir dirs in listCabalFiles cwd >>= \ case
[] -> do
empty
[name] -> do
trace $ "XMonad will use " <> show name <> " to recompile."
pure CompileCabal
_ : _ : _ -> do
trace $ "XMonad will not use cabal, because there are multiple cabal files in " <> show cwd <> "."
empty
useGhc = do useGhc = do
trace $ "XMonad will use ghc to recompile, because none of " trace $ "XMonad will use ghc to recompile, because none of "
<> intercalate ", " <> intercalate ", "
@ -656,20 +643,9 @@ detectCompile dirs =
, show stackYaml , show stackYaml
, show flakeNix , show flakeNix
, show defaultNix , show defaultNix
] <> " nor a suitable .cabal file exist." ] <> " exist."
pure CompileGhc pure CompileGhc
listCabalFiles :: FilePath -> IO [FilePath]
listCabalFiles dir = map (dir </>) . Prelude.filter isCabalFile <$> listFiles dir
isCabalFile :: FilePath -> Bool
isCabalFile file = case splitExtension file of
(name, ".cabal") -> not (null name)
_ -> False
listFiles :: FilePath -> IO [FilePath]
listFiles dir = getDirectoryContents dir >>= filterM (doesFileExist . (dir </>))
-- | Determine whether or not the file found at the provided filepath is executable. -- | Determine whether or not the file found at the provided filepath is executable.
isExecutable :: FilePath -> IO Bool isExecutable :: FilePath -> IO Bool
isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False) isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False)
@ -691,7 +667,6 @@ shouldCompile dirs CompileGhc = do
cs <- prep <$> E.catch (getDirectoryContents t) (\(SomeException _) -> return []) cs <- prep <$> E.catch (getDirectoryContents t) (\(SomeException _) -> return [])
ds <- filterM doesDirectoryExist cs ds <- filterM doesDirectoryExist cs
concat . ((cs \\ ds):) <$> mapM allFiles ds concat . ((cs \\ ds):) <$> mapM allFiles ds
shouldCompile _ CompileCabal = return True
shouldCompile dirs CompileStackGhc{} = do shouldCompile dirs CompileStackGhc{} = do
stackYamlT <- getModTime (stackYamlFileName dirs) stackYamlT <- getModTime (stackYamlFileName dirs)
binT <- getModTime (binFileName dirs) binT <- getModTime (binFileName dirs)
@ -711,17 +686,11 @@ compile :: Directories -> Compile -> IO ExitCode
compile dirs method = compile dirs method =
bracket_ uninstallSignalHandlers installSignalHandlers $ bracket_ uninstallSignalHandlers installSignalHandlers $
withFile (errFileName dirs) WriteMode $ \err -> do withFile (errFileName dirs) WriteMode $ \err -> do
let run = runProc err let run = runProc (cfgDir dirs) err
case method of case method of
CompileGhc -> do CompileGhc -> do
ghc <- fromMaybe "ghc" <$> lookupEnv "XMONAD_GHC" ghc <- fromMaybe "ghc" <$> lookupEnv "XMONAD_GHC"
run ghc ghcArgs run ghc ghcArgs
CompileCabal -> run "cabal" ["build"] .&&. copyBinary
where
copyBinary :: IO ExitCode
copyBinary = readProc err "cabal" ["-v0", "list-bin", "."] >>= \ case
Left status -> return status
Right (trim -> path) -> copyBinaryFrom path
CompileStackGhc stackYaml -> CompileStackGhc stackYaml ->
run "stack" ["build", "--silent", "--stack-yaml", stackYaml] .&&. run "stack" ["build", "--silent", "--stack-yaml", stackYaml] .&&.
run "stack" ("ghc" : "--stack-yaml" : stackYaml : "--" : ghcArgs) run "stack" ("ghc" : "--stack-yaml" : stackYaml : "--" : ghcArgs)
@ -732,10 +701,6 @@ compile dirs method =
CompileScript script -> CompileScript script ->
run script [binFileName dirs] run script [binFileName dirs]
where where
cwd :: FilePath
cwd = cfgDir dirs
ghcArgs :: [String]
ghcArgs = [ "--make" ghcArgs = [ "--make"
, "xmonad.hs" , "xmonad.hs"
, "-i" -- only look in @lib@ , "-i" -- only look in @lib@
@ -746,52 +711,26 @@ compile dirs method =
, "-outputdir", buildDirName dirs , "-outputdir", buildDirName dirs
, "-o", binFileName dirs , "-o", binFileName dirs
] ]
andCopyFromResultDir :: ExitCode -> IO ExitCode
andCopyFromResultDir exitCode = do andCopyFromResultDir exitCode = do
if exitCode == ExitSuccess then copyFromResultDir else return exitCode if exitCode == ExitSuccess then copyFromResultDir else return exitCode
findM :: (Monad m, Foldable t) => (a -> m Bool) -> t a -> m (Maybe a)
findM p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing) findM p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing)
catchAny :: IO a -> (SomeException -> IO a) -> IO a catchAny :: IO a -> (SomeException -> IO a) -> IO a
catchAny = E.catch catchAny = E.catch
copyFromResultDir :: IO ExitCode
copyFromResultDir = do copyFromResultDir = do
let binaryDirectory = cfgDir dirs </> "result" </> "bin" let binaryDirectory = cfgDir dirs </> "result" </> "bin"
binFiles <- map (binaryDirectory </>) <$> catchAny (listDirectory binaryDirectory) (\_ -> return []) binFiles <- map (binaryDirectory </>) <$> catchAny (listDirectory binaryDirectory) (\_ -> return [])
mfilepath <- findM isExecutable binFiles mfilepath <- findM isExecutable binFiles
case mfilepath of case mfilepath of
Just filepath -> copyBinaryFrom filepath Just filepath -> copyFile filepath (binFileName dirs) >> return ExitSuccess
Nothing -> return $ ExitFailure 1 Nothing -> return $ ExitFailure 1
copyBinaryFrom :: FilePath -> IO ExitCode
copyBinaryFrom filepath = copyFile filepath (binFileName dirs) >> return ExitSuccess
-- waitForProcess =<< System.Process.runProcess, but without closing the err handle -- waitForProcess =<< System.Process.runProcess, but without closing the err handle
runProc :: Handle -> String -> [String] -> IO ExitCode runProc cwd err exe args = do
runProc err exe args = do
(Nothing, Nothing, Nothing, h) <- createProcess_ "runProc" =<< mkProc err exe args
waitForProcess h
readProc :: Handle -> String -> [String] -> IO (Either ExitCode String)
readProc err exe args = do
spec <- mkProc err exe args
(Nothing, Just out, Nothing, h) <- createProcess_ "readProc" spec{ std_out = CreatePipe }
result <- hGetContents out
hPutStr err result >> hFlush err
waitForProcess h >>= \ case
ExitSuccess -> return $ Right result
status -> return $ Left status
mkProc :: Handle -> FilePath -> [FilePath] -> IO CreateProcess
mkProc err exe args = do
hPutStrLn err $ unwords $ "$" : exe : args hPutStrLn err $ unwords $ "$" : exe : args
hFlush err hFlush err
return (proc exe args){ cwd = Just cwd, std_err = UseHandle err } (_, _, _, h) <- createProcess_ "runProc" (proc exe args){ cwd = Just cwd, std_err = UseHandle err }
waitForProcess h
(.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode
cmd1 .&&. cmd2 = cmd1 >>= \case cmd1 .&&. cmd2 = cmd1 >>= \case
ExitSuccess -> cmd2 ExitSuccess -> cmd2
e -> pure e e -> pure e
@ -891,6 +830,3 @@ uninstallSignalHandlers = io $ do
installHandler openEndedPipe Default Nothing installHandler openEndedPipe Default Nothing
installHandler sigCHLD Default Nothing installHandler sigCHLD Default Nothing
return () return ()
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace

View File

@ -26,7 +26,7 @@ import qualified Data.Map as M
import qualified Data.Set as S import qualified Data.Set as S
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.State import Control.Monad.State
import Control.Monad (filterM, guard, unless, void, when, forever) import Control.Monad (filterM, guard, unless, void, when)
import Data.Maybe (fromMaybe, isJust) import Data.Maybe (fromMaybe, isJust)
import Data.Monoid (getAll) import Data.Monoid (getAll)
@ -248,10 +248,11 @@ launch initxmc drs = do
userCode $ startupHook initxmc userCode $ startupHook initxmc
rrData <- io $ xrrQueryExtension dpy rrData <- io $ xrrQueryExtension dpy
let rrUpdate = when (isJust rrData) . void . xrrUpdateConfiguration
-- main loop, for all you HOF/recursion fans out there. -- main loop, for all you HOF/recursion fans out there.
forever $ prehandle =<< io (nextEvent dpy e >> rrUpdate e >> getEvent e) -- forever $ prehandle =<< io (nextEvent dpy e >> rrUpdate e >> getEvent e)
-- sadly, 9.2.{1,2,3} join points mishandle the above and trash the heap (see #389)
mainLoop dpy e rrData
return () return ()
where where
@ -262,6 +263,8 @@ launch initxmc drs = do
in local (\c -> c { mousePosition = mouse, currentEvent = Just e }) (handleWithHook e) in local (\c -> c { mousePosition = mouse, currentEvent = Just e }) (handleWithHook e)
evs = [ keyPress, keyRelease, enterNotify, leaveNotify evs = [ keyPress, keyRelease, enterNotify, leaveNotify
, buttonPress, buttonRelease] , buttonPress, buttonRelease]
rrUpdate e r = when (isJust r) (void (xrrUpdateConfiguration e))
mainLoop d e r = io (nextEvent d e >> rrUpdate e r >> getEvent e) >>= prehandle >> mainLoop d e r
-- | Runs handleEventHook from the configuration and runs the default handler -- | Runs handleEventHook from the configuration and runs the default handler

View File

@ -64,8 +64,7 @@ x <&&> y = ifM x y (pure False)
(<||>) :: Monad m => m Bool -> m Bool -> m Bool (<||>) :: Monad m => m Bool -> m Bool -> m Bool
x <||> y = ifM x (pure True) y x <||> y = ifM x (pure True) y
-- | Return the window title; i.e., the string returned by @_NET_WM_NAME@, -- | Return the window title.
-- or failing that, the string returned by @WM_NAME@.
title :: Query String title :: Query String
title = ask >>= \w -> liftX $ do title = ask >>= \w -> liftX $ do
d <- asks display d <- asks display
@ -92,9 +91,7 @@ className :: Query String
className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w) className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w)
-- | A query that can return an arbitrary X property of type 'String', -- | A query that can return an arbitrary X property of type 'String',
-- identified by name. Works for ASCII strings only. For the properties -- identified by name.
-- @_NET_WM_NAME@/@WM_NAME@ and @WM_CLASS@ the specialised variants 'title'
-- and 'appName'/'className' are preferred.
stringProperty :: String -> Query String stringProperty :: String -> Query String
stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fromMaybe "" <$> getStringProperty d w p) stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fromMaybe "" <$> getStringProperty d w p)

View File

@ -1,5 +1,5 @@
name: xmonad name: xmonad
version: 0.18.0.9 version: 0.18.0
synopsis: A tiling window manager synopsis: A tiling window manager
description: xmonad is a tiling window manager for X. Windows are arranged description: xmonad is a tiling window manager for X. Windows are arranged
automatically to tile the screen without gaps or overlap, maximising automatically to tile the screen without gaps or overlap, maximising
@ -27,7 +27,7 @@ author: Spencer Janssen, Don Stewart, Adam Vogt, David Roundy, Jason
Ondřej Súkup, Paul Hebble, Shachaf Ben-Kiki, Siim Põder, Tim McIver, Ondřej Súkup, Paul Hebble, Shachaf Ben-Kiki, Siim Põder, Tim McIver,
Trevor Elliott, Wouter Swierstra, Conrad Irwin, Tim Thelion, Tony Zorman Trevor Elliott, Wouter Swierstra, Conrad Irwin, Tim Thelion, Tony Zorman
maintainer: xmonad@haskell.org maintainer: xmonad@haskell.org
tested-with: GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.8 || == 9.4.8 || == 9.6.7 || == 9.8.4 || == 9.10.2 || == 9.12.2 tested-with: GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.8 || == 9.4.8 || == 9.6.4 || == 9.8.1
category: System category: System
homepage: http://xmonad.org homepage: http://xmonad.org
bug-reports: https://github.com/xmonad/xmonad/issues bug-reports: https://github.com/xmonad/xmonad/issues
@ -65,7 +65,7 @@ library
XMonad.StackSet XMonad.StackSet
other-modules: Paths_xmonad other-modules: Paths_xmonad
hs-source-dirs: src hs-source-dirs: src
build-depends: base >= 4.12 && < 5 build-depends: base >= 4.11 && < 5
, X11 >= 1.10 && < 1.11 , X11 >= 1.10 && < 1.11
, containers , containers
, data-default-class , data-default-class