1
Fork 0
mirror of https://github.com/RGBCube/ncc synced 2025-07-31 12:07:48 +00:00

Compare commits

...

7 commits

Author SHA1 Message Date
b3af8158a7
darwin: do not remap tilde, do not enableKeyMapping
for some reason this turned '"' into '<', which is not good.

revert it all using:

  hidutil property --set '{"UserKeyMapping":[]}'

or:

  hidutil property --set '{"UserKeyMapping": [{"HIDKeyboardModifierMappingSrc":0x70000003e, "HIDKeyboardModifierMappingDst":0x70000003e}]}'
2025-07-26 03:45:37 +03:00
7f1381c474
darwin: more tinkering 2025-07-26 03:13:19 +03:00
6b94e1cea1
ssh: use hm lib 2025-07-26 03:09:19 +03:00
7f2a57a24d
paperwm: overhaul space change binds 2025-07-26 01:56:23 +03:00
3e466fcaf0
shell: fix aliases 2025-07-26 01:12:24 +03:00
f673d73cd2
shells: fix a lot of logic and use activation scripts 2025-07-26 00:44:24 +03:00
e759456954
modules.home-manager: always enable xdg 2025-07-25 23:12:33 +03:00
13 changed files with 294 additions and 160 deletions

View file

@ -1,6 +1,12 @@
{
{ lib, ... }: let
inherit (lib) enabled;
in {
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
sharedModules = [{
xdg = enabled {};
}];
};
}

View file

