Merge branch 'experimental'

This commit is contained in:
Noah Masur
2022-06-20 09:23:26 -04:00
255 changed files with 4237 additions and 4485 deletions

View File

@ -0,0 +1,10 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
unfreePackages = [ "1password" "_1password-gui" ];
home-manager.users.${config.user} = {
home.packages = with pkgs; [ _1password-gui ];
};
};
}

View File

@ -0,0 +1,83 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
home-manager.users.${config.user} = {
xsession.windowManager.i3.config.terminal = "alacritty";
programs.rofi.terminal = "${pkgs.alacritty}/bin/alacritty";
programs.alacritty = {
enable = true;
settings = {
window = {
dimensions = {
columns = 85;
lines = 30;
};
padding = {
x = 20;
y = 20;
};
opacity = 1.0;
};
scrolling.history = 10000;
font = { size = 14.0; };
key_bindings = [
{
key = "L";
mods = "Control|Shift";
chars = "\\x1F";
}
{
key = "K";
mods = "Control";
mode = "~Vi";
action = "ToggleViMode";
}
{
key = "Return";
mode = "Vi";
action = "ToggleViMode";
}
# Used to enable $ keybind in Vi mode
{
key = 5; # Scancode for key4
mods = "Shift";
mode = "Vi|~Search";
action = "Last";
}
];
colors = {
primary = {
background = config.gui.colorscheme.base00;
foreground = config.gui.colorscheme.base05;
};
cursor = {
text = "#1d2021";
cursor = config.gui.colorscheme.base05;
};
normal = {
black = "#1d2021";
red = config.gui.colorscheme.base08;
green = config.gui.colorscheme.base0B;
yellow = config.gui.colorscheme.base0A;
blue = config.gui.colorscheme.base0D;
magenta = config.gui.colorscheme.base0E;
cyan = config.gui.colorscheme.base0C;
white = config.gui.colorscheme.base05;
};
bright = {
black = config.gui.colorscheme.base03;
red = config.gui.colorscheme.base09;
green = config.gui.colorscheme.base01;
yellow = config.gui.colorscheme.base02;
blue = config.gui.colorscheme.base04;
magenta = config.gui.colorscheme.base06;
cyan = config.gui.colorscheme.base0F;
white = config.gui.colorscheme.base07;
};
};
draw_bold_text_with_bright_colors = false;
};
};
};
};
}

View File

@ -0,0 +1,10 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
home-manager.users.${config.user} = {
home.packages = with pkgs; [ calibre ];
# home.sessionVariables = { CALIBRE_USE_DARK_PALETTE = 1; };
};
environment.sessionVariables = { CALIBRE_USE_DARK_PALETTE = "1"; };
};
}

View File

@ -0,0 +1,15 @@
{ ... }: {
imports = [
./1password.nix
./alacritty.nix
./calibre.nix
./discord.nix
./firefox.nix
./media.nix
./obsidian.nix
./qbittorrent.nix
./nautilus.nix
];
}

View File

@ -0,0 +1,19 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
unfreePackages = [ "discord" ];
home-manager.users.${config.user} = {
home.packages = with pkgs; [ discord ];
xdg.configFile."discord/settings.json".text = ''
{
"BACKGROUND_COLOR": "#202225",
"IS_MAXIMIZED": false,
"IS_MINIMIZED": false,
"OPEN_ON_STARTUP": false,
"MINIMIZE_TO_TRAY": false,
"SKIP_HOST_UPDATE": true
}
'';
};
};
}

View File

@ -0,0 +1,121 @@
{ config, pkgs, lib, ... }:
{
config = lib.mkIf config.gui.enable {
unfreePackages = [ "onepassword-password-manager" "okta-browser-plugin" ];
home-manager.users.${config.user} = {
programs.firefox = {
enable = true;
extensions = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
vimium
multi-account-containers
facebook-container
temporary-containers
onepassword-password-manager
okta-browser-plugin
sponsorblock
reddit-enhancement-suite
bypass-paywalls-clean
markdownload
darkreader
snowflake
don-t-fuck-with-paste
i-dont-care-about-cookies
];
profiles.Profile0 = {
id = 0;
name = "default";
isDefault = true;
settings = {
"browser.aboutConfig.showWarning" = false;
"browser.warnOnQuit" = false;
"browser.theme.dark-private-windows" = true;
"browser.toolbars.bookmarks.visibility" = "newtab";
"browser.startup.page" = 3; # Restore previous session
"browser.newtabpage.enabled" = false; # Make new tabs blank
"general.autoScroll" = true; # Drag middle-mouse to scroll
"services.sync.prefs.sync.general.autoScroll" =
false; # Prevent disabling autoscroll
"extensions.pocket.enabled" = false;
"toolkit.legacyUserProfileCustomizations.stylesheets" =
true; # Allow userChrome.css
"layout.css.color-mix.enabled" = true;
};
userChrome = ''
:root {
--focus-outline-color: ${config.gui.colorscheme.base04} !important;
--toolbar-color: ${config.gui.colorscheme.base07} !important;
--tab-min-height: 30px !important;
}
/* Background of tab bar */
.toolbar-items {
background-color: ${config.gui.colorscheme.base00} !important;
}
/* Tabs themselves */
.tabbrowser-tab .tab-stack {
border-radius: 5px 5px 0 0;
overflow: hidden;
background-color: ${config.gui.colorscheme.base00};
color: ${config.gui.colorscheme.base06} !important;
}
.tab-content {
border-bottom: 2px solid color-mix(in srgb, var(--identity-tab-color) 40%, transparent);
border-radius: 5px 5px 0 0;
background-color: ${config.gui.colorscheme.base00};
color: ${config.gui.colorscheme.base06} !important;
}
.tab-content[selected=true] {
border-bottom: 2px solid color-mix(in srgb, var(--identity-tab-color) 25%, transparent);
background-color: ${config.gui.colorscheme.base01} !important;
color: ${config.gui.colorscheme.base07} !important;
}
/* Below tab bar */
#nav-bar {
background: ${config.gui.colorscheme.base01} !important;
}
/* URL bar in nav bar */
#urlbar[focused=true] {
color: ${config.gui.colorscheme.base07} !important;
background: ${config.gui.colorscheme.base02} !important;
caret-color: ${config.gui.colorscheme.base05} !important;
}
#urlbar:not([focused=true]) {
color: ${config.gui.colorscheme.base04} !important;
background: ${config.gui.colorscheme.base02} !important;
}
#urlbar ::-moz-selection {
color: ${config.gui.colorscheme.base07} !important;
background: ${config.gui.colorscheme.base02} !important;
}
#urlbar-input-container {
border: 1px solid ${config.gui.colorscheme.base01} !important;
}
#urlbar-background {
background: ${config.gui.colorscheme.base01} !important;
}
/* Text in URL bar */
#urlbar-input, #urlbar-scheme, .searchbar-textbox {
color: ${config.gui.colorscheme.base07} !important;
}
'';
userContent = ''
@-moz-document url-prefix(about:blank) {
* {
background-color:${config.gui.colorscheme.base01} !important;
}
}
'';
extraConfig = "";
};
};
};
};
}

View File

@ -1,6 +0,0 @@
{ config, ... }: {
config = {
services.keybase.enable = true;
services.kbfs.enable = true;
};
}

View File

@ -0,0 +1,11 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
home-manager.users.${config.user}.home.packages = with pkgs; [
mpv # Video viewer
sxiv # Image viewer
mupdf # PDF viewer
];
};
}

View File

@ -0,0 +1,13 @@
{ config, pkgs, lib, ... }: {
# Install Nautilus file manager
config = lib.mkIf config.gui.enable {
home-manager.users.${config.user} = {
home.packages = with pkgs; [
gnome.nautilus
gnome.sushi # Quick preview with spacebar
];
};
};
}

View File

@ -0,0 +1,10 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
unfreePackages = [ "obsidian" ];
home-manager.users.${config.user} = {
home.packages = with pkgs; [ obsidian ];
};
};
}

View File

@ -0,0 +1,12 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
home-manager.users.${config.user} = {
home.packages = with pkgs; [ qbittorrent ];
};
};
}

View File

@ -0,0 +1,20 @@
{
name = "everforest"; # dark, hard
author = "Sainnhe Park";
base00 = "#2b3339"; # Default Background
base01 = "#323c41"; # Lighter Background
base02 = "#503946"; # Selection Background
base03 = "#868d80"; # Comments, Invisibles, Line Highlighting
base04 = "#d3c6aa"; # Dark Foreground (Used for status bars)
base05 = "#d3c6aa"; # Default Foreground, Caret, Delimiters, Operators
base06 = "#e9e8d2"; # Light Foreground (Not often used)
base07 = "#fff9e8"; # Light Background (Not often used)
base08 = "#7fbbb3"; # Variables, XML Tags, Markup Link Text, ...
base09 = "#d699b6"; # Integers, Boolean, Constants, ...
base0A = "#83c092"; # Classes, Markup Bold, Search Text Background
base0B = "#dbbc7f"; # Strings, Inherited Class, Markup Code, Diff Inserted
base0C = "#e69875"; # Support, Regular Expressions, Escape Characters, ...
base0D = "#a7c080"; # Functions, Methods, Attribute IDs, Headings
base0E = "#e67e80"; # Keywords, Storage, Selector, Markup Italic, Diff Changed
base0F = "#d699b6"; # Deprecated, Opening/Closing Embedded Language Tags, ...
}

View File

@ -0,0 +1,21 @@
{
name = "gruvbox"; # Dark, Medium
author =
"Dawid Kurek (dawikur@gmail.com), morhetz (https://github.com/morhetz/gruvbox)";
base00 = "#282828"; # ----
base01 = "#3c3836"; # ---
base02 = "#504945"; # --
base03 = "#665c54"; # -
base04 = "#bdae93"; # +
base05 = "#d5c4a1"; # ++
base06 = "#ebdbb2"; # +++
base07 = "#fbf1c7"; # ++++
base08 = "#fb4934"; # red
base09 = "#fe8019"; # orange
base0A = "#fabd2f"; # yellow
base0B = "#b8bb26"; # green
base0C = "#8ec07c"; # aqua/cyan
base0D = "#83a598"; # blue
base0E = "#d3869b"; # purple
base0F = "#d65d0e"; # brown
}

View File

@ -0,0 +1,20 @@
{
name = "nord";
author = "arcticicestudio";
base00 = "#2E3440";
base01 = "#3B4252";
base02 = "#434C5E";
base03 = "#4C566A";
base04 = "#D8DEE9";
base05 = "#E5E9F0";
base06 = "#ECEFF4";
base07 = "#8FBCBB";
base08 = "#88C0D0";
base09 = "#81A1C1";
base0A = "#5E81AC";
base0B = "#BF616A";
base0C = "#D08770";
base0D = "#EBCB8B";
base0E = "#A3BE8C";
base0F = "#B48EAD";
}

View File

@ -0,0 +1,23 @@
{ config, pkgs, lib, ... }: {
# MacOS-specific settings for Alacritty
home-manager.users.${config.user} = {
programs.alacritty.settings = {
font.size = lib.mkForce 20.0;
shell.program = "${pkgs.fish}/bin/fish";
key_bindings = [
{
key = "F";
mods = "Super";
action = "ToggleSimpleFullscreen";
}
{
key = "L";
mods = "Super";
chars = "\\x1F";
}
];
};
};
}

View File

@ -0,0 +1,15 @@
{ ... }: {
imports = [
./alacritty.nix
./dotfiles.nix
./fonts.nix
./hammerspoon.nix
./homebrew.nix
./system.nix
./tmux.nix
./user.nix
./utilities.nix
];
}

View File

@ -0,0 +1,28 @@
{ config, ... }: {
home-manager.users.${config.user} = {
programs.fish = {
shellAbbrs = {
nr = lib.mkForce "rebuild-darwin";
nro = lib.mkForce "rebuild-darwin offline";
};
functions = {
rebuild-darwin = {
body = ''
if test "$argv[1]" = "offline"
set option "--option substitute false"
end
pushd ${config.dotfilesPath}
git add --all
popd
commandline -r "darwin-rebuild switch $option --flake ${config.dotfilesPath}#macbook"
commandline -f execute
'';
};
};
};
};
}

14
modules/darwin/fonts.nix Normal file
View File

@ -0,0 +1,14 @@
{ config, pkgs, ... }: {
home-manager.users.${config.user} = {
home.packages = with pkgs;
[ (nerdfonts.override { fonts = [ "FiraCode" ]; }) ];
programs.alacritty.settings = {
font.normal.family = "FiraCode Nerd Font Mono";
};
};
}

View File

@ -0,0 +1,15 @@
{ config, ... }: {
# Hammerspoon - MacOS custom automation scripting
home-manager.users.${config.user} = {
xdg.configFile.hammerspoon = { source = ./hammerspoon; };
};
homebrew.casks = [ "hammerspoon" ];
system.activationScripts.hammerspoon.text = ''
defaults write org.hammerspoon.Hammerspoon MJConfigFile "~/.config/hammerspoon/init.lua"
'';
}

View File

