Compare commits

..

No commits in common. "fe746e014a3cb94a3d86a2231430dd3aacd44375" and "3063b4e06a6fb8ec286cfe15e89be88c5f2e5e89" have entirely different histories.

2 changed files with 93 additions and 191 deletions

155
CLAUDE.md
View file

@ -1,155 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
This is a personal XMonad + Xmobar configuration built as a Haskell project using Nix flakes. The project uses Relude as a custom Prelude and follows a strict, opinionated Haskell development workflow.
## Build System
This project uses **just** for task running and **Nix flakes** for reproducible builds:
```bash
# List available commands
just
# Build the project
just build
# Run XMonad executable
just run xmonad
# Run XMobar executable
just run xmobar
# Start REPL
just repl
# Access Hoogle documentation (serves at http://127.0.0.1:8888)
just docs
```
### Nix Commands
```bash
# Update flake inputs
nix flake update
# Build all outputs
nix --accept-flake-config run github:juspay/omnix ci
# Run without installing
nix run .
# Enter development shell (or use direnv)
nix develop
```
### Pre-commit Hooks
Pre-commit hooks are automatically configured in the Nix shell and include:
- **fourmolu** for Haskell formatting (with FOURMOLU_DISABLE/ENABLE pragmas where needed)
- **nixpkgs-fmt** for Nix formatting
- **hlint** for Haskell linting
Run manually: `pre-commit run -a`
## Project Structure
The repository follows a standard Cabal package layout:
- **`src/xmonad.hs`** - Main XMonad configuration (executable entry point)
- **`src/xmobar.hs`** - XMobar status bar configuration (executable entry point)
- **`src/XMonadConfig/GruvboxMaterial.hs`** - Shared color scheme module providing xmobar escape codes
### Two Executables
The project builds two separate executables defined in `xmonad-config.cabal`:
1. **xmonad** - The window manager configuration
2. **xmobar** - The status bar configuration
Both share the `XMonadConfig.GruvboxMaterial` module for consistent theming.
## Architecture
### XMonad Configuration (`src/xmonad.hs`)
The configuration is built compositionally using function application:
```haskell
main = xmonad
. docks
. ewmhFullscreen
. ewmh
. withNavigation2DConfig def
. withSB myXmobar
$ myConfig
```
**Key architectural components:**
- **Navigation2D**: Directional window and screen navigation using arrow keys and Navigation2D module
- **Custom keybindings**: Leader-key approach (`M-a` prefix) for spawning applications and layout switching
- **Window manipulation**: Uses `XMonad.Actions.RotSlaves` for window rotation (mimics wezterm behavior)
- **Layout system**: Three layouts - dynamic tiling, maximised, and fullscreen
- **StatusBar integration**: Communicates with xmobar via `_XMONAD_LOG_1` X property
- **Mnemonic bindings**: Control (M-C) for layout manipulation, Shift (M-S) for window operations
### XMobar Configuration (`src/xmobar.hs`)
Defines a status bar with:
- System information (uname, uptime, disk usage)
- Weather data (station YPJT)
- Date/time
- XMonad workspace/layout information from `_XMONAD_LOG_1` property
The bar is positioned statically for a multi-monitor setup (positioned at x=1920).
### Color Scheme Module
`XMonadConfig.GruvboxMaterial` exports color functions that wrap strings in xmobar color escape codes. This ensures consistent theming across both XMonad and XMobar configurations.
## Haskell Configuration
### Custom Prelude
Uses **Relude** instead of standard Prelude, configured in `xmonad-config.cabal`:
```cabal
mixins:
base hiding (Prelude),
relude (Relude as Prelude, Relude.Container.One),
relude
```
### Default Extensions
The following extensions are enabled project-wide:
- DataKinds, DerivingStrategies, DerivingVia
- LambdaCase, MultiWayIf, NoStarIsType
- OverloadedStrings, StrictData, TypeFamilies, ViewPatterns
### GHC Options
Strict compilation with extensive warnings:
- `-Wall`
- `-Wincomplete-record-updates`, `-Wincomplete-uni-patterns`
- `-Wmissing-deriving-strategies`, `-Wunused-foralls`
- `-fprint-explicit-foralls`, `-fprint-explicit-kinds`
## Development Workflow
1. The project uses **haskell-flake** via flake-parts for Haskell package management
2. HLS (Haskell Language Server) is available but checks are disabled in devShell (`hlsCheck.enable = false`)
3. Static analysis via **stan** is enabled for the xmonad-config package
4. The project filters `projectRoot` in `nix/modules/flake/haskell.nix` to avoid unnecessary rebuilds
## Key Dependencies
- **xmonad**, **xmonad-contrib** - Core window manager libraries
- **xmobar** - Status bar library
- **relude** - Alternative Prelude
- **optics-core** - For lens-style accessors
- **data-default** - Default instances for configuration