@ -1,66 +1,25 @@
{ config, lib, pkgs, ... }: let
inherit (lib) attrNames attrValues concatStringsSep const enabled filter filterAttrs flatten foldl' head last listToAttrs mapAttrs mapAttrsToList match nameValuePair readFile replaceStrings splitString;
inherit (lib) attrNames attrValues const enabled filterAttrs mapAttrs readFile replaceStrings;
package = pkgs.nushell;
in {
shells."0" = package;
home-manager.sharedModules = [(homeArgs: let
config' = homeArgs.config;
environmentVariables = let
variablesMap = {
HOME = config'.home.homeDirectory;
USER = config'.home.username;
XDG_CACHE_HOME = config'.xdg.cacheHome;
XDG_CONFIG_HOME = config'.xdg.configHome;
XDG_DATA_HOME = config'.xdg.dataHome;
XDG_STATE_HOME = config'.xdg.stateHome;
}
|> mapAttrsToList (name: value: [
{ name = "\$${name}"; inherit value; }
{ name = "\${${name}}"; inherit value; }
])
|> flatten
|> listToAttrs;
environmentVariables = config.environment.variables;
homeVariables = config'.home.sessionVariables;
homeVariablesExtra = pkgs.runCommand "home-variables-extra.env" {} ''
bash -ic '
${variablesMap
|> mapAttrsToList (name: value: "export ${name}='${value}'")
|> concatStringsSep "\n"}
alias export=echo
source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh
' > $out
''
|> readFile
|> splitString "\n"
|> filter (s: s != "")
|> map (match "([^=]+)=(.*)")
|> map (keyAndValue: nameValuePair (head keyAndValue) (last keyAndValue))
|> foldl' (x: y: x // y) {};
homeSearchVariables = config'.home.sessionSearchVariables
|> mapAttrs (const <| concatStringsSep ":");
in environmentVariables
// homeVariables
// homeVariablesExtra
// homeSearchVariables
|> mapAttrs (const <| replaceStrings (attrNames variablesMap) (attrValues variablesMap))
environmentVariables = config.environment.variables
|> mapAttrs (const <| replaceStrings (attrNames config'.variablesMap) (attrValues config'.variablesMap))
|> filterAttrs (name: const <| name != "TERM");
in {
shells."0" = package;
programs.nushell = enabled {
inherit package;
inherit (config.environment) shellAliases;
inherit environmentVariables;
shellAliases = config.environment.shellAliases
|> filterAttrs (_: value: value != null);
configFile.text = readFile ./0_nushell.nu;
};
})];

View file

@ -1,16 +1,78 @@
{ config, lib, ... }: let
inherit (lib) attrsToList catAttrs mkConst mkIf mkValue sortOn toInt;
{ config, lib, pkgs, ... }: let
inherit (lib) attrsToList catAttrs concatStringsSep const filter flatten foldl' getAttr getExe head last listToAttrs mapAttrs mapAttrsToList match mkConst mkIf mkValue nameValuePair readFile sortOn splitString toInt unique;
in {
options.shells = mkValue {};
environment.shells = config.home-manager.users
|> mapAttrsToList (const <| getAttr "shellsByPriority")
|> flatten
|> unique;
options.shellsByPriority = mkConst (config.shells
|> attrsToList
|> sortOn ({ name, ... }: toInt name)
|> catAttrs "value");
home-manager.sharedModules = [
config = mkIf config.isDarwin {
environment.shells = config.shellsByPriority;
};
(homeArgs: let
config' = homeArgs.config;
in {
options.shells = mkValue {};
options.shellsByPriority = mkConst (config'.shells
|> attrsToList
|> sortOn ({ name, ... }: toInt name)
|> catAttrs "value");
options.variablesMap = mkConst ({
HOME = config'.home.homeDirectory;
USER = config'.home.username;
XDG_CACHE_HOME = config'.xdg.cacheHome;
XDG_CONFIG_HOME = config'.xdg.configHome;
XDG_DATA_HOME = config'.xdg.dataHome;
XDG_STATE_HOME = config'.xdg.stateHome;
}
|> mapAttrsToList (name: value: [
{ name = "\$${name}"; inherit value; }
{ name = "\${${name}}"; inherit value; }
])
|> flatten
|> listToAttrs);
})
(mkIf config.isDarwin (homeArgs: let
config' = homeArgs.config;
homeSessionVariables = let
homeSessionVariables = config'.home.sessionVariables;
homeSessionVariablesExtra = pkgs.runCommand "home-variables-extra.env" {} ''
bash -ic '
${config'.variablesMap
|> mapAttrsToList (name: value: "export ${name}='${value}'")
|> concatStringsSep "\n"}
alias export=echo
source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh
' > $out
''
|> readFile
|> splitString "\n"
|> filter (s: s != "")
|> map (match "([^=]+)=(.*)")
|> map (keyAndValue: nameValuePair (head keyAndValue) (last keyAndValue))
|> foldl' (x: y: x // y) {};
homeSessionSearchVariables = config'.home.sessionSearchVariables
|> mapAttrs (const <| concatStringsSep ":");
in homeSessionVariables
// homeSessionVariablesExtra
// homeSessionSearchVariables;
in {
home.file.".zshrc".text = mkIf config.isDarwin /* zsh */ ''
${homeSessionVariables
|> mapAttrsToList (name: value: "export ${name}='${value}'")
|> concatStringsSep "\n"}
SHELL='${getExe <| head config'.shellsByPriority}' exec "$SHELL"
'';
}))
];
# More at modules/linux/shell/default.nix.
#

View file

@ -0,0 +1,78 @@
{ config, lib, pkgs, ... }: let
inherit (lib) getExe mkAfter mkIf;
in {
home-manager.sharedModules = mkIf config.isDarwin [(homeArgs: let
config' = homeArgs.config;
lib' = homeArgs.lib;
inherit (lib'.hm.dag) entryAfter;
# Replace with the command that has been triggering
# the "install developer tools" popup.
#
# Set by default to "SplitForks" because who even uses that?
originalTrigger = "/usr/bin/SplitForks";
originalTriggerLiteral = ''"${originalTrigger}"'';
# Where the symbolic links to `/usr/bin/false` will
# be created in to shadow all popup-triggering binaries.
#
# Place this in your $env.PATH right before /usr/bin
# to never get the "install developer tools" popup ever again:
#
# ```nu
# let usr_bin_index = $env.PATH
# | enumerate
# | where item == /usr/bin
# | get 0.index
#
# $env.PATH = $env.PATH | insert $usr_bin_index $shadow_path
# ```
#
# Do NOT set this to a path that you use for other things,
# it will get deleted if it exists to only have the shadowers.
shadowPath = "${config'.home.homeDirectory}/.local/shadow"; # Did you read the comment?
shadowPathLiteral = ''"${shadowPath}"'';
in {
home.activation.shadow = entryAfter [ "installPackages" "linkGeneration" ] /* bash */ ''
${getExe pkgs.nushell} ${pkgs.writeScript "shadow-xcode.nu" ''
use std null_device
let original_size = ls ${originalTriggerLiteral} | get 0.size
let shadoweds = ls /usr/bin
| flatten
| where {
# All xcode-select binaries are the same size, so we can narrow down and not run weird stuff.
$in.size == $original_size and (try {
open $null_device | ^$in.name out+err>| str contains "xcode-select: note: No developer tools were found, requesting install."
} catch {
# If it exited with a nonzero code, it's probably already set up.
false
})
}
| get name
| each { path basename }
rm -rf ${shadowPathLiteral}
mkdir ${shadowPathLiteral}
for shadowed in $shadoweds {
ln --symbolic /usr/bin/false (${shadowPathLiteral} | path join $shadowed)
}
''}
'';
programs.nushell.configFile.text = mkAfter /* nu */ ''
do --env {
let usr_bin_index = $env.PATH
| enumerate
| where item == /usr/bin
| get 0.index;
$env.PATH = $env.PATH
| insert $usr_bin_index ${shadowPathLiteral};
}
'';
})];
}

View file

@ -24,12 +24,14 @@ in {
mode = "444";
};
home-manager.sharedModules = [{
home.activation.createControlPath = {
after = [ "writeBoundary" ];
before = [];
data = "mkdir --parents ${controlPath}";
};
home-manager.sharedModules = [(homeArgs: let
lib' = homeArgs.lib;
inherit (lib'.hm.dag) entryAfter;
in {
home.activation.createControlPath = entryAfter [ "writeBoundary" ] /* bash */ ''
mkdir --parents ${controlPath}
'';
programs.ssh = enabled {
controlMaster = "auto";
@ -49,7 +51,7 @@ in {
};
};
};
}];
})];
environment.systemPackages = mkIf config.isDesktop [
pkgs.mosh

View file

@ -1,21 +1,38 @@
{
system.defaults.dock = {
autohide = true;
autohide = true;
showhidden = true; # Translucent.
mouse-over-hilite-stack = true;
show-recents = false;
mru-spaces = false;
tilesize = 48;
tilesize = 48;
magnification = false;
enable-spring-load-actions-on-all-items = true;
expose-animation-duration = 0.1;
persistent-apps = [
{ app = "/Applications/Zen.app"; }
{ app = "/Applications/Ghostty.app"; }
];
};
system.defaults.CustomSystemPreferences."com.apple.dock" = {
autohide-time-modifier = 0.0;
autohide-delay = 0.0;
expose-animation-duration = 0.0;
springboard-show-duration = 0.0;
springboard-hide-duration = 0.0;
springboard-page-duration = 0.0;
# Disable hot corners.
wvous-tl-corner = 0;
wvous-tr-corner = 0;
wvous-bl-corner = 0;
wvous-br-corner = 0;
launchanim = 0;
};
}

View file

@ -26,10 +26,32 @@
NewWindowTarget = "Home";
QuitMenuItem = true; # Allow quitting of Finder application
ShowExternalHardDrivesOnDesktop = true;
ShowMountedServersOnDesktop = true;
ShowPathbar = true;
ShowRemovableMediaOnDesktop = true;
ShowStatusBar = true;
};
system.defaults.CustomSystemPreferences."com.apple.finder" = {
DisableAllAnimations = true;
FXArrangeGroupViewBy = "Name";
FxDefaultSearchScope = "SCcf"; # Search in current folder by default.
WarnOnEmptyTrash = false;
};
home-manager.sharedModules = [(homeArgs: let
lib' = homeArgs.lib;
inherit (lib'.hm.dag) entryAfter;
in {
home.activation.showLibrary = entryAfter [ "writeBoundary" ] /* bash */ ''
# Unhide ~/Library.
/usr/bin/chflags nohidden ~/Library
'';
})];
}

View file

@ -1,8 +1,10 @@
{ config, lib, pkgs, ... }: let
inherit (lib) mkAfter mkIf;
inherit (lib) mkAfter;
in {
system.defaults.NSGlobalDomain = {
AppleInterfaceStyle = mkIf (lib.isDark config.theme) "Dark";
_HIHideMenuBar = true; # Automatically hide/show the menu bar.
AppleInterfaceStyle = if lib.isDark config.theme then "Dark" else null;
AppleScrollerPagingBehavior = true; # Jump to the spot that was pressed in the scrollbar.
AppleShowScrollBars = "WhenScrolling";
@ -12,16 +14,16 @@ in {
AppleEnableSwipeNavigateWithScrolls = false;
AppleWindowTabbingMode = "always"; # Always prefer tabs for new windows.
AppleKeyboardUIMode = 3; # Full keyboard access.
ApplePressAndHoldEnabled = false; # No ligatures when you press and hold a key, just repeat it.
AppleKeyboardUIMode = 3; # Full keyboard access.
ApplePressAndHoldEnabled = false; # No ligatures when you press and hold a key, just repeat it.
NSScrollAnimationEnabled = true;
NSWindowResizeTime = 0.001;
NSWindowResizeTime = 0.003;
"com.apple.keyboard.fnState" = false; # Don't invert Fn.
"com.apple.trackpad.scaling" = 1.5; # Faster mouse speed.
"com.apple.trackpad.scaling" = 1.5; # Faster mouse speed.
InitialKeyRepeat = 15;
InitialKeyRepeat = 12;
KeyRepeat = 1;
NSAutomaticCapitalizationEnabled = false;
@ -29,8 +31,15 @@ in {
NSAutomaticInlinePredictionEnabled = false;
NSAutomaticPeriodSubstitutionEnabled = false;
NSAutomaticQuoteSubstitutionEnabled = false;
NSNavPanelExpandedStateForSaveMode = true; # Expand save panel by default.
PMPrintingExpandedStateForPrint = true; # Expand print panel by default.
AppleSpacesSwitchOnActivate = false; # Do not switch workspaces implicitly.
};
system.defaults.CustomSystemPreferences."com.apple.dock".workspaces-auto-swoosh = false; # Read `AppleSpacesSwitchOnActivate`.
system.defaults.CustomSystemPreferences."com.apple.AppleMultitouchTrackpad" = {
TrackpadThreeFingerVertSwipeGesture = 0; # Four finger swipe up for mission control.
@ -106,7 +115,7 @@ in {
window:close()
end
local spaceChange = function(offset)
local currentSpaceIndex = function()
local current_space = hs.spaces.activeSpaceOnScreen()
local spaces = hs.spaces.allSpaces()[hs.screen.mainScreen():getUUID()]
@ -118,6 +127,13 @@ in {
end
end
return current_index
end
local changeSpaceBy = function(offset)
local current_index = currentSpaceIndex()
local spaces = hs.spaces.allSpaces()[hs.screen.mainScreen():getUUID()]
local next_index = current_index + offset
if next_index > #spaces then
next_index = 1
@ -125,11 +141,22 @@ in {
next_index = #spaces
end
if next_index == current_index then
return
end
local next_space = spaces[next_index]
hs.spaces.gotoSpace(next_space)
end
local gotoSpace = function(index)
local current_index = currentSpaceIndex()
local change_by = index - current_index
changeSpaceBy(change_by)
end
do -- HOTKEYS
local super = { "cmd", "ctrl" }
local super_alt = { "cmd", "ctrl", "alt" }
@ -161,12 +188,12 @@ in {
hs.hotkey.bind(super_alt, "f", PaperWM.actions.full_width)
-- CYCLE SPACES -- SUPER[ + SHIFT FOR REVERSE] + TAB
hs.hotkey.bind(super, "tab", function() spaceChange(1) end)
hs.hotkey.bind(super_shift, "tab", function() spaceChange(-1) end)
hs.hotkey.bind(super, "tab", function() changeSpaceBy(1) end)
hs.hotkey.bind(super_shift, "tab", function() changeSpaceBy(-1) end)
for index = 1, 9 do
-- GO TO SPACE -- SUPER + NUMBER
hs.hotkey.bind(super, tostring(index), PaperWM.actions["switch_space_" .. index])
hs.hotkey.bind(super, tostring(index), function() gotoSpace(index) end)
-- MOVE WINDOW TO SPACE -- SUPER + SHIFT + NUMBER
hs.hotkey.bind(super_shift, tostring(index), PaperWM.actions["move_window_" .. index])
@ -217,9 +244,9 @@ in {
threshold = math.huge -- only trigger once per swipe
if direction == "up" then
spaceChange(1)
changeSpaceBy(1)
elseif direction == "down" then
spaceChange(-1)
changeSpaceBy(-1)
end
end
end)
@ -249,7 +276,7 @@ in {
local button = hs.menubar.new()
button:setTitle(hs.styledtext.new(title, attributes))
button:setClickCallback(function()
hs.spaces.gotoSpace(space)
gotoSpace(space)
end)
table.insert(space_buttons, button)

View file

@ -0,0 +1,3 @@
{
system.defaults.screencapture.location = "~/Downloads";
}

View file

@ -0,0 +1,7 @@
{
system.defaults.CustomSystemPreferences."com.apple.screensaver" = {
# Request password immediately.
askForPassword = 1;
askForPasswordDelay = 0;
};
}

View file

@ -0,0 +1,6 @@
{
system.defaults.trackpad = {
Clicking = false; # No touch-to-click.
Dragging = false; # No tap-to-drag.
};
}

View file

@ -1,9 +1,20 @@
{ config, lib, pkgs, ... }: let
inherit (lib) concatStringsSep;
inherit (lib) concatStringsSep const flatten getAttr mapAttrsToList mkForce unique;
in {
users.defaultUserShell = pkgs.crash;
environment.sessionVariables.SHELLS = config.shellsByPriority
|> map (drv: "${drv}${drv.shellPath}")
|> concatStringsSep ":";
# TODO: This should be a per-user session variable. But we can't set
# a home-manager session variable because that's initialized by the
# shell itself! Lol.
environment.sessionVariables.SHELLS = config.home-manager.users
|> mapAttrsToList (const <| getAttr "shellsByPriority")
|> flatten
|> map (drv: "${drv}${drv.shellPath}")
|> unique
|> concatStringsSep ":";
environment.shellAliases = {
ls = mkForce null;
l = mkForce null;
};
}

View file

@ -17,7 +17,7 @@ def --wrapped sync [...arguments] {
# Rebuild a NixOS / Darwin config.
def main --wrapped [
host: string = "" # The host to build.
--remote (-r) # Whether if this is a remote host. The config will be built on this host if it is.
--remote # Whether if this is a remote host. The config will be built on this host if it is.
...arguments # The arguments to pass to `nh {os,darwin} switch` and `nix` (separated by --).
]: nothing -> nothing {
let host = if ($host | is-not-empty) {
@ -34,6 +34,10 @@ def main --wrapped [
}
if $remote {
ssh -tt ("root@" + $host) "
rm --recursive --force ncc
"
git ls-files
| sync --files-from - ./ $"root@($host):ncc"
@ -57,77 +61,7 @@ def main --wrapped [
if (uname | get kernel-name) == "Darwin" {
NH_BYPASS_ROOT_CHECK=true NH_NO_CHECKS=true nh darwin switch . ...$nh_flags -- ...$nix_flags
if not (xcode-select --install e>| str contains "Command line tools are already installed") {
darwin-shadow-xcode-popup
}
darwin-set-zshrc
} else {
NH_BYPASS_ROOT_CHECK=true NH_NO_CHECKS=true nh os switch . ...$nh_flags -- ...$nix_flags
}
}
# Replace with the command that has been triggering
# the "install developer tools" popup.
#
# Set by default to "SplitForks" because who even uses that?
const original_trigger = "/usr/bin/SplitForks"
# Where the symbolic links to `/usr/bin/false` will
# be created in to shadow all popup-triggering binaries.
#
# Place this in your $env.PATH right before /usr/bin
# to never get the "install developer tools" popup ever again:
#
# ```nu
# let usr_bin_index = $env.PATH
# | enumerate
# | where item == /usr/bin
# | get 0.index
#
# $env.PATH = $env.PATH | insert $usr_bin_index $shadow_path
# ```
#
# Do NOT set this to a path that you use for other things,
# it will get deleted if it exists to only have the shadowers.
const shadow_path = "~/.local/shadow" | path expand # Did you read the comment?
def darwin-shadow-xcode-popup [] {
print "shadowing xcode popup binaries..."
let original_size = ls $original_trigger | get 0.size
let shadoweds = ls /usr/bin
| flatten
| where {
# All xcode-select binaries are the same size, so we can narrow down and not run weird stuff.
$in.size == $original_size
}
| where {
^$in.name e>| str contains "xcode-select: note: No developer tools were found, requesting install."
}
| get name
| each { path basename }
rm -rf $shadow_path
mkdir $shadow_path
for shadowed in $shadoweds {
let shadow_path = $shadow_path | path join $shadowed
ln --symbolic /usr/bin/false $shadow_path
}
}
def darwin-set-zshrc [] {
print "setting zshrc..."
let nu_command = $"let usr_bin_index = $env.PATH | enumerate | where item == /usr/bin | get 0.index;
$env.PATH = $env.PATH | insert $usr_bin_index ($shadow_path | path expand);
$env.SHELL = which nu | get 0.path" | str replace --all "\n" ""
let zshrc = $"exec nu --execute '($nu_command)'"
$zshrc | save --force ~/.zshrc
}