@ -0,0 +1,120 @@
--- === ControlEscape ===
---
--- Adapted very loosely from https://github.com/jasonrudolph/ControlEscape.spoon
--- Removed timing/delay; always send Escape as well as Control
---
--- Make the `control` key more useful: If the `control` key is tapped, treat it
--- as the `escape` key. If the `control` key is held down and used in
--- combination with another key, then provide the normal `control` key
--- behavior.
local obj={}
obj.__index = obj
-- Metadata
obj.name = 'ControlEscape'
obj.version = '0.1'
obj.author = 'Jason Rudolph <jason@jasonrudolph.com>'
obj.homepage = 'https://github.com/jasonrudolph/ControlEscape.spoon'
obj.license = 'MIT - https://opensource.org/licenses/MIT'
function obj:init()
self.movements = 0
self.sendEscape = false
self.lastModifiers = {}
-- Create an eventtap to run each time the modifier keys change (i.e., each
-- time a key like control, shift, option, or command is pressed or released)
self.controlTap = hs.eventtap.new({hs.eventtap.event.types.flagsChanged},
function(event)
local newModifiers = event:getFlags()
-- If this change to the modifier keys does not involve a *change* to the
-- up/down state of the `control` key (i.e., it was up before and it's
-- still up, or it was down before and it's still down), then don't take
-- any action.
if self.lastModifiers['ctrl'] == newModifiers['ctrl'] then
return false
end
-- Control was not down but is now
if not self.lastModifiers['ctrl'] then
-- Only prepare to send escape if no other modifier keys are in use
self.lastModifiers = newModifiers
if (not self.lastModifiers['cmd'] and not self.lastModifiers['alt']) then
self.sendEscape = true
self.movements = 0
end
-- Control was down and is up, hasn't been blocked by another key, and
-- isn't above the movement threshold
elseif (self.sendEscape == true and not newModifiers['ctrl'] and self.movements < 30) then
self.lastModifiers = newModifiers
-- Allow for shift-escape
if newModifiers['shift'] then
hs.eventtap.keyStroke({'shift'}, 'escape', 0)
else
hs.eventtap.keyStroke(newModifiers, 'escape', 0)
end
self.sendEscape = false
self.movements = 0
self.numberOfCharacters = 0
-- Control was down and is up, but isn't ready to send escape
else
self.lastModifiers = newModifiers
end
end
)
-- If any other key is pressed, don't send escape
self.asModifier = hs.eventtap.new({hs.eventtap.event.types.keyDown},
function(event)
self.sendEscape = false
end
)
-- If mouse is moving significantly, don't send escape
self.scrolling = hs.eventtap.new({hs.eventtap.event.types.gesture},
function(event)
local touches = event:getTouches()
local i, v = next(touches, nil)
while i do
if v["phase"] == "moved" then
-- Increment the movement counter
self.movements = self.movements + 1
end
i, v = next(touches, i) -- get next index
end
end
)
end
--- ControlEscape:start()
--- Method
--- Start sending `escape` when `control` is pressed and released in isolation
function obj:start()
self.controlTap:start()
self.asModifier:start()
self.scrolling:start()
end
--- ControlEscape:stop()
--- Method
--- Stop sending `escape` when `control` is pressed and released in isolation
function obj:stop()
-- Stop monitoring keystrokes
self.controlTap:stop()
self.asModifier:stop()
self.scrolling:stop()
-- Reset state
self.sendEscape = false
self.lastModifiers = {}
end
return obj

View File

@ -0,0 +1,298 @@
/* Credit: https://gist.github.com/lancethomps/a5ac103f334b171f70ce2ff983220b4f */
function run(input, parameters) {
const appNames = [];
const skipAppNames = [];
const verbose = true;
const scriptName = "close_notifications_applescript";
const CLEAR_ALL_ACTION = "Clear All";
const CLEAR_ALL_ACTION_TOP = "Clear";
const CLOSE_ACTION = "Close";
const notNull = (val) => {
return val !== null && val !== undefined;
};
const isNull = (val) => {
return !notNull(val);
};
const notNullOrEmpty = (val) => {
return notNull(val) && val.length > 0;
};
const isNullOrEmpty = (val) => {
return !notNullOrEmpty(val);
};
const isError = (maybeErr) => {
return notNull(maybeErr) && (maybeErr instanceof Error || maybeErr.message);
};
const systemVersion = () => {
return Application("Finder").version().split(".").map(val => parseInt(val));
};
const systemVersionGreaterThanOrEqualTo = (vers) => {
return systemVersion()[0] >= vers;
};
const isBigSurOrGreater = () => {
return systemVersionGreaterThanOrEqualTo(11);
};
const V11_OR_GREATER = isBigSurOrGreater();
const APP_NAME_MATCHER_ROLE = V11_OR_GREATER ? "AXStaticText" : "AXImage";
const hasAppNames = notNullOrEmpty(appNames);
const hasSkipAppNames = notNullOrEmpty(skipAppNames);
const hasAppNameFilters = hasAppNames || hasSkipAppNames;
const appNameForLog = hasAppNames ? ` [${appNames.join(",")}]` : "";
const logs = [];
const log = (message, ...optionalParams) => {
let message_with_prefix = `${new Date().toISOString().replace("Z", "").replace("T", " ")} [${scriptName}]${appNameForLog} ${message}`;
console.log(message_with_prefix, optionalParams);
logs.push(message_with_prefix);
};
const logError = (message, ...optionalParams) => {
if (isError(message)) {
let err = message;
message = `${err}${err.stack ? (" " + err.stack) : ""}`;
}
log(`ERROR ${message}`, optionalParams);
};
const logErrorVerbose = (message, ...optionalParams) => {
if (verbose) {
logError(message, optionalParams);
}
};
const logVerbose = (message) => {
if (verbose) {
log(message);
}
};
const getLogLines = () => {
return logs.join("\n");
};
const getSystemEvents = () => {
let systemEvents = Application("System Events");
systemEvents.includeStandardAdditions = true;
return systemEvents;
};
const getNotificationCenter = () => {
try {
return getSystemEvents().processes.byName("NotificationCenter");
} catch (err) {
logError("Could not get NotificationCenter");
throw err;
}
};
const getNotificationCenterGroups = (retryOnError = false) => {
try {
let notificationCenter = getNotificationCenter();
if (notificationCenter.windows.length <= 0) {
return [];
}
if (!V11_OR_GREATER) {
return notificationCenter.windows();
}
return notificationCenter.windows[0].uiElements[0].uiElements[0].uiElements();
} catch (err) {
logError("Could not get NotificationCenter groups");
if (retryOnError) {
logError(err);
log("Retrying getNotificationCenterGroups...");
return getNotificationCenterGroups(false);
} else {
throw err;
}
}
};
const isClearButton = (description, name) => {
return description === "button" && name === CLEAR_ALL_ACTION_TOP;
};
const matchesAnyAppNames = (value, checkValues) => {
if (isNullOrEmpty(checkValues)) {
return false;
}
let lowerAppName = value.toLowerCase();
for (let checkValue of checkValues) {
if (lowerAppName === checkValue.toLowerCase()) {
return true;
}
}
return false;
};
const matchesAppName = (role, value) => {
if (role !== APP_NAME_MATCHER_ROLE) {
return false;
}
if (hasAppNames) {
return matchesAnyAppNames(value, appNames);
}
return !matchesAnyAppNames(value, skipAppNames);
};
const notificationGroupMatches = (group) => {
try {
let description = group.description();
if (V11_OR_GREATER && isClearButton(description, group.name())) {
return true;
}
if (V11_OR_GREATER && description !== "group") {
return false;
}
if (!V11_OR_GREATER) {
let matchedAppName = !hasAppNameFilters;
if (!matchedAppName) {
for (let elem of group.uiElements()) {
if (matchesAppName(elem.role(), elem.description())) {
matchedAppName = true;
break;
}
}
}
if (matchedAppName) {
return notNull(findCloseActionV10(group, -1));
}
return false;
}
if (!hasAppNameFilters) {
return true;
}
let firstElem = group.uiElements[0];
return matchesAppName(firstElem.role(), firstElem.value());
} catch (err) {
logErrorVerbose(`Caught error while checking window, window is probably closed: ${err}`);
logErrorVerbose(err);
}
return false;
};
const findCloseActionV10 = (group, closedCount) => {
try {
for (let elem of group.uiElements()) {
if (elem.role() === "AXButton" && elem.title() === CLOSE_ACTION) {
return elem.actions["AXPress"];
}
}
} catch (err) {
logErrorVerbose(`(group_${closedCount}) Caught error while searching for close action, window is probably closed: ${err}`);
logErrorVerbose(err);
return null;
}
log("No close action found for notification");
return null;
};
const findCloseAction = (group, closedCount) => {
try {
if (!V11_OR_GREATER) {
return findCloseActionV10(group, closedCount);
}
let checkForPress = isClearButton(group.description(), group.name());
let clearAllAction;
let closeAction;
for (let action of group.actions()) {
let description = action.description();
if (description === CLEAR_ALL_ACTION) {
clearAllAction = action;
break;
} else if (description === CLOSE_ACTION) {
closeAction = action;
} else if (checkForPress && description === "press") {
clearAllAction = action;
break;
}
}
if (notNull(clearAllAction)) {
return clearAllAction;
} else if (notNull(closeAction)) {
return closeAction;
}
} catch (err) {
logErrorVerbose(`(group_${closedCount}) Caught error while searching for close action, window is probably closed: ${err}`);
logErrorVerbose(err);
return null;
}
log("No close action found for notification");
return null;
};
const closeNextGroup = (groups, closedCount) => {
try {
for (let group of groups) {
if (notificationGroupMatches(group)) {
let closeAction = findCloseAction(group, closedCount);
if (notNull(closeAction)) {
try {
closeAction.perform();
return [true, 1];
} catch (err) {
logErrorVerbose(`(group_${closedCount}) Caught error while performing close action, window is probably closed: ${err}`);
logErrorVerbose(err);
}
}
return [true, 0];
}
}
return false;
} catch (err) {
logError("Could not run closeNextGroup");
throw err;
}
};
try {
let groupsCount = getNotificationCenterGroups(true).filter(group => notificationGroupMatches(group)).length;
if (groupsCount > 0) {
logVerbose(`Closing ${groupsCount}${appNameForLog} notification group${(groupsCount > 1 ? "s" : "")}`);
let startTime = new Date().getTime();
let closedCount = 0;
let maybeMore = true;
let maxAttempts = 2;
let attempts = 1;
while (maybeMore && ((new Date().getTime() - startTime) <= (1000 * 30))) {
try {
let closeResult = closeNextGroup(getNotificationCenterGroups(), closedCount);
maybeMore = closeResult[0];
if (maybeMore) {
closedCount = closedCount + closeResult[1];
}
} catch (innerErr) {
if (maybeMore && closedCount === 0 && attempts < maxAttempts) {
log(`Caught an error before anything closed, trying ${maxAttempts - attempts} more time(s).`)
attempts++;
} else {
throw innerErr;
}
}
}
} else {
throw Error(`No${appNameForLog} notifications found...`);
}
} catch (err) {
logError(err);
logError(err.message);
getLogLines();
throw err;
}
return getLogLines();
}

View File

@ -0,0 +1,17 @@
--- === Dismiss Alerts ===
local obj = {}
obj.__index = obj
-- Metadata
obj.name = "DismissAlerts"
obj.version = "0.1"
obj.license = "MIT - https://opensource.org/licenses/MIT"
function obj:init()
hs.hotkey.bind({ "cmd", "alt", "ctrl" }, "k", function()
hs.osascript.javascriptFromFile("Spoons/DismissAlerts.spoon/close_notifications_applescript.js")
end)
end
return obj

View File

@ -0,0 +1,110 @@
--- === Launcher ===
local obj = {}
obj.__index = obj
-- Metadata
obj.name = "Launcher"
obj.version = "0.1"
obj.license = "MIT - https://opensource.org/licenses/MIT"
function drawSwitcher()
-- Drawing
width = hs.screen.mainScreen():fullFrame().w
switcherWidth = 500
canv = hs.canvas.new({
x = width / 2 - switcherWidth / 2,
y = 1,
h = 3,
w = switcherWidth,
})
canv[#canv + 1] = {
action = "build",
type = "rectangle",
}
canv[#canv + 1] = {
type = "rectangle",
fillColor = { alpha = 1, red = 0.8, green = 0.6, blue = 0.3 },
action = "fill",
}
return canv:show()
end
function obj:init()
-- Begin launcher mode
if self.launcher == nil then
self.launcher = hs.hotkey.modal.new("ctrl", "space")
end
-- Behaviors on enter
function self.launcher:entered()
-- hs.alert("Entered mode")
self.canv = drawSwitcher()
end
-- Behaviors on exit
function self.launcher:exited()
-- hs.alert("Exited mode")
self.canv:hide()
end
-- Use escape to exit launcher mode
self.launcher:bind("", "escape", function()
self.launcher:exit()
end)
-- Launcher shortcuts
self.launcher:bind("ctrl", "space", function() end)
self.launcher:bind("", "space", function()
hs.hints.windowHints()
self.launcher:exit()
end)
self.launcher:bind("", "return", function()
self:switch("Alacritty.app")
end)
self.launcher:bind("", "C", function()
self:switch("Calendar.app")
end)
self.launcher:bind("", "D", function()
self:switch("Discord.app")
end)
self.launcher:bind("", "E", function()
self:switch("Mail.app")
end)
self.launcher:bind("", "U", function()
self:switch("Music.app")
end)
self.launcher:bind("", "F", function()
self:switch("Firefox.app")
end)
self.launcher:bind("", "H", function()
self:switch("Hammerspoon.app")
end)
self.launcher:bind("", "G", function()
self:switch("Mimestream.app")
end)
self.launcher:bind("", "M", function()
self:switch("Messages.app")
end)
self.launcher:bind("", "O", function()
self:switch("Obsidian.app")
end)
self.launcher:bind("", "P", function()
self:switch("System Preferences.app")
end)
self.launcher:bind("", "R", function()
hs.reload()
end)
self.launcher:bind("", "S", function()
self:switch("Slack.app")
end)
self.launcher:bind("", "Z", function()
self:switch("zoom.us.app")
end)
end
function obj:switch(app)
hs.application.launchOrFocus(app)
self.launcher:exit()
end
return obj

View File

@ -0,0 +1,40 @@
--- === Move Window ===
local obj = {}
obj.__index = obj
-- Metadata
obj.name = "MoveWindow"
obj.version = "0.1"
obj.license = "MIT - https://opensource.org/licenses/MIT"
function obj:init()
-- bind hotkey
hs.hotkey.bind({ "alt", "ctrl", "cmd" }, "n", function()
-- get the focused window
local win = hs.window.focusedWindow()
-- get the screen where the focused window is displayed, a.k.a. current screen
local screen = win:screen()
-- local nextScreen = screen:next()
-- compute the unitRect of the focused window relative to the current screen
-- and move the window to the next screen setting the same unitRect
win:moveToScreen(screen:next(), true, true, 0)
end)
hs.hotkey.bind({ "alt", "ctrl", "cmd" }, "b", function()
local win = hs.window.focusedWindow()
local screen = win:screen()
win:moveToScreen(screen:previous(), true, true, 0)
end)
hs.hotkey.bind({ "alt", "ctrl", "cmd" }, "m", function()
-- get the focused window
local win = hs.window.focusedWindow()
-- maximize if possible
for i = 1, 8 do
win:maximize()
end
end)
end
return obj

View File

@ -0,0 +1,4 @@
hs.loadSpoon("ControlEscape"):start() -- Load Hammerspoon bits from https://github.com/jasonrudolph/ControlEscape.spoon
hs.loadSpoon("Launcher"):init()
hs.loadSpoon("DismissAlerts"):init()
hs.loadSpoon("MoveWindow"):init()

View File

@ -0,0 +1,51 @@
{ config, ... }: {
# Homebrew - Mac-specific packages that aren't in Nix
# Requires Homebrew to be installed (works if you rebuild twice)
homebrew = {
enable = true;
autoUpdate = false; # Don't update during rebuild
cleanup = "zap"; # Uninstall all programs not declared
taps = [
"homebrew/cask" # Required for casks
"homebrew/cask-drivers" # Used for Logitech G-Hub
];
brews = [
"trash" # Delete files and folders to trash instead of rm
];
casks = [
"firefox" # Firefox packaging on Nix is broken for MacOS
"1password" # 1Password packaging on Nix is broken for MacOS
"scroll-reverser" # Different scroll style for mouse vs. trackpad
"meetingbar" # Show meetings in menu bar
"gitify" # Git notifications in menu bar
"logitech-g-hub" # Mouse and keyboard management
"mimestream" # Gmail client
"obsidian" # Obsidian packaging on Nix is not available for MacOS
];
global.brewfile = true; # Run brew bundle from anywhere
global.noLock = true; # Don't save lockfile (since running from anywhere)
};
home-manager.users.${config.user} = {
home.activation = {
# Always install homebrew if it doesn't exist
installHomeBrew =
config.home-manager.users.${config.user}.lib.dag.entryAfter
[ "writeBoundary" ] ''
if ! xcode-select --version 2>/dev/null; then
$DRY_RUN_CMD xcode-select --install
fi
if ! /usr/local/bin/brew --version 2>/dev/null; then
$DRY_RUN_CMD /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
'';
};
};
}

View File

@ -0,0 +1,8 @@
{ ... }: {
networking = {
computerName = "MacBook"; # Host name
hostName = "MacBook";
};
}

175
modules/darwin/system.nix Normal file
View File

@ -0,0 +1,175 @@
{ ... }: {
services.nix-daemon.enable = true;
system = {
keyboard = {
remapCapsLockToControl = true;
enableKeyMapping = true; # Allows for skhd
};
defaults = {
NSGlobalDomain = {
# Set to dark mode
AppleInterfaceStyle = "Dark";
# Don't change from dark to light automatically
# AppleInterfaceSwitchesAutomatically = false;
# Enable full keyboard access for all controls (e.g. enable Tab in modal dialogs)
AppleKeyboardUIMode = 3;
# Automatically show and hide the menu bar
_HIHideMenuBar = true;
# Expand save panel by default
NSNavPanelExpandedStateForSaveMode = true;
# Expand print panel by default
PMPrintingExpandedStateForPrint = true;
# Replace press-and-hold with key repeat
ApplePressAndHoldEnabled = false;
# Set a fast key repeat rate
KeyRepeat = 2;
# Shorten delay before key repeat begins
InitialKeyRepeat = 12;
# Save to local disk by default, not iCloud
NSDocumentSaveNewDocumentsToCloud = false;
# Disable autocorrect capitalization
NSAutomaticCapitalizationEnabled = false;
# Disable autocorrect smart dashes
NSAutomaticDashSubstitutionEnabled = false;
# Disable autocorrect adding periods
NSAutomaticPeriodSubstitutionEnabled = false;
# Disable autocorrect smart quotation marks
NSAutomaticQuoteSubstitutionEnabled = false;
# Disable autocorrect spellcheck
NSAutomaticSpellingCorrectionEnabled = false;
};
dock = {
# Automatically show and hide the dock
autohide = true;
# Add translucency in dock for hidden applications
showhidden = true;
# Enable spring loading on all dock items
enable-spring-load-actions-on-all-items = true;
# Highlight hover effect in dock stack grid view
mouse-over-hilite-stack = true;
mineffect = "genie";
orientation = "bottom";
show-recents = false;
tilesize = 44;
};
finder = {
# Default Finder window set to column view
FXPreferredViewStyle = "clmv";
# Finder search in current folder by default
FXDefaultSearchScope = "SCcf";
# Disable warning when changing file extension
FXEnableExtensionChangeWarning = false;
# Allow quitting of Finder application
QuitMenuItem = true;
};
# Disable "Are you sure you want to open" dialog
LaunchServices.LSQuarantine = false;
# Disable trackpad tap to click
trackpad.Clicking = false;
# universalaccess = {
# # Zoom in with Control + Scroll Wheel
# closeViewScrollWheelToggle = true;
# closeViewZoomFollowsFocus = true;
# };
# Where to save screenshots
screencapture.location = "~/Downloads";
};
# Settings that don't have an option in nix-darwin
activationScripts.postActivation.text = ''
echo "Disable disk image verification"
defaults write com.apple.frameworks.diskimages skip-verify -bool true
defaults write com.apple.frameworks.diskimages skip-verify-locked -bool true
defaults write com.apple.frameworks.diskimages skip-verify-remote -bool true
echo "Avoid creating .DS_Store files on network volumes"
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
echo "Disable the warning before emptying the Trash"
defaults write com.apple.finder WarnOnEmptyTrash -bool false
echo "Require password immediately after sleep or screen saver begins"
defaults write com.apple.screensaver askForPassword -int 1
defaults write com.apple.screensaver askForPasswordDelay -int 0
echo "Show the ~/Library folder"
chflags nohidden ~/Library
echo "Enable dock magnification"
defaults write com.apple.dock magnification -bool true
echo "Set dock magnification size"
defaults write com.apple.dock largesize -int 48
echo "Choose and order dock icons"
__dock_item() {
printf '%s%s%s%s%s' \
'<dict><key>tile-data</key><dict><key>file-data</key><dict>' \
'<key>_CFURLString</key><string>' \
"$1" \
'</string><key>_CFURLStringType</key><integer>0</integer>' \
'</dict></dict></dict>'
}
defaults write com.apple.dock persistent-apps -array \
"$(__dock_item /Applications/1Password.app)" \
"$(__dock_item /Applications/Slack.app)" \
"$(__dock_item /System/Applications/Calendar.app)" \
"$(__dock_item /Applications/Firefox.app)" \
"$(__dock_item /System/Applications/Messages.app)" \
"$(__dock_item /System/Applications/Mail.app)" \
"$(__dock_item /Applications/Mimestream.app)" \
"$(__dock_item /Applications/zoom.us.app)" \
"$(__dock_item /Applications/Obsidian.app)" \
"$(__dock_item /Applications/Alacritty.app)" \
"$(__dock_item /System/Applications/System\ Preferences.app)"
echo "Allow apps from anywhere"
SPCTL=$(spctl --status)
if ! [ "$SPCTL" = "assessments disabled" ]
then
sudo spctl --master-disable
fi
echo "Show the ~/Library folder"
chflags nohidden ~/Library
'';
};
}

125
modules/darwin/tmux.nix Normal file
View File

@ -0,0 +1,125 @@
{ config, pkgs, ... }: {
home-manager.users.${config.user} = {
programs.tmux = {
enable = true;
baseIndex = 1; # Start windows and panes at 1
escapeTime = 0; # Wait time after escape is input
historyLimit = 100000;
keyMode = "vi";
newSession = true; # Automatically spawn new session
plugins = [ ];
resizeAmount = 10;
shell = "${pkgs.fish}/bin/fish";
terminal = "screen-256color";
extraConfig = ''
# Horizontal and vertical splits
bind \\ split-window -h -c '#{pane_current_path}'
bind - split-window -v -c '#{pane_current_path}'
# Move between panes with vi keys
bind h select-pane -L
bind j select-pane -D
bind K select-pane -U
bind l select-pane -R
# Split out pane
bind b break-pane
# Synchronize panes
bind S set-window-option synchronize-panes
# Copy mode works as Vim
bind Escape copy-mode
bind k copy-mode
bind C-[ copy-mode
# Use v to trigger selection
bind-key -T copy-mode-vi v send-keys -X begin-selection
# Use y to yank current selection
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
# Enable mouse mode
set -g mouse on
# Status bar
set -g status-interval 60 # Seconds between refreshes
set -g renumber-windows on
set-option -g status-position bottom
## COLORSCHEME: gruvbox dark
set-option -g status "on"
# Default statusbar color
set-option -g status-style bg=colour237,fg=colour223 # bg=bg1, fg=fg1
# Default window title colors
set-window-option -g window-status-style bg=colour214,fg=colour237 # bg=yellow, fg=bg1
# Default window with an activity alert
set-window-option -g window-status-activity-style bg=colour237,fg=colour248 # bg=bg1, fg=fg3
# Active window title colors
set-window-option -g window-status-current-style bg=red,fg=colour237 # fg=bg1
# Pane border
set-option -g pane-active-border-style fg=colour250 #fg2
set-option -g pane-border-style fg=colour237 #bg1
# Message infos
set-option -g message-style bg=colour239,fg=colour223 # bg=bg2, fg=fg1
# Writing commands inactive
set-option -g message-command-style bg=colour239,fg=colour223 # bg=fg3, fg=bg1
# Pane number display
set-option -g display-panes-active-colour colour250 #fg2
set-option -g display-panes-colour colour237 #bg1
# Clock
set-window-option -g clock-mode-colour colour109 #blue
# Bell
set-window-option -g window-status-bell-style bg=colour167,fg=colour235 # bg=red, fg=bg
# Theme settings mixed with colors (unfortunately, but there is no cleaner way)
set-option -g status-justify "left"
set-option -g status-left-style none
set-option -g status-left-length "80"
set-option -g status-right-style none
set-option -g status-right-length "80"
set-window-option -g window-status-separator ""
set-option -g status-left "#[fg=colour248, bg=colour241] #S #[fg=colour241, bg=colour237, nobold, noitalics, nounderscore]"
set-option -g status-right "#[fg=colour239, bg=colour237, nobold, nounderscore, noitalics]#[fg=colour246,bg=colour239] %Y-%m-%d %H:%M #[fg=colour248, bg=colour239, nobold, noitalics, nounderscore]"
set-window-option -g window-status-current-format "#[fg=colour237, bg=colour214, nobold, noitalics, nounderscore]#[fg=colour239, bg=colour214] #I #[fg=colour239, bg=colour214, bold] #W #[fg=colour214, bg=colour237, nobold, noitalics, nounderscore]"
set-window-option -g window-status-format "#[fg=colour237,bg=colour239,noitalics]#[fg=colour223,bg=colour239] #I #[fg=colour223, bg=colour239] #W #[fg=colour239, bg=colour237, noitalics]"
'';
};
programs.alacritty.settings = {
shell.args = [
"--login"
"--init-command"
"tmux attach-session -t noah || tmux new-session -s noah"
];
key_bindings = [
{
key = "H";
mods = "Super|Shift";
chars = "\\x02p"; # Previous tmux window
}
{
key = "L";
mods = "Super|Shift";
chars = "\\x02n"; # Next tmux window
}
];
};
};
}

8
modules/darwin/user.nix Normal file
View File

@ -0,0 +1,8 @@
{ config, pkgs, lib, ... }: {
users.users."${config.user}" = { # macOS user
home = config.homePath;
shell = pkgs.zsh; # Default shell
};
}

View File

@ -0,0 +1,21 @@
{ config, pkgs, ... }: {
home-manager.users.${config.user} = {
home.packages = with pkgs; [
visidata # CSV inspector
dos2unix # Convert Windows text files
inetutils # Includes telnet
youtube-dl # Convert web videos
pandoc # Convert text documents
mpd # TUI slideshows
awscli2
awslogs
kubectl
k9s
noti # Create notifications programmatically
];
};
}

View File

@ -0,0 +1,5 @@
{ ... }: {
imports = [ ./neovim ./notes.nix ./dotfiles.nix ];
}

View File

@ -0,0 +1,42 @@
{ config, pkgs, lib, ... }: {
home-manager.users.${config.user} = {
home.activation = {
# Always clone dotfiles repository if it doesn't exist
cloneDotfiles =
config.home-manager.users.${config.user}.lib.dag.entryAfter
[ "writeBoundary" ] ''
if [ ! -d "${config.dotfilesPath}" ]; then
$DRY_RUN_CMD mkdir --parents $VERBOSE_ARG $(dirname "${config.dotfilesPath}")
$DRY_RUN_CMD ${pkgs.git}/bin/git clone ${config.dotfilesRepo} "${config.dotfilesPath}"
fi
'';
};
programs.fish = {
shellAbbrs = {
nr = "rebuild-nixos";
nro = "rebuild-nixos offline";
};
functions = {
rebuild-nixos = {
body = ''
if test "$argv[1]" = "offline"
set option "--option substitute false"
end
pushd ${config.dotfilesPath}
git add --all
popd
commandline -r "doas nixos-rebuild switch $option --flake ${config.dotfilesPath}"
commandline -f execute
'';
};
};
};
};
}

View File

@ -0,0 +1,13 @@
-- Bootstrap the Packer plugin manager
local fn = vim.fn
local install_path = fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim"
if fn.empty(fn.glob(install_path)) > 0 then
packer_bootstrap = fn.system({
"git",
"clone",
"--depth",
"1",
"https://github.com/wbthomason/packer.nvim",
install_path,
})
end

View File

@ -0,0 +1,11 @@
-- Colorscheme
use({
"morhetz/gruvbox",
config = function()
vim.g.gruvbox_italic = 1
vim.cmd([[
autocmd ColorScheme * highlight Normal ctermbg=NONE guibg=NONE
colorscheme gruvbox
]])
end,
})

View File

@ -0,0 +1,87 @@
-- =======================================================================
-- Completion System
-- =======================================================================
-- Completion sources
use("hrsh7th/cmp-nvim-lsp") --- Language server completion plugin
use("hrsh7th/cmp-buffer") --- Generic text completion
use("hrsh7th/cmp-path") --- Local file completion
use("hrsh7th/cmp-cmdline") --- Command line completion
use("hrsh7th/cmp-nvim-lua") --- Nvim lua api completion
use("saadparwaiz1/cmp_luasnip") --- Luasnip completion
use("lukas-reineke/cmp-rg") --- Ripgrep completion
-- Completion engine
use({
"hrsh7th/nvim-cmp",
requires = { "L3MON4D3/LuaSnip" },
config = function()
local cmp = require("cmp")
cmp.setup({
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
mapping = {
["<C-d>"] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }),
["<C-f>"] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }),
["<Esc>"] = function(fallback)
cmp.mapping({
i = cmp.mapping.abort(),
c = cmp.mapping.close(),
})
vim.cmd("stopinsert") --- Abort and leave insert mode
end,
-- ['<Tab>'] = cmp.mapping(cmp.mapping.select_next_item(), { 'i', 's' }),
-- ['<S-Tab>'] = cmp.mapping(cmp.mapping.select_prev_item(), { 'i', 's' }),
["<CR>"] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Insert,
select = true,
}),
["<C-r>"] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}),
["<C-l>"] = cmp.mapping(function(fallback)
if require("luasnip").expand_or_jumpable() then
require("luasnip").expand_or_jump()
end
end, { "i", "s" }),
},
sources = {
{ name = "nvim_lua" },
{ name = "nvim_lsp" },
{ name = "path" },
{ name = "luasnip" },
{ name = "buffer", keyword_length = 3, max_item_count = 10 },
{
name = "rg",
keyword_length = 6,
max_item_count = 10,
option = { additional_arguments = "--ignore-case" },
},
},
experimental = {
native_menu = false, --- Use cmp menu instead of Vim menu
ghost_text = true, --- Show preview auto-completion
},
})
-- Use buffer source for `/`
cmp.setup.cmdline("/", {
sources = {
{ name = "buffer", keyword_length = 5 },
},
})
-- Use cmdline & path source for ':'
cmp.setup.cmdline(":", {
sources = cmp.config.sources({
{ name = "path" },
}, {
{ name = "cmdline" },
}),
})
end,
})