View file

@ -1,17 +1,21 @@
import Data.List as L
import Data.Map qualified as M
import XMonad
import XMonad.Actions.CycleWS
import XMonad.Actions.Navigation2D
import XMonad.Actions.RotSlaves
import XMonad.Actions.Submap
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.Modal
import XMonad.Hooks.StatusBar
import XMonad.Layout.BinarySpacePartition
import XMonad.Layout.NoBorders
import XMonad.Layout.Renamed
import XMonad.Layout.Spacing
import XMonad.StackSet qualified as W
import XMonad.Util.EZConfig
import XMonad.Util.Font
import XMonad.Util.Loggers
import Graphics.X11.ExtraTypes.XF86
@ -29,7 +33,8 @@ main = xmonad
. docks
. ewmhFullscreen
. ewmh
. withNavigation2DConfig def
. withNavigation2DConfig def
. modal [editMode]
. withSB myXmobar
$ myConfig
@ -72,20 +77,24 @@ myKeymap =
-- spawning programs
[ ("M-a n", spawn myTerminal )
, ("M-a e", spawn myLauncher )
, ("M-a t", spawn myFileManager)
, ("M-a f", spawn myFileManager)
, ("M-a s", spawn myScrot )
-- toggling layouts
, ("M-a d", sendMessage $ JumpToLayout "dynamic tiling")
, ("M-a m", sendMessage $ JumpToLayout "maximised" )
, ("M-a f", sendMessage $ JumpToLayout "fullscreen" )
-- quit window
, ("M-a q", kill)
-- toggling layouts
, ("M-a <Backspace> t", sendMessage $ JumpToLayout "dynamic tiling" )
, ("M-a <Backspace> b", sendMessage $ JumpToLayout "binary space partition")
, ("M-a <Backspace> m", sendMessage $ JumpToLayout "maximised" )
, ("M-a <Backspace> f", sendMessage $ JumpToLayout "fullscreen" )
-- enable modal modes
, ("M-a m e", setMode "edit")
--
-- Layout Navigation
-- Modifier Keys
--
-- directional navigation of windows
@ -94,22 +103,16 @@ myKeymap =
, ("M-<Down>" , windowGo D False)
, ("M-<Right>" , windowGo R False)
-- swap adjacent windows
, ("M-S-<Up>" , windowSwap U False)
, ("M-S-<Left>" , windowSwap L False)
, ("M-S-<Down>" , windowSwap D False)
, ("M-S-<Right>", windowSwap R False)
-- cycle windows
, ("M-<Page_Up>" , windows W.focusUp )
, ("M-<Page_Down>", windows W.focusDown)
-- window rotation
, ("M-C-<Page_Up>", rotAllUp)
, ("M-C-<Page_Down>", rotAllDown)
-- cycle workspaces
, ("M-<Home>", moveTo Prev hiddenWS)
, ("M-<End>" , moveTo Next hiddenWS)
-- focus screens (directional)
, ("M-C-<Home>", screenGo L False) -- focus left monitor
, ("M-C-<End>", screenGo R False) -- focus right monitor
-- switch workspaces
, ("M-1", windows $ W.greedyView "code" )
, ("M-2", windows $ W.greedyView "chat" )
@ -117,6 +120,10 @@ myKeymap =
, ("M-4", windows $ W.greedyView "games")
, ("M-5", windows $ W.greedyView "misc" )
-- cycle workspaces
, ("M-<Home>", moveTo Prev hiddenWS)
, ("M-<End>" , moveTo Next hiddenWS)
-- send window to workspace
, ("M-S-1", windows $ W.shift "code" )
, ("M-S-2", windows $ W.shift "chat" )
@ -124,16 +131,6 @@ myKeymap =
, ("M-S-4", windows $ W.shift "games")
, ("M-S-5", windows $ W.shift "misc" )
-- master pane manipulation
, ("M-C-<Left>", sendMessage Shrink) -- control layout: shrink master
, ("M-C-<Right>", sendMessage Expand) -- control layout: expand master
, ("M-S-<Left>", sendMessage (IncMasterN (-1))) -- shift windows: fewer in master
, ("M-S-<Right>", sendMessage (IncMasterN 1)) -- shift windows: more in master
-- master window operations
, ("M-<Delete>", windows W.focusMaster)
, ("M-S-<Delete>", windows W.swapMaster)
--
-- Multimedia
@ -148,16 +145,73 @@ myKeymap =
]
--
-- Modal keybindings
--
editMode :: Mode
editMode = mode "edit" $ mkKeysEz
--
-- Navigation2D / DynamicTiling
--
-- directional navigation of windows
[ ("o", windowGo U False)
, ("n", windowGo L False)
, ("e", windowGo D False)
, ("i", windowGo R False)
-- swap adjacent windows
, ("S-o", windowSwap U False)
, ("S-n", windowSwap L False)
, ("S-e", windowSwap D False)
, ("S-i", windowSwap R False)
-- shrink/expand the master area
, ("f", sendMessage Shrink)
, ("u", sendMessage Expand)
-- number of windows in the master area
, ("S-f", sendMessage (IncMasterN 1) )
, ("S-u", sendMessage (IncMasterN (-1)))
--
-- BinarySpacePartition
--
-- expand windows
, ("M-o", sendMessage $ ExpandTowardsBy U 0.01)
, ("M-n", sendMessage $ ExpandTowardsBy L 0.01)
, ("M-e", sendMessage $ ExpandTowardsBy D 0.01)
, ("M-i", sendMessage $ ExpandTowardsBy R 0.01)
-- shrink windows
, ("M-M1-o", sendMessage $ ShrinkFromBy U 0.01)
, ("M-M1-n", sendMessage $ ShrinkFromBy L 0.01)
, ("M-M1-e", sendMessage $ ShrinkFromBy D 0.01)
, ("M-M1-i", sendMessage $ ShrinkFromBy R 0.01)
-- swap/rotate
, ("M-r", sendMessage Rotate)
, ("M-s", sendMessage Swap )
-- split shift
, ("M-f", sendMessage $ SplitShift Prev)
, ("M-u", sendMessage $ SplitShift Next)
]
--
-- Layouts
--
myLayouts = myTile ||| myMax ||| myFull
myLayouts = myTile ||| myBsp ||| myMax ||| myFull
where
-- our layouts
myTile = renamed [Replace "dynamic tiling"] . avoidStruts . myGaps $ Tall nmaster delta ratio
myMax = renamed [Replace "maximised" ] . avoidStruts . myGaps $ Full
myFull = renamed [Replace "fullscreen" ] . noBorders $ Full
myTile = renamed [Replace "dynamic tiling" ] . avoidStruts . myGaps $ Tall nmaster delta ratio
myBsp = renamed [Replace "binary space partition"] . avoidStruts . myGaps $ emptyBSP
myMax = renamed [Replace "maximised" ] . avoidStruts . myGaps $ Full
myFull = renamed [Replace "fullscreen" ] . noBorders $ Full
-- add a configurable amount of space around windows.
myGaps = spacingRaw False (Border 10 10 10 10) True (Border 10 10 10 10) True
-- layout configuration
@ -182,8 +236,11 @@ myXmobarPP = def
, ppHiddenNoWindows = grey0 . wrap " " ""
, ppUrgent = red . wrap " " ""
, ppLayout = aqua . wrap (grey0 " <fn=1>[</fn> ") (grey0 " <fn=1>]</fn> ")
, ppOrder = \[ws, l, _] -> [ws, l]
, ppOrder = \case { [ws, l, title, mode] -> [ws, l, mode, title]; xs -> xs }
, ppExtras = [lMode]
}
where
lMode = xmobarColorL "#d8a657" "#282828" . fixedWidthL AlignCenter "-" 4 $ logMode
--