View File

@ -0,0 +1,63 @@
{ config, pkgs, lib, ... }: {
home-manager.users.${config.user} = {
home.packages = with pkgs; [
neovim
gcc # for tree-sitter
];
xdg.configFile = {
"nvim/init.lua".text = lib.mkMerge [
(lib.mkOrder 100 ''
${builtins.readFile ./bootstrap.lua}
require("packer").startup(function(use)
${builtins.readFile ./packer-basics.lua}
'')
(lib.mkOrder 200 ''
${builtins.readFile ./colors.lua}
'')
(lib.mkOrder 300 ''
${builtins.readFile ./lsp.lua}
'')
(lib.mkOrder 400 ''
${builtins.readFile ./completion.lua}
'')
(lib.mkOrder 500 ''
${builtins.readFile ./syntax.lua}
'')
(lib.mkOrder 600 ''
${builtins.readFile ./telescope.lua}
'')
(lib.mkOrder 700 ''
${builtins.readFile ./packer-sync.lua}
end)
'')
(lib.mkOrder 800 ''
${builtins.readFile ./settings.lua}
${builtins.readFile ./functions.lua}
${builtins.readFile ./keybinds.lua}
'')
];
};
programs.git.extraConfig.core.editor = "nvim";
home.sessionVariables = {
EDITOR = "nvim";
MANPAGER = "nvim +Man!";
};
programs.fish = {
shellAliases = { vim = "nvim"; };
shellAbbrs = {
v = lib.mkForce "nvim";
vl = lib.mkForce "nvim -c 'normal! `0'";
vll = "nvim -c 'Telescope oldfiles'";
};
};
};
# Used for icons in Vim
fonts.fonts = with pkgs; [ nerdfonts ];
}

View File

@ -0,0 +1,49 @@
-- ===========================================================================
-- Custom Functions
-- ===========================================================================
grep_notes = function()
local opts = {
prompt_title = "Search Notes",
cwd = "$NOTES_PATH",
}
require("telescope.builtin").live_grep(opts)
end
find_notes = function()
local opts = {
prompt_title = "Find Notes",
cwd = "$NOTES_PATH",
}
require("telescope.builtin").find_files(opts)
end
find_downloads = function()
local opts = {
prompt_title = "Find Downloads",
cwd = "~/downloads",
}
require("telescope").extensions.file_browser.file_browser(opts)
end
choose_project = function()
local opts = require("telescope.themes").get_ivy({
layout_config = {
bottom_pane = {
height = 10,
},
},
})
require("telescope").extensions.project.project(opts)
end
command_history = function()
local opts = require("telescope.themes").get_ivy({
layout_config = {
bottom_pane = {
height = 15,
},
},
})
require("telescope.builtin").command_history(opts)
end

View File

@ -0,0 +1,121 @@
-- ===========================================================================
-- Key Mapping
-- ===========================================================================
-- Function to cut down config boilerplate
local key = function(mode, key_sequence, action, params)
params = params or {}
params["noremap"] = true
vim.api.nvim_set_keymap(mode, key_sequence, action, params)
end
-- Remap space as leader key
key("", "<Space>", "<Nop>", { silent = true })
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Keep selection when changing indentation
key("v", "<", "<gv")
key("v", ">", ">gv")
-- Clear search register
key("n", "<CR>", ":noh<CR><CR>", { silent = true })
-- Shuffle lines around
key("n", "<A-j>", ":m .+1<CR>==")
key("n", "<A-k>", ":m .-2<CR>==")
key("i", "<A-j>", "<Esc>:m .+1<CR>==gi")
key("i", "<A-k>", "<Esc>:m .-2<CR>==gi")
key("v", "<A-j>", ":m '>+1<CR>gv=gv")
key("v", "<A-k>", ":m '<-2<CR>gv=gv")
-- Telescope (fuzzy finder)
key("n", "<Leader>k", ":Telescope keymaps<CR>")
key("n", "<Leader>/", ":Telescope live_grep<CR>")
key("n", "<Leader>ff", ":Telescope find_files<CR>")
key("n", "<Leader>fp", ":Telescope git_files<CR>")
key("n", "<Leader>fN", "<Cmd>lua find_notes()<CR>")
key("n", "<Leader>N", "<Cmd>lua grep_notes()<CR>")
key("n", "<Leader>fD", "<Cmd>lua find_downloads()<CR>")
key("n", "<Leader>fa", ":Telescope file_browser<CR>")
key("n", "<Leader>fw", ":Telescope grep_string<CR>")
key("n", "<Leader>wt", ":Telescope tmux sessions<CR>")
key("n", "<Leader>ww", ":Telescope tmux windows<CR>")
key("n", "<Leader>w/", ":Telescope tmux pane_contents<CR>")
key("n", "<Leader>fz", ":Telescope zoxide list<CR>")
key("n", "<Leader>b", ":Telescope buffers<CR>")
key("n", "<Leader>hh", ":Telescope help_tags<CR>")
key("n", "<Leader>fr", ":Telescope oldfiles<CR>")
key("n", "<Leader>cc", ":Telescope commands<CR>")
key("n", "<Leader>cr", "<Cmd>lua command_history()<CR>")
key("n", "<Leader>y", "<Cmd>lua clipboard_history()<CR>")
key("i", "<c-y>", "<Cmd>lua clipboard_history()<CR>")
key("n", "<Leader>s", ":Telescope current_buffer_fuzzy_find<CR>")
key("n", "<Leader>gc", ":Telescope git_commits<CR>")
key("n", "<Leader>gf", ":Telescope git_bcommits<CR>")
key("n", "<Leader>gb", ":Telescope git_branches<CR>")
key("n", "<Leader>gs", ":Telescope git_status<CR>")
key("n", "<C-p>", "<Cmd>lua choose_project()<CR>")
-- Buffer tabs (tmux interferes)
-- key("n", "<C-L>", "gt")
-- key("i", "<C-L>", "<Esc>gt")
-- key("n", "<C-H>", "gT")
-- key("i", "<C-H>", "<Esc>gT")
-- LSP
key("n", "gd", "<Cmd>lua vim.lsp.buf.definition()<CR>", { silent = true })
key("n", "gT", "<Cmd>lua vim.lsp.buf.type_definition()<CR>", { silent = true })
key("n", "gi", "<Cmd>lua vim.lsp.buf.implementation()<CR>", { silent = true })
key("n", "gh", "<Cmd>lua vim.lsp.buf.hover()<CR>", { silent = true })
key("n", "gr", "<Cmd>Telescope lsp_references<CR>", { silent = true })
key("n", "<Leader>R", "<Cmd>lua vim.lsp.buf.rename()<CR>", { silent = true })
key("n", "]e", "<Cmd>lua vim.diagnostic.goto_next()<CR>", { silent = true })
key("n", "[e", "<Cmd>lua vim.diagnostic.goto_prev()<CR>", { silent = true })
key("n", "<Leader>e", "<Cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>", { silent = true })
key("n", "<Leader>E", "<Cmd>lua vim.lsp.buf.code_action()<CR>", { silent = true })
-- File commands
key("n", "<Leader>q", ":quit<CR>")
key("n", "<Leader>Q", ":quitall<CR>")
key("n", "<Leader>fs", ":write<CR>")
key("n", "<Leader>fd", ":lcd %:p:h<CR>", { silent = true })
key("n", "<Leader>fu", ":lcd ..<CR>", { silent = true })
key("n", "<Leader><Tab>", ":b#<CR>", { silent = true })
key("n", "<Leader>gr", ":!gh repo view -w<CR><CR>", { silent = true })
key("n", "<Leader>tt", [[<Cmd>exe 'edit $NOTES_PATH/journal/'.strftime("%Y-%m-%d_%a").'.md'<CR>]])
key("n", "<Leader>jj", ":!journal<CR>:e<CR>")
-- Window commands
key("n", "<Leader>wv", ":vsplit<CR>")
key("n", "<Leader>wh", ":split<CR>")
key("n", "<Leader>wm", ":only<CR>")
-- Tabularize
key("", "<Leader>ta", ":Tabularize /")
key("", "<Leader>t#", ":Tabularize /#<CR>")
key("", "<Leader>tl", ":Tabularize /---<CR>")
-- Vimrc editing
key("n", "<Leader>fv", ":edit $DOTS/nvim.configlink/init.lua<CR>")
key("n", "<Leader>rr", ":luafile $MYVIMRC<CR>")
key("n", "<Leader>rp", ":luafile $MYVIMRC<CR>:PackerInstall<CR>:")
key("n", "<Leader>rc", ":luafile $MYVIMRC<CR>:PackerCompile<CR>")
-- Keep cursor in place
key("n", "n", "nzz")
key("n", "N", "Nzz")
key("n", "J", "mzJ`z") --- Mark and jump back to it
-- Add undo breakpoints
key("i", ",", ",<C-g>u")
key("i", ".", ".<C-g>u")
key("i", "!", "!<C-g>u")
key("i", "?", "?<C-g>u")
-- Other
key("t", "<A-CR>", "<C-\\><C-n>") --- Exit terminal mode
key("n", "<A-CR>", ":noh<CR>", { silent = true }) --- Clear search in VimWiki
key("n", "Y", "y$") --- Copy to end of line
key("v", "<C-r>", "y<Esc>:%s/<C-r>+//gc<left><left><left>") --- Substitute selected
key("v", "D", "y'>gp") --- Duplicate selected

View File

@ -0,0 +1,65 @@
-- =======================================================================
-- Language Server
-- =======================================================================
-- Language server engine
use({
"neovim/nvim-lspconfig",
requires = { "hrsh7th/cmp-nvim-lsp" },
config = function()
local capabilities = require("cmp_nvim_lsp").update_capabilities(vim.lsp.protocol.make_client_capabilities())
require("lspconfig").rust_analyzer.setup({ capabilities = capabilities })
require("lspconfig").tflint.setup({ capabilities = capabilities })
require("lspconfig").terraformls.setup({ capabilities = capabilities })
require("lspconfig").pyright.setup({
on_attach = function()
-- set keymaps (requires 0.7.0)
-- vim.keymap.set("n", "", "", {buffer=0})
end,
capabilities = capabilities,
})
end,
})
-- Pretty highlights
use("folke/lsp-colors.nvim")
-- Linting
use({
"jose-elias-alvarez/null-ls.nvim",
branch = "main",
requires = {
"nvim-lua/plenary.nvim",
"neovim/nvim-lspconfig",
},
config = function()
require("null-ls").setup({
sources = {
require("null-ls").builtins.formatting.stylua,
require("null-ls").builtins.formatting.black,
require("null-ls").builtins.formatting.fish_indent,
require("null-ls").builtins.formatting.nixfmt,
require("null-ls").builtins.formatting.rustfmt,
require("null-ls").builtins.diagnostics.shellcheck,
require("null-ls").builtins.formatting.shfmt.with({
extra_args = { "-i", "4", "-ci" },
}),
require("null-ls").builtins.formatting.terraform_fmt,
-- require("null-ls").builtins.diagnostics.luacheck,
-- require("null-ls").builtins.diagnostics.markdownlint,
-- require("null-ls").builtins.diagnostics.pylint,
},
-- Format on save
on_attach = function(client)
if client.resolved_capabilities.document_formatting then
vim.cmd([[
augroup LspFormatting
autocmd! * <buffer>
autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_seq_sync()
augroup END
]])
end
end,
})
end,
})

View File

@ -0,0 +1,112 @@
-- Maintain plugin manager
use("wbthomason/packer.nvim")
-- Startup speed hacks
use({
"lewis6991/impatient.nvim",
config = function()
require("impatient")
end,
})
-- Important tweaks
use("tpope/vim-surround") --- Manipulate parentheses
-- Convenience tweaks
use("tpope/vim-eunuch") --- File manipulation in Vim
use("tpope/vim-vinegar") --- Fixes netrw file explorer
use("tpope/vim-fugitive") --- Git commands and syntax
use("tpope/vim-repeat") --- Actually repeat using .
use("christoomey/vim-tmux-navigator") --- Hotkeys for tmux panes
-- Use gc or gcc to add comments
use({
"numToStr/Comment.nvim",
config = function()
require("Comment").setup()
end,
})
-- Git next to line numbers
use({
"lewis6991/gitsigns.nvim",
branch = "main",
requires = { "nvim-lua/plenary.nvim" },
config = function()
require("gitsigns").setup()
end,
})
-- Status bar
use({
"hoob3rt/lualine.nvim",
requires = { "kyazdani42/nvim-web-devicons", opt = true },
config = function()
require("lualine").setup({
options = {
theme = "gruvbox",
icons_enabled = true,
},
})
end,
})
-- Improve speed and filetype detection
use({
"nathom/filetype.nvim",
config = function()
-- Filetype for .env files
local envfiletype = function()
vim.bo.filetype = "text"
vim.bo.syntax = "sh"
end
-- Force filetype patterns that Vim doesn't know about
require("filetype").setup({
overrides = {
extensions = {
Brewfile = "brewfile",
muttrc = "muttrc",
tfvars = "terraform",
tf = "terraform",
},
literal = {
Caskfile = "brewfile",
[".gitignore"] = "gitignore",
config = "config",
},
complex = {
[".*git/config"] = "gitconfig",
["tmux.conf%..*link"] = "tmux",
["gitconfig%..*link"] = "gitconfig",
[".*ignore%..*link"] = "gitignore",
[".*%.toml%..*link"] = "toml",
},
function_extensions = {},
function_literal = {
[".envrc"] = envfiletype,
[".env"] = envfiletype,
[".env.dev"] = envfiletype,
[".env.prod"] = envfiletype,
[".env.example"] = envfiletype,
},
},
})
end,
})
-- Alignment tool
use("godlygeek/tabular")
-- Markdown renderer / wiki notes
use("vimwiki/vimwiki")
-- Markdown pretty view
use("ellisonleao/glow.nvim")
-- Hex color previews
use({
"norcalli/nvim-colorizer.lua",
config = function()
require("colorizer").setup()
end,
})

View File

@ -0,0 +1,6 @@
-- =======================================================================
-- Install on initial bootstrap
if packer_bootstrap then
require("packer").sync()
end

View File

@ -0,0 +1,116 @@
-- ===========================================================================
-- Settings
-- ===========================================================================
vim.o.termguicolors = true --- Set to truecolor
vim.o.hidden = true --- Don't unload buffers when leaving them
vim.wo.number = true --- Show line numbers
vim.wo.relativenumber = true --- Relative numbers instead of absolute
vim.o.list = true --- Reveal whitespace with dashes
vim.o.expandtab = true --- Tabs into spaces
vim.o.shiftwidth = 4 --- Amount to shift with > key
vim.o.softtabstop = 4 --- Amount to shift with <TAB> key
vim.o.ignorecase = true --- Ignore case when searching
vim.o.smartcase = true --- Check case when using capitals in search
vim.o.infercase = true --- Don't match cases when completing suggestions
vim.o.incsearch = true --- Search while typing
vim.o.visualbell = true --- No sounds
vim.o.scrolljump = 1 --- Number of lines to scroll
vim.o.scrolloff = 3 --- Margin of lines to see while scrolling
vim.o.splitright = true --- Vertical splits on the right side
vim.o.splitbelow = true --- Horizontal splits on the bottom side
vim.o.pastetoggle = "<F3>" --- Use F3 to enter raw paste mode
vim.o.clipboard = "unnamedplus" --- Uses system clipboard for yanking
vim.o.updatetime = 300 --- Faster diagnostics
vim.o.mouse = "nv" --- Mouse interaction / scrolling
-- Neovim features
vim.o.inccommand = "split" --- Live preview search and replace
--- Required for nvim-cmp completion
vim.opt.completeopt = {
"menu",
"menuone",
"noselect",
}
-- Required until 0.6.0: do not source the default filetype.vim
vim.g.did_load_filetypes = 1
-- Remember last position when reopening file
vim.api.nvim_exec(
[[
au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal! g`\"" | endif
]],
false
)
-- Better backup, swap and undo storage
vim.o.backup = true --- Easier to recover and more secure
vim.bo.swapfile = false --- Instead of swaps, create backups
vim.bo.undofile = true --- Keeps undos after quit
-- Create backup directories if they don't exist
-- Should be fixed in 0.6 by https://github.com/neovim/neovim/pull/15433
vim.o.backupdir = vim.fn.stdpath("cache") .. "/backup"
vim.api.nvim_exec(
[[
if !isdirectory(&backupdir)
call mkdir(&backupdir, "p")
endif
]],
false
)
-- LaTeX options
vim.api.nvim_exec(
[[
au FileType tex inoremap ;bf \textbf{}<Esc>i
au BufWritePost *.tex silent! execute "!pdflatex -output-directory=%:p:h % >/dev/null 2>&1" | redraw!
]],
false
)
-- Highlight when yanking
vim.api.nvim_exec(
[[
au TextYankPost * silent! lua vim.highlight.on_yank { timeout = 250 }
]],
false
)
-- Netrw
vim.g.netrw_liststyle = 3 -- Change style to 'tree' view
vim.g.netrw_banner = 0 -- Remove useless banner
vim.g.netrw_winsize = 15 -- Explore window takes % of page
vim.g.netrw_browse_split = 4 -- Open in previous window
vim.g.netrw_altv = 1 -- Always split left
-- VimWiki
vim.g.vimwiki_list = {
{
["path"] = "$NOTES_PATH",
["syntax"] = "markdown",
["index"] = "home",
["ext"] = ".md",
},
}
vim.g.vimwiki_key_mappings = {
["all_maps"] = 1,
["mouse"] = 1,
}
vim.g.vimwiki_auto_chdir = 1 -- Set local dir to Wiki when open
vim.g.vimwiki_create_link = 0 -- Don't automatically create new links
vim.g.vimwiki_listsyms = " x" -- Set checkbox symbol progression
vim.g.vimwiki_table_mappings = 0 -- VimWiki table keybinds interfere with tab completion
vim.api.nvim_exec(
[[
au FileType markdown inoremap ;tt <Esc>:AddTag<CR>
function! PInsert(item)
let @z=a:item
norm "zpx
endfunction
command! AddTag call fzf#run({'source': 'rg "#[A-Za-z/]+[ |\$]" -o --no-filename --no-line-number | sort | uniq', 'sink': function('PInsert')})
]],
false
)

View File

@ -0,0 +1,31 @@
-- =======================================================================
-- Syntax
-- =======================================================================
-- Syntax engine
use({
"nvim-treesitter/nvim-treesitter",
run = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = {
"hcl",
"python",
"lua",
"nix",
"fish",
"toml",
"yaml",
"json",
},
highlight = { enable = true },
indent = { enable = true },
})
end,
})
-- Additional syntax sources
use("bfontaine/Brewfile.vim") --- Brewfile syntax
use("chr4/nginx.vim") --- Nginx syntax
use("towolf/vim-helm") --- Helm syntax
use("rodjek/vim-puppet") --- Puppet syntax

View File

@ -0,0 +1,67 @@
-- =======================================================================
-- Fuzzy Launcher
-- =======================================================================
use({
"nvim-telescope/telescope.nvim",
branch = "master",
requires = { "nvim-lua/plenary.nvim" },
config = function()
-- Telescope: quit instantly with escape
local actions = require("telescope.actions")
require("telescope").setup({
defaults = {
mappings = {
i = {
["<esc>"] = actions.close,
["<C-h>"] = "which_key",
},
},
},
pickers = {
find_files = { theme = "ivy" },
oldfiles = { theme = "ivy" },
buffers = { theme = "dropdown" },
},
extensions = {
fzy_native = {},
tmux = {},
zoxide = {},
--neoclip = {},
project = {
base_dirs = { "~/dev" },
},
},
})
end,
})
-- Faster sorting
use("nvim-telescope/telescope-fzy-native.nvim")
-- Jump around tmux sessions
use("camgraff/telescope-tmux.nvim")
-- Jump directories
use({
"jvgrootveld/telescope-zoxide",
requires = { "nvim-lua/popup.nvim" },
})
-- Jump projects
use({
"nvim-telescope/telescope-project.nvim",
requires = { "nvim-telescope/telescope.nvim" },
config = function()
require("telescope").load_extension("project")
end,
})
-- File browser
use({
"nvim-telescope/telescope-file-browser.nvim",
requires = { "nvim-telescope/telescope.nvim" },
config = function()
require("telescope").load_extension("file_browser")
end,
})

11
modules/editor/notes.nix Normal file
View File

@ -0,0 +1,11 @@
{ config, ... }: {
home-manager.users.${config.user} = {
home.sessionVariables = {
NOTES_PATH = "${config.homePath}/dev/personal/notes";
};
};
}

View File

@ -1,5 +1,7 @@
{ config, ... }: {
imports = [ ./leagueoflegends.nix ./lutris.nix ./steam.nix ./legendary.nix ];
config = {
hardware.opengl = {
enable = true;

View File

@ -1,14 +1,30 @@
{ config, pkgs, ... }:
{ config, pkgs, lib, ... }: {
{
imports = [ ./common.nix ./lutris.nix ];
options.gaming.leagueoflegends = lib.mkEnableOption "League of Legends";
config = {
config = lib.mkIf config.gaming.leagueoflegends {
# League of Legends anti-cheat
# League of Legends anti-cheat requirement
boot.kernel.sysctl = { "abi.vsyscall32" = 0; };
environment.systemPackages = with pkgs; [ openssl dconf ];
environment.systemPackages = with pkgs; [
# Lutris requirement to install the game
lutris
amdvlk
wineWowPackages.stable
# vulkan-tools
# Required according to https://lutris.net/games/league-of-legends/
openssl
gnome.zenity
# Don't remember if this is required
dconf
];
environment.sessionVariables = { QT_X11_NO_MITSHM = "1"; };
};
}

View File

@ -0,0 +1,56 @@
{ config, pkgs, lib, ... }:
let home-packages = config.home-manager.users.${config.user}.home.packages;
in {
options.gaming.legendary =
lib.mkEnableOption "Legendary - Epic Games Launcher";
config = lib.mkIf config.gaming.legendary {
environment.systemPackages = with pkgs; [
legendary-gl
rare # GUI for Legendary (not working)
wineWowPackages.stable # 32-bit and 64-bit wineWowPackages, see https://nixos.wiki/wiki/Wine
];
home-manager.users.${config.user} = {
xdg.configFile."legendary/config.ini".text = ''
[Legendary]
; Disables the automatic update check
disable_update_check = false
; Disables the notice about an available update on exit
disable_update_notice = true
; Set install directory
install_dir = ${config.homePath}/media/games
; Make output quiet
log_level = error
'';
home.file = let
ignorePatterns = ''
.wine/
drive_c/'';
in {
".rgignore".text = ignorePatterns;
".fdignore".text = ignorePatterns;
};
programs.fish.functions =
lib.mkIf (builtins.elem pkgs.fzf home-packages) {
epic-games = {
body = ''
set game (legendary list 2>/dev/null \
| awk '/^ \* / { print $0; }' \
| sed -e 's/ (.*)$//' -e 's/ \* //' \
| fzf)
and legendary launch "$game" &> /dev/null
'';
};
};
};
};
}

View File

@ -1,9 +1,13 @@
{ config, pkgs, ... }:
{ config, pkgs, lib, ... }: {
{
options.gaming.lutris = lib.mkEnableOption "Lutris";
imports = [ ./common.nix ];
config = { environment.systemPackages = with pkgs; [ lutris amdvlk wine ]; };
config = lib.mkIf config.gaming.lutris {
environment.systemPackages = with pkgs; [
lutris
amdvlk # Vulkan drivers (probably already installed)
wineWowPackages.stable # 32-bit and 64-bit wineWowPackages
];
};
}

View File

@ -1,10 +1,19 @@
{ config, pkgs, ... }: {
{ config, pkgs, lib, ... }: {
imports = [ ./common.nix ];
options.gaming.steam = lib.mkEnableOption "Steam";
config = {
config = lib.mkIf config.gaming.steam {
hardware.steam-hardware.enable = true;
environment.systemPackages = with pkgs; [ steam ];
unfreePackages = [ "steam" "steam-original" "steamcmd" ];
environment.systemPackages = with pkgs; [
steam
# Enable terminal interaction
steamPackages.steamcmd
steam-tui
];
};
}

View File

@ -0,0 +1,55 @@
{ lib, ... }: {
imports = [
./xorg.nix
./fonts.nix
./i3.nix
./polybar.nix
./picom.nix
# ./dmenu.nix
./rofi.nix
];
options = with lib; {
gui = {
compositor.enable = mkEnableOption {
description = "Enable transparency, blur, shadows";
default = false;
};
launcherCommand = mkOption {
type = types.str;
description = "Command to use for launching";
};
systemdSearch = mkOption {
type = types.str;
description = "Command to use for interacting with systemd";
};
altTabCommand = mkOption {
type = types.str;
description = "Command to use for choosing windows";
};
toggleBarCommand = lib.mkOption {
type = lib.types.str;
description = "Command to hide and show the status bar.";
};
gtk.theme = {
name = mkOption {
type = types.str;
description = "Theme name for GTK applications";
};
package = mkOption {
type = types.str;
description = "Theme package name for GTK applications";
default = "gnome-themes-extra";
};
};
wallpaper = mkOption {
type = types.path;
description = "Wallpaper background image file";
};
};
};
}

View File

@ -0,0 +1,12 @@
{ config, pkgs, lib, ... }:
{
config = lib.mkIf config.services.xserver.enable {
home-manager.users.${config.user}.home.packages = [ pkgs.dmenu ];
gui.launcherCommand = "${pkgs.dmenu}/bin/dmenu_run";
};
}

View File

@ -0,0 +1,28 @@
{ config, pkgs, lib, ... }:
let fontName = "Victor Mono";
in {
config = lib.mkIf config.gui.enable {
fonts.fonts = with pkgs; [
victor-mono # Used for Vim and Terminal
(nerdfonts.override { fonts = [ "Hack" ]; }) # For Polybar, Rofi
];
fonts.fontconfig.defaultFonts.monospace = [ fontName ];
home-manager.users.${config.user} = {
xsession.windowManager.i3.config.fonts = {
names = [ "pango:${fontName}" ];
# style = "Regular";
# size = 11.0;
};
services.polybar.config."bar/main".font-0 = "Hack Nerd Font:size=10;2";
programs.rofi.font = "Hack Nerd Font 14";
programs.alacritty.settings.font.normal.family = fontName;
};
};
}

276
modules/graphical/i3.nix Normal file
View File

@ -0,0 +1,276 @@
{ config, pkgs, lib, ... }:
let
lockCmd =
"${pkgs.betterlockscreen}/bin/betterlockscreen --lock --display 1 --blur 0.5 --span";
lockUpdate =
"${pkgs.betterlockscreen}/bin/betterlockscreen --update ${config.gui.wallpaper} --display 1 --span";
in {
config = lib.mkIf config.services.xserver.enable {
services.xserver.windowManager = {
i3 = {
enable = true;
package = pkgs.i3-gaps;
};
};
environment.systemPackages = with pkgs; [
feh # Wallpaper
playerctl # Media control
];
home-manager.users.${config.user} = {
xsession.windowManager.i3 = {
enable = true;
package = pkgs.i3-gaps;
config = let
modifier = "Mod4"; # Super key
ws1 = "1:I";
ws2 = "2:II";
ws3 = "3:III";
ws4 = "4:IV";
ws5 = "5:V";
ws6 = "6:VI";
ws7 = "7:VII";
ws8 = "8:VIII";
ws9 = "9:IX";
ws10 = "10:X";
in {
modifier = modifier;
assigns = {
"${ws1}" = [{ class = "Firefox"; }];
"${ws2}" = [{ class = "Alacritty"; }];
"${ws3}" = [{ class = "discord"; }];
"${ws4}" = [{ class = "Steam"; }];
};
bars = [{ command = "echo"; }]; # Disable i3bar
colors = let
background = config.gui.colorscheme.base00;
inactiveBackground = config.gui.colorscheme.base01;
border = config.gui.colorscheme.base01;
inactiveBorder = config.gui.colorscheme.base01;
text = config.gui.colorscheme.base07;
inactiveText = config.gui.colorscheme.base04;
urgentBackground = config.gui.colorscheme.base08;
indicator = "#00000000";
in {
background = config.gui.colorscheme.base00;
focused = {
inherit background indicator text border;
childBorder = background;
};
focusedInactive = {
inherit indicator;
background = inactiveBackground;
border = inactiveBorder;
childBorder = inactiveBackground;
text = inactiveText;
};
# placeholder = { };
unfocused = {
inherit indicator;
background = inactiveBackground;
border = inactiveBorder;
childBorder = inactiveBackground;
text = inactiveText;
};
urgent = {
inherit text indicator;
background = urgentBackground;
border = urgentBackground;
childBorder = urgentBackground;
};
};
floating.modifier = modifier;
focus = {
mouseWarping = true;
newWindow = "urgent";
followMouse = false;
};
keybindings = {
# Adjust screen brightness
"Shift+F12" =
"exec ${pkgs.ddcutil}/bin/ddcutil --display 1 setvcp 10 + 30 && sleep 1; exec ${pkgs.ddcutil}/bin/ddcutil --display 2 setvcp 10 + 30";
"Shift+F11" =
"exec ${pkgs.ddcutil}/bin/ddcutil --display 1 setvcp 10 - 30 && sleep 1; exec ${pkgs.ddcutil}/bin/ddcutil --display 2 setvcp 10 - 30";
"XF86MonBrightnessUp" =
"exec ${pkgs.ddcutil}/bin/ddcutil --display 1 setvcp 10 + 30 && sleep 1; exec ${pkgs.ddcutil}/bin/ddcutil --display 2 setvcp 10 + 30";
"XF86MonBrightnessDown" =
"exec ${pkgs.ddcutil}/bin/ddcutil --display 1 setvcp 10 - 30 && sleep 1; exec ${pkgs.ddcutil}/bin/ddcutil --display 2 setvcp 10 - 30";
# Media player controls
"XF86AudioPlay" = "exec ${pkgs.playerctl}/bin/playerctl play-pause";
"XF86AudioStop" = "exec ${pkgs.playerctl}/bin/playerctl stop";
"XF86AudioNext" = "exec ${pkgs.playerctl}/bin/playerctl next";
"XF86AudioPrev" = "exec ${pkgs.playerctl}/bin/playerctl previous";
# Launchers
"${modifier}+Return" =
"exec --no-startup-id alacritty; workspace ${ws2}; layout tabbed";
"${modifier}+space" =
"exec --no-startup-id ${config.gui.launcherCommand}";
"${modifier}+Shift+s" =
"exec --no-startup-id ${config.gui.systemdSearch}";
"Mod1+Tab" = "exec --no-startup-id ${config.gui.altTabCommand}";
"${modifier}+Shift+c" = "reload";
"${modifier}+Shift+r" = "restart";
"${modifier}+Shift+q" = ''
exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'"'';
"${modifier}+Shift+x" = "exec ${lockCmd}";
# Window options
"${modifier}+q" = "kill";
"${modifier}+b" = "exec ${config.gui.toggleBarCommand}";
"${modifier}+f" = "fullscreen toggle";
"${modifier}+h" = "focus left";
"${modifier}+j" = "focus down";
"${modifier}+k" = "focus up";
"${modifier}+l" = "focus right";
"${modifier}+Left" = "focus left";
"${modifier}+Down" = "focus down";
"${modifier}+Up" = "focus up";
"${modifier}+Right" = "focus right";
"${modifier}+Shift+h" = "move left";
"${modifier}+Shift+j" = "move down";
"${modifier}+Shift+k" = "move up";
"${modifier}+Shift+l" = "move right";
"${modifier}+Shift+Left" = "move left";
"${modifier}+Shift+Down" = "move down";
"${modifier}+Shift+Up" = "move up";
"${modifier}+Shift+Right" = "move right";
# Tiling
"${modifier}+i" = "split h";
"${modifier}+v" = "split v";
"${modifier}+s" = "layout stacking";
"${modifier}+t" = "layout tabbed";
"${modifier}+e" = "layout toggle split";
"${modifier}+Shift+space" = "floating toggle";
"${modifier}+Control+space" = "focus mode_toggle";
"${modifier}+a" = "focus parent";
# Workspaces
"${modifier}+1" = "workspace ${ws1}";
"${modifier}+2" = "workspace ${ws2}";
"${modifier}+3" = "workspace ${ws3}";
"${modifier}+4" = "workspace ${ws4}";
"${modifier}+5" = "workspace ${ws5}";
"${modifier}+6" = "workspace ${ws6}";
"${modifier}+7" = "workspace ${ws7}";
"${modifier}+8" = "workspace ${ws8}";
"${modifier}+9" = "workspace ${ws9}";
"${modifier}+0" = "workspace ${ws10}";
# Move windows
"${modifier}+Shift+1" =
"move container to workspace ${ws1}; workspace ${ws1}";
"${modifier}+Shift+2" =
"move container to workspace ${ws2}; workspace ${ws2}";
"${modifier}+Shift+3" =
"move container to workspace ${ws3}; workspace ${ws3}";
"${modifier}+Shift+4" =
"move container to workspace ${ws4}; workspace ${ws4}";
"${modifier}+Shift+5" =
"move container to workspace ${ws5}; workspace ${ws5}";
"${modifier}+Shift+6" =
"move container to workspace ${ws6}; workspace ${ws6}";
"${modifier}+Shift+7" =
"move container to workspace ${ws7}; workspace ${ws7}";
"${modifier}+Shift+8" =
"move container to workspace ${ws8}; workspace ${ws8}";
"${modifier}+Shift+9" =
"move container to workspace ${ws9}; workspace ${ws9}";
"${modifier}+Shift+0" =
"move container to workspace ${ws10}; workspace ${ws10}";
# Move screens
"${modifier}+Control+l" = "move workspace to output right";
"${modifier}+Control+h" = "move workspace to output left";
# Resizing
"${modifier}+r" = ''mode "resize"'';
"${modifier}+Control+Shift+h" =
"resize shrink width 10 px or 10 ppt";
"${modifier}+Control+Shift+j" =
"resize grow height 10 px or 10 ppt";
"${modifier}+Control+Shift+k" =
"resize shrink height 10 px or 10 ppt";
"${modifier}+Control+Shift+l" = "resize grow width 10 px or 10 ppt";
};
modes = { };
startup = [
{
command = "feh --bg-fill ${config.gui.wallpaper}";
always = true;
notification = false;
}
{
command = "i3-msg workspace ${ws1}";
notification = false;
}
];
window = {
border = 0;
hideEdgeBorders = "smart";
titlebar = false;
};
workspaceAutoBackAndForth = false;
workspaceOutputAssign = [ ];
# gaps = {
# bottom = 8;
# top = 8;
# left = 8;
# right = 8;
# horizontal = 15;
# vertical = 15;
# inner = 15;
# outer = 0;
# smartBorders = "off";
# smartGaps = false;
# };
};
extraConfig = "";
};
programs.fish.functions = {
update-lock-screen = {
description = "Update lockscreen with wallpaper";
body = lockUpdate;
};
};
# Update lock screen cache only if cache is empty
home.activation.updateLockScreenCache =
let cacheDir = "${config.homePath}/.cache/betterlockscreen/current";
in config.home-manager.users.${config.user}.lib.dag.entryAfter
[ "writeBoundary" ] ''
if [ ! -d ${cacheDir} ] || [ -z "$(ls ${cacheDir})" ]; then
$DRY_RUN_CMD ${lockUpdate}
fi
'';
};
# Ref: https://github.com/betterlockscreen/betterlockscreen/blob/next/system/betterlockscreen%40.service
systemd.services.lock = {
description = "Lock the screen on resume from suspend";
before = [ "sleep.target" "suspend.target" ];
serviceConfig = {
User = config.user;
Type = "simple";
Environment = "DISPLAY=:0";
TimeoutSec = "infinity";
ExecStart = lockCmd;
ExecStartPost = "${pkgs.coreutils-full}/bin/sleep 1";
};
wantedBy = [ "sleep.target" "suspend.target" ];
};
};
}

View File

@ -0,0 +1,49 @@
{ config, lib, ... }: {
config =
lib.mkIf (config.services.xserver.enable && config.gui.compositor.enable) {
home-manager.users.${config.user} = {
services.picom = {
enable = true;
blur = false;
blurExclude = [ ];
# extraOptions = ''
# shadow-radius = 20
# '';
# extraOptions = ''
# shadow-radius = 20
# corner-radius = 10
# blur-size = 20
# rounded-corners-exclude = [
# "window_type = 'dock'",
# "class_g = 'i3-frame'"
# ]
# '';
fade = false;
experimentalBackends = true;
inactiveDim = "0.05";
inactiveOpacity = "1.0";
menuOpacity = "1.0";
noDNDShadow = false;
noDockShadow = false;
opacityRule = [
"0:_NET_WM_STATE@[0]:32a = '_NET_WM_STATE_HIDDEN'" # Hide tabbed windows
];
shadow = false;
shadowExclude = [ ];
shadowOffsets = [ (-10) (-10) ];
shadowOpacity = "0.5";
vSync = true;
};
xsession.windowManager.i3.config.startup = [{
command = "systemctl --user restart picom";
always = true;
notification = false;
}];
};
};
}

View File

@ -0,0 +1,185 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.services.xserver.enable {
gui.toggleBarCommand = "polybar-msg cmd toggle";
home-manager.users.${config.user} = {
services.polybar = {
enable = true;
package = pkgs.polybar.override {
i3GapsSupport = true;
pulseSupport = true;
githubSupport = true;
};
script = "polybar &";
config = {
"bar/main" = {
bottom = false;
width = "100%";
height = "22pt";
radius = 0;
# offset-y = -5;
# offset-y = "5%";
# dpi = 96;
background = config.gui.colorscheme.base01;
foreground = config.gui.colorscheme.base05;
line-size = "3pt";
border-top-size = 0;
border-right-size = 0;
border-left-size = 0;
border-bottom-size = "4pt";
border-color = config.gui.colorscheme.base00;
padding-left = 2;
padding-right = 2;
module-margin = 1;
modules-left = "i3";
modules-center = "xwindow";
modules-right = "pulseaudio date";
cursor-click = "pointer";
cursor-scroll = "ns-resize";
enable-ipc = true;
tray-position = "right";
# wm-restack = "generic";
# wm-restack = "bspwm";
# wm-restack = "i3";
# override-redirect = true;
};
"module/i3" = let padding = 2;
in {
type = "internal/i3";
pin-workspaces = false;
show-urgent = true;
strip-wsnumbers = true;
index-sort = true;
enable-click = true;
wrapping-scroll = true;
fuzzy-match = true;
format = "<label-state> <label-mode>";
label-focused = "%name%";
label-focused-foreground = config.gui.colorscheme.base01;
label-focused-background = config.gui.colorscheme.base05;
label-focused-underline = config.gui.colorscheme.base03;
label-focused-padding = padding;
label-unfocused = "%name%";
label-unfocused-padding = padding;
label-visible = "%name%";
label-visible-underline = config.gui.colorscheme.base01;
label-visible-padding = padding;
label-urgent = "%name%";
label-urgent-foreground = config.gui.colorscheme.base00;
label-urgent-background = config.gui.colorscheme.base08;
label-urgent-underline = config.gui.colorscheme.base0F;
label-urgent-padding = padding;
};
"module/xworkspaces" = {
type = "internal/xworkspaces";
label-active = "%name%";
label-active-background = config.gui.colorscheme.base05;
label-active-foreground = config.gui.colorscheme.base01;
label-active-underline = config.gui.colorscheme.base03;
label-active-padding = 1;
label-occupied = "%name%";
label-occupied-padding = 1;
label-urgent = "%name%";
label-urgent-background = config.gui.colorscheme.base08;
label-urgent-padding = 1;
label-empty = "%name%";
label-empty-foreground = config.gui.colorscheme.base06;
label-empty-padding = 1;
};
"module/xwindow" = {
type = "internal/xwindow";
label = "%title:0:60:...%";
};
# "module/filesystem" = {
# type = "internal/fs";
# interval = 25;
# mount-0 = "/";
# label-mounted = "%{F#F0C674}%mountpoint%%{F-} %percentage_used%%";
# label-unmounted = "%mountpoint% not mounted";
# label-unmounted-foreground = colors.disabled;
# };
"module/pulseaudio" = {
type = "internal/pulseaudio";
# format-volume-prefix = "VOL ";
# format-volume-prefix-foreground = colors.primary;
format-volume = "<ramp-volume> <label-volume>";
# format-volume-background = colors.background;
# label-volume-background = colors.background;
format-volume-foreground = config.gui.colorscheme.base0B;
label-volume = "%percentage%%";
label-muted = " ---";
label-muted-foreground = config.gui.colorscheme.base03;
ramp-volume-0 = "";
ramp-volume-1 = "";
ramp-volume-2 = "";
};
# "module/xkeyboard" = {
# type = "internal/xkeyboard";
# blacklist-0 = "num lock";
# label-layout = "%layout%";
# label-layout-foreground = colors.primary;
# label-indicator-padding = 2;
# label-indicator-margin = 1;
# label-indicator-foreground = colors.background;
# label-indicator-background = colors.secondary;
# };
# "module/memory" = {
# type = "internal/memory";
# interval = 2;
# format-prefix = "RAM ";
# format-prefix-foreground = colors.primary;
# label = "%percentage_used:2%%";
# };
# "module/cpu" = {
# type = "internal/cpu";
# interval = 2;
# format-prefix = "CPU ";
# format-prefix-foreground = colors.primary;
# label = "%percentage:2%%";
# };
# "network-base" = {
# type = "internal/network";
# interval = 5;
# format-connected = "<label-connected>";
# format-disconnected = "<label-disconnected>";
# label-disconnected = "%{F#F0C674}%ifname%%{F#707880} disconnected";
# };
# "module/wlan" = {
# "inherit" = "network-base";
# interface-type = "wireless";
# label-connected = "%{F#F0C674}%ifname%%{F-} %essid% %local_ip%";
# };
# "module/eth" = {
# "inherit" = "network-base";
# interface-type = "wired";
# label-connected = "%{F#F0C674}%ifname%%{F-} %local_ip%";
# };
"module/date" = {
type = "internal/date";
interval = 1;
date = "%d %b %l:%M %p";
date-alt = "%Y-%m-%d %H:%M:%S";
label = "%date%";
label-foreground = config.gui.colorscheme.base0A;
# format-background = colors.background;
};
"settings" = {
screenchange-reload = true;
pseudo-transparency = false;
};
};
};
xsession.windowManager.i3.config.startup = [{
command = "systemctl --user restart polybar";
always = true;
notification = false;
}];
};
};
}

153
modules/graphical/rofi.nix Normal file
View File

@ -0,0 +1,153 @@
{ config, pkgs, lib, ... }:
{
config = lib.mkIf config.services.xserver.enable {
home-manager.users.${config.user} = {
home.packages = with pkgs;
[
jq # Required for rofi-systemd
];
programs.rofi = {
enable = true;
cycle = true;
location = "center";
pass = { };
plugins = [ pkgs.rofi-calc pkgs.rofi-emoji pkgs.rofi-systemd ];
theme = let
inherit (config.home-manager.users.${config.user}.lib.formats.rasi)
mkLiteral;
in {
# Inspired by https://github.com/sherubthakur/dotfiles/blob/master/users/modules/desktop-environment/rofi/launcher.rasi
"*" = {
background-color = mkLiteral config.gui.colorscheme.base00;
foreground-color = mkLiteral config.gui.colorscheme.base07;
text-color = mkLiteral config.gui.colorscheme.base07;
border-color = mkLiteral config.gui.colorscheme.base04;
};
# Holds the entire window
"#window" = {
transparency = "real";
background-color = mkLiteral config.gui.colorscheme.base00;
text-color = mkLiteral config.gui.colorscheme.base07;
border = mkLiteral "4px";
border-color = mkLiteral config.gui.colorscheme.base04;
border-radius = mkLiteral "4px";
width = mkLiteral "850px";
padding = mkLiteral "15px";
};
# Wrapper around bar and results
"#mainbox" = {
background-color = mkLiteral config.gui.colorscheme.base00;
border = mkLiteral "0px";
border-radius = mkLiteral "0px";
border-color = mkLiteral config.gui.colorscheme.base04;
children = map mkLiteral [ "inputbar" "listview" ];
spacing = mkLiteral "10px";
padding = mkLiteral "10px";
};
# Unknown
"#textbox-prompt-colon" = {
expand = false;
str = ":";
margin = mkLiteral "0px 0.3em 0em 0em";
text-color = mkLiteral config.gui.colorscheme.base07;
};
# Command prompt left of the input
"#prompt" = { enabled = false; };
# Actual text box
"#entry" = {
placeholder-color = mkLiteral config.gui.colorscheme.base03;
expand = true;
horizontal-align = "0";
placeholder = "Launch Program";
padding = mkLiteral "0px 0px 0px 5px";
blink = true;
};
# Top bar
"#inputbar" = {
children = map mkLiteral [ "prompt" "entry" ];
border = mkLiteral "1px";
border-radius = mkLiteral "4px";
padding = mkLiteral "6px";
};
# Results
"#listview" = {
background-color = mkLiteral config.gui.colorscheme.base00;
padding = mkLiteral "0px";
columns = 1;
lines = 12;
spacing = "5px";
cycle = true;
dynamic = true;
layout = "vertical";
};
# Each result
"#element" = {
orientation = "vertical";
border-radius = mkLiteral "0px";
padding = mkLiteral "5px 0px 5px 5px";
};
"#element.selected" = {
border = mkLiteral "1px";
border-radius = mkLiteral "4px";
border-color = mkLiteral config.gui.colorscheme.base07;
background-color = mkLiteral config.gui.colorscheme.base04;
text-color = mkLiteral config.gui.colorscheme.base00;
};
"#element-text" = {
expand = true;
# horizontal-align = mkLiteral "0.5";
vertical-align = mkLiteral "0.5";
margin = mkLiteral "0px 2.5px 0px 2.5px";
};
"#element-text.selected" = {
background-color = mkLiteral config.gui.colorscheme.base04;
text-color = mkLiteral config.gui.colorscheme.base00;
};
# Not sure how to get icons
"#element-icon" = {
size = mkLiteral "18px";
border = mkLiteral "0px";
padding = mkLiteral "2px 5px 2px 2px";
background-color = mkLiteral config.gui.colorscheme.base00;
};
"#element-icon.selected" = {
background-color = mkLiteral config.gui.colorscheme.base04;
text-color = mkLiteral config.gui.colorscheme.base00;
};
};
xoffset = 0;
yoffset = -20;
extraConfig = {
show-icons = true;
kb-cancel = "Escape,Super+space";
modi = "window,run,ssh,emoji,calc,systemd";
};
};
};
gui.launcherCommand = "${pkgs.rofi}/bin/rofi -show run -modi run";
gui.systemdSearch = "${pkgs.rofi-systemd}/bin/rofi-systemd";
gui.altTabCommand = "${pkgs.rofi}/bin/rofi -show window -modi window";
};
}

View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
# THEME="$HOME/.config/rofi/config.rasi"
ICON_UP=""
ICON_DOWN=""
ICON_OPT=""
options="$ICON_UP\n$ICON_OPT\n$ICON_DOWN"
chosen="$(echo -e "$options" | rofi -theme-str 'listview { layout:horizontal; }' -dmenu)"
echo "$chosen"

View File

@ -0,0 +1,65 @@
{ config, pkgs, lib, ... }:
let
gtkTheme = {
name = config.gui.gtk.theme.name;
package = pkgs.${config.gui.gtk.theme.package};
};
in {
config = lib.mkIf config.gui.enable {
# Enable the X11 windowing system.
services.xserver = {
enable = config.gui.enable;
# Enable touchpad support
libinput.enable = true;
# Login screen
displayManager = {
lightdm = {
enable = config.services.xserver.enable;
background = config.gui.wallpaper;
# Make the login screen dark
greeters.gtk.theme = gtkTheme;
};
};
};
environment.systemPackages = with pkgs;
[
xclip # Clipboard
];
# Required for setting GTK theme (for preferred-color-scheme in browser)
services.dbus.packages = [ pkgs.dconf ];
programs.dconf.enable = true;
environment.sessionVariables = { GTK_THEME = config.gui.gtk.theme.name; };
home-manager.users.${config.user} = {
programs.fish.shellAliases = {
pbcopy = "xclip -selection clipboard -in";
pbpaste = "xclip -selection clipboard -out";
};
gtk = let gtkExtraConfig = { gtk-application-prefer-dark-theme = true; };
in {
enable = true;
theme = gtkTheme;
gtk3.extraConfig = gtkExtraConfig;
gtk4.extraConfig = gtkExtraConfig;
};
};
};
}

View File

@ -0,0 +1,77 @@
{ config, pkgs, lib, ... }:
let
# These micro-scripts change the volume while also triggering the volume
# notification widget
increaseVolume = pkgs.writeShellScriptBin "increaseVolume" ''
${pkgs.pamixer}/bin/pamixer -i 2
volume=$(${pkgs.pamixer}/bin/pamixer --get-volume)
${pkgs.volnoti}/bin/volnoti-show $volume
'';
decreaseVolume = pkgs.writeShellScriptBin "decreaseVolume" ''
${pkgs.pamixer}/bin/pamixer -d 2
volume=$(${pkgs.pamixer}/bin/pamixer --get-volume)
${pkgs.volnoti}/bin/volnoti-show $volume
'';
toggleMute = pkgs.writeShellScriptBin "toggleMute" ''
${pkgs.pamixer}/bin/pamixer --toggle-mute
mute=$(${pkgs.pamixer}/bin/pamixer --get-mute)
if [ "$mute" == "true" ]; then
${pkgs.volnoti}/bin/volnoti-show --mute
else
volume=$(${pkgs.pamixer}/bin/pamixer --get-volume)
${pkgs.volnoti}/bin/volnoti-show $volume
fi
'';
in {
config = lib.mkIf config.gui.enable {
sound.enable = true;
# Enable PulseAudio
hardware.pulseaudio.enable = true;
# These aren't necessary, but helpful for the user
environment.systemPackages = with pkgs; [
pamixer # Audio control
volnoti # Volume notifications
];
home-manager.users.${config.user} = {
# Graphical volume notifications
services.volnoti.enable = true;
xsession.windowManager.i3.config = {
# Make sure that Volnoti actually starts (home-manager doesn't start
# user daemon's automatically)
startup = [{
command = "systemctl --user restart volnoti";
always = true;
notification = false;
}];
# i3 keybinds for changing the volume
keybindings = {
"XF86AudioRaiseVolume" =
"exec --no-startup-id ${increaseVolume}/bin/increaseVolume";
"XF86AudioLowerVolume" =
"exec --no-startup-id ${decreaseVolume}/bin/decreaseVolume";
"XF86AudioMute" = "exec --no-startup-id ${toggleMute}/bin/toggleMute";
# We can mute the mic by adding "--default-source"
"XF86AudioMicMute" =
"exec --no-startup-id ${pkgs.pamixer}/bin/pamixer --default-source --toggle-mute";
};
};
};
};
}

35
modules/hardware/boot.nix Normal file
View File

@ -0,0 +1,35 @@
{ config, ... }: {
boot.loader = {
grub = {
enable = true;
# Not sure what this does, but it involves the UEFI/BIOS
efiSupport = true;
# Check for other OSes and make them available
useOSProber = true;
# Install GRUB onto the boot disk
# device = config.fileSystems."/boot".device;
# Don't install GRUB, required for UEFI?
device = "nodev";
# Display menu indefinitely if holding shift key
extraConfig = ''
if keystatus --shift ; then
set timeout=-1
else
set timeout=0
fi
'';
};
# Always display menu indefinitely; default is 5 seconds
# timeout = null;
# Allows GRUB to interact with the UEFI/BIOS I guess
efi.canTouchEfiVariables = true;
};
}

View File

@ -0,0 +1,14 @@
{ ... }: {
imports = [
./audio.nix
./boot.nix
./keyboard.nix
./monitors.nix
./mouse.nix
./networking.nix
./sleep.nix
./wifi.nix
];
}

View File

@ -0,0 +1,16 @@
{ ... }: {
services.xserver = {
layout = "us";
# Keyboard responsiveness
autoRepeatDelay = 250;
autoRepeatInterval = 40;
# Swap escape key with caps lock key
xkbOptions = "eurosign:e,caps:swapescape";
};
}

View File

@ -0,0 +1,53 @@
{ config, pkgs, lib, ... }: {
# Timezone required for Redshift schedule
imports = [ ../system/timezone.nix ];
config = lib.mkIf config.gui.enable {
environment.systemPackages = with pkgs;
[
ddcutil # Monitor brightness control
];
# Reduce blue light at night
services.redshift = {
enable = true;
brightness = {
day = "1.0";
night = "1.0";
};
};
# Detect monitors (brightness) for ddcutil
hardware.i2c.enable = true;
# Grant main user access to external monitors
users.users.${config.user}.extraGroups = [ "i2c" ];
services.xserver.displayManager = {
# Put the login screen on the left monitor
lightdm.greeters.gtk.extraConfig = ''
active-monitor=0
'';
# Set up screen position and rotation
setupCommands = ''
${pkgs.xorg.xrandr}/bin/xrandr --output DisplayPort-0 \
--mode 1920x1200 \
--pos 1920x0 \
--rotate left \
--output HDMI-0 \
--primary \
--mode 1920x1080 \
--pos 0x560 \
--rotate normal \
--output DVI-0 --off \
--output DVI-1 --off \
'';
};
};
}

View File

@ -0,0 +1,21 @@
{ config, pkgs, lib, ... }: {
config = lib.mkIf config.gui.enable {
# Mouse customization
services.ratbagd.enable = true;
environment.systemPackages = with pkgs; [
libratbag # Mouse adjustments
piper # Mouse adjustments GUI
];
services.xserver.libinput.mouse = {
# Disable mouse acceleration
accelProfile = "flat";
accelSpeed = "1.15";
};
};
}

View File

@ -0,0 +1,10 @@
{ ... }: {
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
# Per-interface useDHCP will be mandatory in the future, so this generated config
# replicates the default behaviour.
networking.useDHCP = false;
networking.interfaces.enp0s31f6.useDHCP = true;
networking.interfaces.wlp3s0.useDHCP = true;
}

View File

@ -0,0 +1,8 @@
{ ... }: {
# Prevent wake from keyboard
powerManagement.powerDownCommands = ''
for wakeup in /sys/bus/usb/devices/1-*/power/wakeup; do echo disabled > $wakeup; done
'';
}

View File

@ -0,0 +1,9 @@
{ ... }: {
# Enables wireless support via wpa_supplicant.
networking.wireless.enable = true;
# Allows the user to control the WiFi settings.
networking.wireless.userControlled.enable = true;
}

88
modules/mail/himalaya.nix Normal file
View File

@ -0,0 +1,88 @@
{ config, pkgs, lib, ... }: {
options = {
mailServer = lib.mkOption {
type = lib.types.str;
description = "Server name for the email address.";
};
};
config = {
home-manager.users.${config.user} = {
programs.himalaya = { enable = true; };
programs.mbsync = { enable = true; };
services.mbsync = lib.mkIf pkgs.stdenv.isLinux {
enable = true;
frequency = "*:0/5";
};
accounts.email = {
maildirBasePath = "$HOME/mail";
accounts = {
home = let address = "${config.user}@${config.mailServer}";
in {
userName = address;
realName = config.fullName;
primary = true;
inherit address;
aliases = map (mailUser: "${mailUser}@${config.mailServer}") [
"me"
"hey"
"admin"
];
alot = { };
flavor = "plain";
folders = { };
getmail = { };
himalaya = {
enable = true;
settings = {
downloads-dir = config.userDirs.download;
smtp-insecure = true;
};
};
imap = {
host = "imap.purelymail.com";
port = 993;
tls.enable = true;
};
imapnotify = {
enable = false;
boxes = [ ];
onNotify = "";
onNotifyPost = "";
};
maildir = { path = "main"; };
mbsync = {
enable = true;
create = "maildir";
expunge = "none";
remove = "none";
patterns = [ "*" ];
extraConfig.channel = {
CopyArrivalDate = "yes"; # Sync time of original message
};
};
mu.enable = false;
notmuch.enable = false;
passwordCommand =
"${pkgs.age}/bin/age --decrypt --identity ${config.homePath}/.ssh/id_ed25519 ${
builtins.toString ./mailpass.age
}";
smtp = {
host = "smtp.purelymail.com";
port = 465;
tls.enable = true;
};
};
};
};
programs.fish.shellAbbrs = { hi = "himalaya"; };
};
};
}

View File

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 MgHaOw 8h/ESNjn0gknNXoHM34UobHzPgmRunoP97H+KHOuGQM
qowH+6TlCRECGCscRgKx6kswY+PZezYUD6E+x9e+5pM
--- kFj1JzRdh/D13Uq9aNTzMJIFysEE+kzzthjewOIR2+o
Ȳ<EFBFBD><EFBFBD>6<EFBFBD><EFBFBD><EFBFBD>}rC<72>z<><7A><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1,16 @@
{ config, pkgs, lib, ... }: {
home-manager.users.${config.user} = {
programs.gpg.enable = true;
services.gpg-agent = {
enable = true;
defaultCacheTtl = 86400; # Resets when used
defaultCacheTtlSsh = 86400; # Resets when used
maxCacheTtl = 34560000; # Can never reset
maxCacheTtlSsh = 34560000; # Can never reset
pinentryFlavor = "tty";
};
home = lib.mkIf config.gui.enable { packages = with pkgs; [ pinentry ]; };
};
}

View File

@ -0,0 +1,28 @@
{ config, pkgs, lib, ... }: {
services.keybase.enable = true;
services.kbfs = {
enable = true;
# enableRedirector = true;
mountPoint = "/run/user/1000/keybase/kbfs";
};
security.wrappers.keybase-redirector = {
setuid = true;
owner = "root";
group = "root";
source = "${pkgs.kbfs}/bin/redirector";
};
home-manager.users.${config.user} = {
home.packages = [ (lib.mkIf config.gui.enable pkgs.keybase-gui) ];
home.file = let
ignorePatterns = ''
keybase/
kbfs/'';
in {
".rgignore".text = ignorePatterns;
".fdignore".text = ignorePatterns;
};
};
}

View File

@ -0,0 +1,6 @@
{ pkgs, ... }: {
services.mullvad-vpn.enable = true;
environment.systemPackages = [ pkgs.mullvad-vpn ];
}

View File

@ -0,0 +1,18 @@
{ ... }: {
networking.wireguard = {
enable = true;
interfaces = {
wg0 = {
ips = [ "10.66.127.235/32" "fc00:bbbb:bbbb:bb01::3:7fea/128" ];
generatePrivateKeyFile = true;
privateKeyFile = "/private/wireguard/wg0";
peers = [{
publicKey = "cVDIYPzNChIeANp+0jE12kWM5Ga1MbmNErT1Pmaf12A=";
allowedIPs = [ "0.0.0.0/0" "::0/0" ];
endpoint = "89.46.62.197:51820";
persistentKeepalive = 25;
}];
};
};
};
}

5
modules/shell/age.nix Normal file
View File

@ -0,0 +1,5 @@
{ config, pkgs, ... }: {
home-manager.users.${config.user}.home.packages = with pkgs; [ age ];
}

12
modules/shell/default.nix Normal file
View File

@ -0,0 +1,12 @@
{ ... }: {
imports = [
./age.nix
./direnv.nix
./fish
./fzf.nix
./git.nix
./github.nix
./starship.nix
./utilities.nix
];
}

9
modules/shell/direnv.nix Normal file
View File

@ -0,0 +1,9 @@
{ config, ... }: {
home-manager.users.${config.user}.programs.direnv = {
enable = true;
nix-direnv.enable = true;
config = { whitelist = { prefix = [ config.dotfilesPath ]; }; };
};
}

View File

@ -0,0 +1,155 @@
{ config, pkgs, lib, ... }: {
users.users.${config.user}.shell = pkgs.fish;
programs.fish.enable =
true; # Needed for LightDM to remember username (TODO: fix)
home-manager.users.${config.user} = {
# Packages used in abbreviations and aliases
home.packages = with pkgs; [ curl ];
programs.fish = {
enable = true;
functions = {
commandline-git-commits = {
description = "Insert commit into commandline";
body = builtins.readFile ./functions/commandline-git-commits.fish;
};
copy = {
description = "Copy file contents into clipboard";
body = "cat $argv | pbcopy"; # Need to fix for non-macOS
};
edit = {
description = "Open a file in Vim";
body = builtins.readFile ./functions/edit.fish;
};
envs = {
description = "Evaluate a bash-like environment variables file";
body = ''set -gx (cat $argv | tr "=" " " | string split ' ')'';
};
fcd = {
description = "Jump to directory";
argumentNames = "directory";
body = builtins.readFile ./functions/fcd.fish;
};
fish_user_key_bindings = {
body = builtins.readFile ./functions/fish_user_key_bindings.fish;
};
ip = { body = builtins.readFile ./functions/ip.fish; };
json = {
description = "Tidy up JSON using jq";
body = "pbpaste | jq '.' | pbcopy"; # Need to fix for non-macOS
};
ls = { body = "${pkgs.exa}/bin/exa $argv"; };
note = {
description = "Edit or create a note";
argumentNames = "filename";
body = builtins.readFile ./functions/note.fish;
};
recent = {
description = "Open a recent file in Vim";
body = builtins.readFile ./functions/recent.fish;
};
syncnotes = {
description = "Full git commit on notes";
body = builtins.readFile ./functions/syncnotes.fish;
};
};
interactiveShellInit = ''
fish_vi_key_bindings
bind yy fish_clipboard_copy
bind Y fish_clipboard_copy
bind -M visual y fish_clipboard_copy
bind -M default p fish_clipboard_paste
set -g fish_vi_force_cursor
set -g fish_cursor_default block
set -g fish_cursor_insert line
set -g fish_cursor_visual block
set -g fish_cursor_replace_one underscore
'';
loginShellInit = "";
shellAliases = { };
shellAbbrs = {
# Directory aliases
l = "ls -lh";
lh = "ls -lh";
ll = "ls -alhF";
la = "ls -a";
c = "cd";
"-" = "cd -";
mkd = "mkdir -pv";
# System
s = "sudo";
sc = "systemctl";
scs = "systemctl status";
m = "make";
# Tmux
ta = "tmux attach-session";
tan = "tmux attach-session -t noah";
tnn = "tmux new-session -s noah";
# Vim (overwritten by Neovim)
v = "vim";
vl = "vim -c 'normal! `0'";
# Notes
sn = "syncnotes";
# Fun CLI Tools
weather = "curl wttr.in/$WEATHER_CITY";
moon = "curl wttr.in/Moon";
# Cheat Sheets
ssl =
"openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr";
fingerprint = "ssh-keyscan myhost.com | ssh-keygen -lf -";
publickey = "ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub";
forloop = "for i in (seq 1 100)";
# Docker
dc = "$DOTS/bin/docker_cleanup";
dr = "docker run --rm -it";
db = "docker build . -t";
# Terraform
te = "terraform";
# Kubernetes
k = "kubectl";
pods = "kubectl get pods -A";
nodes = "kubectl get nodes";
deploys = "kubectl get deployments -A";
dash = "kube-dashboard";
ks = "k9s";
# Python
py = "python";
po = "poetry";
pr = "poetry run python";
# Rust
ca = "cargo";
};
shellInit = "";
};
home.sessionVariables.fish_greeting = "";
programs.starship.enableFishIntegration = true;
programs.zoxide.enableFishIntegration = true;
programs.fzf.enableFishIntegration = true;
# Provides "command-not-found" options
# Requires activating a manual download
programs.nix-index = {
enable = true;
enableFishIntegration = true;
};
};
}

View File

@ -0,0 +1,6 @@
set commit (git-commits)
if [ $commit ]
commandline -i "$commit"
else
commandline -i HEAD
end

View File

@ -0,0 +1,4 @@
set vimfile (fzf)
and set vimfile (echo $vimfile | tr -d '\r')
and commandline -r "vim $vimfile"
and commandline -f execute

View File

@ -0,0 +1,10 @@
if test -z $directory
set directory "$HOME"
end
if ! test -d $directory
echo "Directory not found: $directory"
return 1
end
set jump (fd -t d . $directory | fzf)
and cd $jump $argv
and commandline -f execute

View File

@ -0,0 +1,14 @@
bind -M insert \co edit
bind -M default \co edit
bind -M insert \ca 'cd ~; and edit; and commandline -a "; cd -"; commandline -f execute'
bind -M default \ca 'cd ~; and edit; and commandline -a "; cd -"; commandline -f execute'
bind -M insert \ce recent
bind -M default \ce recent
bind -M insert \cg commandline-git-commits
bind -M insert \cG 'commandline -i (git rev-parse --show-toplevel 2>/dev/null || echo ".")'
bind -M insert \cf fcd
bind -M default \cf fcd
bind -M insert \cp projects
bind -M default \cp projects
bind -M insert \x1F accept-autosuggestion
bind -M default \x1F accept-autosuggestion

View File

@ -0,0 +1,122 @@
#!/usr/local/bin/fish
function fish_vi_cursor -d 'Set cursor shape for different vi modes'
# If we're not interactive, there is effectively no bind mode.
if not status is-interactive
return
end
# This is hard to test in expect, since the exact sequences depend on the environment.
# Instead disable it.
if set -q FISH_UNIT_TESTS_RUNNING
return
end
# If this variable is set, skip all checks
if not set -q fish_vi_force_cursor
# Emacs Makes All Cursors Suck
if set -q INSIDE_EMACS
return
end
# vte-based terms set $TERM = xterm*, but only gained support in 2015.
# From https://bugzilla.gnome.org/show_bug.cgi?id=720821, it appears it was version 0.40.0
if set -q VTE_VERSION
and test "$VTE_VERSION" -lt 4000 2>/dev/null
return
end
# Similarly, genuine XTerm can do it since v280.
if set -q XTERM_VERSION
and not test (string replace -r "XTerm\((\d+)\)" '$1' -- "$XTERM_VERSION") -ge 280 2>/dev/null
return
end
# We need one of these terms.
# It would be lovely if we could rely on terminfo, but:
# - The "Ss" entry isn't a thing in macOS' old and crusty terminfo
# - It is set for xterm, and everyone and their dog claims to be xterm
#
# So we just don't care about $TERM, unless it is one of the few terminals that actually have their own entry.
#
# Note: Previous versions also checked $TMUX, and made sure that then $TERM was screen* or tmux*.
# We don't care, since we *cannot* handle term-in-a-terms 100% correctly.
if not set -q KONSOLE_PROFILE_NAME
and not test -n "$KONSOLE_VERSION" -a "$KONSOLE_VERSION" -ge 200400 # konsole, but new.
and not set -q ITERM_PROFILE
and not set -q VTE_VERSION # which version is already checked above
and not set -q WT_PROFILE_ID
and not set -q XTERM_VERSION
and not string match -rq '^st(-.*)$' -- $TERM
and not string match -q 'xterm-kitty*' -- $TERM
and not string match -q 'rxvt*' -- $TERM
and not string match -q 'alacritty*' -- $TERM
return
end
# HACK: Explicitly disable on ITERM because of #3696, which is weirdness with multi-line prompts.
# --force-iterm is now deprecated; set $fish_vi_force_cursor instead
if contains -- $argv[1] --force-iterm
set -e argv[1]
else if set -q ITERM_PROFILE
return
end
end
set -l terminal $argv[1]
set -q terminal[1]
or set terminal auto
set -l function
switch "$terminal"
case auto
# Nowadays, konsole does not set $KONSOLE_PROFILE_NAME anymore,
# and it uses the xterm sequences.
if set -q KONSOLE_PROFILE_NAME
set function __fish_cursor_konsole
else if set -q ITERM_PROFILE
set function __fish_cursor_1337
else
set function __fish_cursor_xterm
end
case konsole
set function __fish_cursor_konsole
case xterm
set function __fish_cursor_xterm
end
set -l tmux_prefix
set -l tmux_postfix
if set -q TMUX
set tmux_prefix echo -ne "'\ePtmux;\e'"
set tmux_postfix echo -ne "'\e\\\\'"
end
set -q fish_cursor_unknown
or set -g fish_cursor_unknown block blink
echo "
function fish_vi_cursor_handle --on-variable fish_bind_mode --on-event fish_postexec --on-event fish_focus_in
set -l varname fish_cursor_\$fish_bind_mode
if not set -q \$varname
set varname fish_cursor_unknown
end
$tmux_prefix
$function \$\$varname
$tmux_postfix
end
" | source
echo "
function fish_vi_cursor_handle_preexec --on-event fish_preexec
set -l varname fish_cursor_default
if not set -q \$varname
set varname fish_cursor_unknown
end
$tmux_prefix
$function \$\$varname
$tmux_postfix
end
" | source
end

View File

@ -0,0 +1,14 @@
set gitfile (git status -s \
| fzf \
--height 50% \
-m \
--preview-window right:70% \
--layout reverse \
--preview 'set -l IFS; set gd (git diff --color=always (echo {} | awk \'{$1=$1};1\' | cut -d" " -f2)); if test "$gd"; echo "$gd"; else; bat --color=always (echo {} | awk \'{$1=$1};1\' | cut -d" " -f2); end')
and for gf in $gitfile
set gf (echo $gf \
| awk '{$1=$1};1' \
| cut -d' ' -f2 \
)
and git add $gf
end

View File

@ -0,0 +1,8 @@
set commitline (git log \
--pretty="format:%C(auto)%ar %h%d %s" \
| fzf \
--height 50% \
--preview 'git show --color=always (echo {} | cut -d" " -f4)' \
)
and set commit (echo $commitline | cut -d" " -f4)
and echo $commit

View File

@ -0,0 +1,10 @@
set -l current (git rev-parse --abbrev-ref HEAD | tr -d '\n')
set -l branch (git branch \
--format "%(refname:short)" \
| fzf \
--height 50% \
--header="On $current, $header" \
--preview-window right:70% \
--preview 'git log {} --color=always --pretty="format:%C(auto)%ar %h%d %s"' \
)
and echo $branch

View File

@ -0,0 +1,14 @@
if not count $argv >/dev/null
echo "Must provide filename."
return 1
end
set commitline ( git log \
--follow \
--pretty="format:%C(auto)%ar %h%d %s" \
-- ./$argv \
| fzf \
--height 100% \
--preview "git diff --color=always (echo {} | cut -d' ' -f4)^1..(echo {} | cut -d' ' -f4) -- ./$argv" \
)
and set commit (echo $commitline | cut -d" " -f4)
and echo $commit

View File

@ -0,0 +1,6 @@
set -l branch (git branch 2>/dev/null | grep '^\*' | colrm 1 2)
and set -l command "git push --set-upstream origin $branch"
and commandline -r $command
and commandline -f execute
and echo "git push --set-upstream origin $branch"
and git push --set-upstream origin $branch

View File

@ -0,0 +1,6 @@
set commitline (git log \
--pretty="format:%C(auto)%ar %h%d %s" \
| fzf \
)
and set commit (echo $commitline | cut -d" " -f4 )
and git show $commit

View File

@ -0,0 +1,37 @@
if contains f $argv
switch $argv[1]
case checkout
git-checkout-fuzzy
case add
git-add-fuzzy
case show
git-show-fuzzy
case merge
git-merge-fuzzy
case branch
if test "$argv[2]" = -d
git-delete-fuzzy
else if test "$argv[2]" = -D
git-force-delete-fuzzy
else
echo "Not a fuzzy option."
return 1
end
case reset
set commit (git-commits)
and if test "$argv[2]" = --hard
git reset --hard $commit
else
git reset $commit
end
case "*"
echo "No fuzzy option."
return 1
end
else
if count $argv >/dev/null
command git $argv
else
command git status -sb
end
end

View File

@ -0,0 +1,5 @@
if count $argv >/dev/null
curl ipinfo.io/$argv
else
curl checkip.amazonaws.com
end

View File

@ -0,0 +1,8 @@
if test -n "$filename"
vim $NOTES_PATH/$filename.md
else
set file (ls $NOTES_PATH | fzf)
if [ $status -eq 0 ]
vim $NOTES_PATH/$file
end
end

View File

@ -0,0 +1,4 @@
set vimfile (fd -t f --exec stat -f "%m%t%N" | sort -nr | cut -f2 | fzf)
and set vimfile (echo $vimfile | tr -d '\r')
and commandline -r "vim $vimfile"
and commandline -f execute

View File

@ -0,0 +1,7 @@
set current_dir $PWD
cd $NOTES_PATH
git pull
git add -A
git commit -m autosync
git push
cd $current_dir

View File

@ -0,0 +1,11 @@
set current_dir (pwd)
cd $HOME/dev
find . -type d -name '.git' | while read dir
cd $dir/../
and if test -n (echo (git status -s))
pwd
git status -s
end
cd -
end
cd $current_dir

31
modules/shell/fzf.nix Normal file
View File

@ -0,0 +1,31 @@
{ config, ... }: {
home-manager.users.${config.user} = {
programs.fzf.enable = true;
programs.fish = {
functions = {
projects = {
description = "Jump to a project";
body = ''
set projdir (ls ${config.homePath}/dev/personal | fzf)
and cd ${config.homePath}/dev/personal/$projdir
and commandline -f execute
'';
};
};
shellAbbrs = { lf = "ls -lh | fzf"; };
};
# Global fzf configuration
home.sessionVariables = let fzfCommand = "fd --type file";
in {
FZF_DEFAULT_COMMAND = fzfCommand;
FZF_CTRL_T_COMMAND = fzfCommand;
FZF_DEFAULT_OPTS = "-m --height 50% --border";
};
};
}

125
modules/shell/git.nix Normal file
View File

@ -0,0 +1,125 @@
{ config, pkgs, lib, ... }:
let home-packages = config.home-manager.users.${config.user}.home.packages;
in {
options = {
fullName = lib.mkOption {
type = lib.types.str;
description = "Human readable name of the user";
};
gitEmail = lib.mkOption {
type = lib.types.str;
description = "Email to use for git commits";
};
};
config = {
home-manager.users.root.programs.git = {
enable = true;
extraConfig.safe.directory = config.dotfilesPath;
};
home-manager.users.${config.user} = {
programs.git = {
enable = true;
userName = config.fullName;
userEmail = config.gitEmail;
extraConfig = {
pager = { branch = "false"; };
safe = { directory = config.dotfilesPath; };
pull = { ff = "only"; };
init = { defaultBranch = "master"; };
};
};
programs.fish.shellAbbrs = {
g = "git";
gs = "git status";
gd = "git diff";
gds = "git diff --staged";
gdp = "git diff HEAD^";
ga = "git add";
gaa = "git add -A";
gac = "git commit -am";
gc = "git commit -m";
gca = "git commit --amend --no-edit";
gcae = "git commit --amend";
gu = "git pull";
gp = "git push";
gpp = "git-push-upstream";
gl = "git log --graph --decorate --oneline -20";
gll = "git log --graph --decorate --oneline";
gco = "git checkout";
gcom = ''
git switch (git symbolic-ref refs/remotes/origin/HEAD | cut -d"/" -f4)'';
gcob = "git switch -c";
gb = "git branch";
gbd = "git branch -d";
gbD = "git branch -D";
gr = "git reset";
grh = "git reset --hard";
gm = "git merge";
gcp = "git cherry-pick";
cdg = "cd (git rev-parse --show-toplevel)";
};
programs.fish.functions = lib.mkIf (builtins.elem pkgs.fzf home-packages
&& builtins.elem pkgs.bat home-packages) {
git = { body = builtins.readFile ./fish/functions/git.fish; };
git-add-fuzzy = {
body = builtins.readFile ./fish/functions/git-add-fuzzy.fish;
};
git-fuzzy-branch = {
argumentNames = "header";
body = builtins.readFile ./fish/functions/git-fuzzy-branch.fish;
};
git-checkout-fuzzy = {
body = ''
set branch (git-fuzzy-branch "checkout branch...")
and git checkout $branch
'';
};
git-delete-fuzzy = {
body = ''
set branch (git-fuzzy-branch "delete branch...")
and git branch -d $branch
'';
};
git-force-delete-fuzzy = {
body = ''
set branch (git-fuzzy-branch "force delete branch...")
and git branch -D $branch
'';
};
git-merge-fuzzy = {
body = ''
set branch (git-fuzzy-branch "merge from...")
and git merge $branch
'';
};
git-show-fuzzy = {
body = builtins.readFile ./fish/functions/git-show-fuzzy.fish;
};
git-commits = {
body = builtins.readFile ./fish/functions/git-commits.fish;
};
git-history = {
body = builtins.readFile ./fish/functions/git-history.fish;
};
git-push-upstream = {
description = "Create upstream branch";
body = builtins.readFile ./fish/functions/git-push-upstream.fish;
};
uncommitted = {
description = "Find uncommitted git repos";
body = builtins.readFile ./fish/functions/uncommitted.fish;
};
};
};
};
}

36
modules/shell/github.nix Normal file
View File

@ -0,0 +1,36 @@
{ config, pkgs, lib, ... }: {
home-manager.users.${config.user} = {
programs.gh =
lib.mkIf config.home-manager.users.${config.user}.programs.git.enable {
enable = true;
enableGitCredentialHelper = true;
settings.git_protocol = "https";
};
programs.fish =
lib.mkIf config.home-manager.users.${config.user}.programs.gh.enable {
shellAbbrs = {
ghr = "gh repo view -w";
gha =
"gh run list | head -1 | awk '{ print $(NF-2) }' | xargs gh run view";
grw = "gh run watch";
grf = "gh run view --log-failed";
grl = "gh run view --log";
};
functions = {
repos = {
description = "Clone GitHub repositories";
argumentNames = "organization";
body = ''
set directory (gh-repos $organization)
and cd $directory
'';
};
};
};
};
}

View File

@ -0,0 +1,54 @@
{ config, lib, ... }: {
home-manager.users.${config.user}.programs.starship = {
enable = true;
settings = {
add_newline = false; # Don't print new line at the start of the prompt
format = lib.concatStrings [
"$directory"
"$git_branch"
"$git_commit"
"$git_status"
"$python"
"$cmd_duration"
"$character"
];
character = {
success_symbol = "[](bold green)";
error_symbol = "[](bold red)";
vicmd_symbol = "[](bold green)";
};
cmd_duration = {
min_time = 5000;
show_notifications = true;
min_time_to_notify = 30000;
format = "[$duration]($style) ";
};
directory = {
truncate_to_repo = true;
truncation_length = 100;
};
git_branch = { format = "[$symbol$branch]($style)"; };
git_commit = {
format = "( @ [$hash]($style) )";
only_detached = false;
};
git_status = {
format = "([$all_status$ahead_behind]($style) )";
conflicted = "=";
ahead = "";
behind = "";
diverged = "";
untracked = "";
stashed = "";
modified = "";
staged = "+";
renamed = "»";
deleted = "";
style = "red";
};
python = { format = "[\\($virtualenv\\)]($style)"; };
};
};
}

Some files were not shown because too many files have changed in this diff Show More