mirror of
https://github.com/nmasur/dotfiles
synced 2025-07-05 15:00:14 +00:00
change macos directory layout
This commit is contained in:
120
macos/hammerspoon/Spoons/ControlEscape.spoon/init.lua
Normal file
120
macos/hammerspoon/Spoons/ControlEscape.spoon/init.lua
Normal 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
|
@ -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();
|
||||
}
|
17
macos/hammerspoon/Spoons/DismissAlerts.spoon/init.lua
Normal file
17
macos/hammerspoon/Spoons/DismissAlerts.spoon/init.lua
Normal 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
|
110
macos/hammerspoon/Spoons/Launcher.spoon/init.lua
Normal file
110
macos/hammerspoon/Spoons/Launcher.spoon/init.lua
Normal 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
|
24
macos/hammerspoon/Spoons/MoveWindow.spoon/init.lua
Normal file
24
macos/hammerspoon/Spoons/MoveWindow.spoon/init.lua
Normal file
@ -0,0 +1,24 @@
|
||||
--- === 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()
|
||||
-- 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:move(win:frame():toUnitRect(screen:frame()), screen:next(), true, 0)
|
||||
end)
|
||||
end
|
||||
|
||||
return obj
|
4
macos/hammerspoon/init.lua
Normal file
4
macos/hammerspoon/init.lua
Normal 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()
|
38
macos/homebrew/Caskfile
Normal file
38
macos/homebrew/Caskfile
Normal file
@ -0,0 +1,38 @@
|
||||
tap "homebrew/cask"
|
||||
|
||||
# Core Applications
|
||||
cask "alacritty" # Terminal
|
||||
cask "firefox" # Browser
|
||||
#cask "slack" # Chat
|
||||
#cask "zoomus" # Video conference
|
||||
cask "1password" # Passwords
|
||||
cask "dropbox" # File sync
|
||||
#cask "docker" # Containers
|
||||
|
||||
# Helpful Applications
|
||||
cask "obsidian" # Notes
|
||||
|
||||
# Auxiliary Tools
|
||||
cask "scroll-reverser" # Mouse vs. trackpad
|
||||
cask "meetingbar" # Scheduling
|
||||
cask "gitify" # GitHub notifications
|
||||
# cask "basictex" # Small LaTeX distribution
|
||||
cask "hammerspoon"
|
||||
|
||||
tap "homebrew/cask-drivers"
|
||||
cask "logitech-g-hub" # Hardware drivers
|
||||
|
||||
# Fonts
|
||||
tap "homebrew/cask-fonts"
|
||||
cask "font-fira-mono-nerd-font"
|
||||
|
||||
# Personal
|
||||
cask "keybase" # Encryption
|
||||
cask "discord" # Chat
|
||||
#cask "steam" # Games
|
||||
#cask "epic-games" # Games
|
||||
#cask "calibre" # E-Books
|
||||
#cask "signal" # Messaging
|
||||
|
||||
# Maybe
|
||||
#cask "jira-client" # Project Management
|
17
macos/homebrew/core.Brewfile
Normal file
17
macos/homebrew/core.Brewfile
Normal file
@ -0,0 +1,17 @@
|
||||
# Core Packages
|
||||
|
||||
brew "fish" # Shell
|
||||
brew "neovim" # Editor
|
||||
brew "tmux" # Terminal panes and windows
|
||||
brew "starship" # Shell prompt
|
||||
brew "git" # Latest git
|
||||
brew "ripgrep" # Faster, better grep
|
||||
brew "fd" # Faster, better find
|
||||
brew "sd" # Faster, better sed
|
||||
brew "zoxide" # Faster, better autojump
|
||||
brew "exa" # Better ls
|
||||
brew "bat" # Better cat
|
||||
brew "fzf" # Fuzzy finder
|
||||
brew "tealdeer" # Mini man page
|
||||
brew "direnv" # Environment variables
|
||||
brew "glow" # Markdown previews
|
14
macos/homebrew/devops.Brewfile
Normal file
14
macos/homebrew/devops.Brewfile
Normal file
@ -0,0 +1,14 @@
|
||||
# DevOps Packages
|
||||
|
||||
tap "nmasur/repo"
|
||||
tap "hashicorp/tap"
|
||||
|
||||
brew "ansible" # Deploy to local server
|
||||
brew "terraform" # Deploy cloud infra
|
||||
brew "packer" # Build deployment images
|
||||
brew "awscli" # AWS API tools
|
||||
brew "kubectl" # Kubernetes CLI
|
||||
brew "k9s" # Kubernetes TUI
|
||||
brew "nmasur/repo/drips" # Retrieve AWS IPs
|
||||
brew "hashicorp/tap/terraform-ls"
|
||||
brew "tflint"
|
8
macos/homebrew/fun.Brewfile
Normal file
8
macos/homebrew/fun.Brewfile
Normal file
@ -0,0 +1,8 @@
|
||||
# Fun / Unnecessary Packages
|
||||
|
||||
#tap "nmasur/repo"
|
||||
#tap "tarkah/tickrs"
|
||||
|
||||
#brew "ffmpeg" # Convert videos
|
||||
#brew "nmasur/repo/bee" # Cheat on NYTimes Spelling Bee
|
||||
#brew "tarkah/tickrs/tickrs" # Interactive stock tickers
|
17
macos/homebrew/learning.Brewfile
Normal file
17
macos/homebrew/learning.Brewfile
Normal file
@ -0,0 +1,17 @@
|
||||
# Still Learning Tools
|
||||
|
||||
tap "superfly/tap"
|
||||
tap "nmasur/repo"
|
||||
tap "cjbassi/ytop"
|
||||
|
||||
#brew "superfly/tap/flyctl" # Fly.io CLI
|
||||
#brew "ghc" # Haskell
|
||||
#brew "xsv" # CSV manipulation
|
||||
#brew "gron" # JSON grep
|
||||
#brew "nushell" # Data manipulation shell
|
||||
#brew "tectonic" # Minimal LaTeX compiler
|
||||
brew "noti" # Create system notifications
|
||||
#brew "b2-tools" # BackBlaze B2 storage
|
||||
#brew "cjbassi/ytop/ytop" # Fancy system performance
|
||||
#brew "nmasur/repo/update-ssh-config" # Update .ssh/config
|
||||
brew "awslogs" # View AWS log streams
|
10
macos/homebrew/programming.Brewfile
Normal file
10
macos/homebrew/programming.Brewfile
Normal file
@ -0,0 +1,10 @@
|
||||
# Programming Packages
|
||||
|
||||
brew "shellcheck" # Lint for bash
|
||||
brew "shfmt" # Formatter for bash
|
||||
brew "stylua" # Formatter for lua
|
||||
brew "python" # Latest version of Python
|
||||
brew "ipython" # Better interactive Python shell
|
||||
brew "poetry" # Project-based Python dependencies
|
||||
brew "ruby" # Newer than default ruby
|
||||
brew "node" # NodeJS
|
20
macos/homebrew/utils.Brewfile
Normal file
20
macos/homebrew/utils.Brewfile
Normal file
@ -0,0 +1,20 @@
|
||||
# Utility Packages
|
||||
|
||||
tap "saulpw/vd"
|
||||
|
||||
brew "jq" # JSON manipulation
|
||||
brew "dos2unix" # File conversion
|
||||
brew "tree" # Display directory trees
|
||||
brew "trash" # Delete to trash
|
||||
brew "wget" # Not quite curl
|
||||
brew "telnet" # Check networking
|
||||
brew "prettyping" # Better ping
|
||||
brew "httpie" # Better curl
|
||||
brew "gpg" # Encryption
|
||||
brew "qrencode" # Make a QR code
|
||||
brew "mpv" # Video player
|
||||
brew "youtube-dl" # Download YouTube videos
|
||||
brew "gh" # GitHub commands
|
||||
brew "pandoc" # Document converter
|
||||
brew "saulpw/vd/visidata" # Spreadsheet manipulation
|
||||
brew "mdp" # Terminal slideshows
|
28
macos/newsboat/com.noah.newsboat.plist
Normal file
28
macos/newsboat/com.noah.newsboat.plist
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.noah.newsboat</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/newsboat -x reload</string>
|
||||
</array>
|
||||
|
||||
<key>Nice</key>
|
||||
<integer>1</integer>
|
||||
|
||||
<key>StartInterval</key>
|
||||
<integer>1800</integer>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<false/>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/newsboat.err</string>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/newsboat.out</string>
|
||||
</dict>
|
||||
</plist>
|
40
macos/newsboat/config
Normal file
40
macos/newsboat/config
Normal file
@ -0,0 +1,40 @@
|
||||
browser "$BROWSER %u"
|
||||
prepopulate-query-feeds yes
|
||||
feed-sort-order lastupdated
|
||||
reload-only-visible-feeds yes
|
||||
text-width 72
|
||||
|
||||
bind-key j down
|
||||
bind-key k up
|
||||
bind-key j next articlelist
|
||||
bind-key k prev articlelist
|
||||
bind-key G end
|
||||
bind-key g home
|
||||
bind-key d pagedown
|
||||
bind-key u pageup
|
||||
bind-key n next-unread
|
||||
bind-key p prev-unread
|
||||
bind-key ; macro-prefix
|
||||
bind-key B bookmark
|
||||
bind-key f edit-flags
|
||||
|
||||
macro v set browser "mpv %u"; open-in-browser; set browser "$BROWSER %u"
|
||||
macro p set browser "echo %u"; one; set browser "$BROWSER %u"
|
||||
macro H set browser "clx view $(echo %u | cut -d '=' -f2)"; one; set browser "$BROWSER %u"
|
||||
macro h set browser "clx view $(echo %u | cut -d '=' -f2)"; two; set browser "$BROWSER %u"
|
||||
macro w set browser "w3m -o confirm_qq=false %u"; open-in-browser; set browser "$BROWSER %u"
|
||||
macro r set browser "url-markdown %u | glow -p -w 72 -"; open-in-browser; set browser "$BROWSER %u"
|
||||
macro d set browser "youtube-dl -o ~/Downloads/%(title)s.%(ext)s %u &"; open-in-browser-noninteractively; set browser "$BROWSER %u"
|
||||
macro n set-tag News; reload-all
|
||||
macro a set-tag All
|
||||
macro e set-tag Reddit; reload-all
|
||||
macro y set-tag YouTube; reload-all
|
||||
|
||||
bookmark-cmd "bookmark"
|
||||
|
||||
highlight article "^(Feed|Title|Author|Link|Date):.*" color243 default
|
||||
highlight article "^(Links):.*" color243 default
|
||||
highlight article "^(\\[[0-9]+\\]):.*" color243 default
|
||||
highlight article "^(\\[[0-9]+\\])" color243 default
|
||||
highlight article "^\\[.*\\]$" color243 default
|
||||
highlight article "^(Title:).*" color249 default
|
79
macos/scripts/bootstrap
Executable file
79
macos/scripts/bootstrap
Executable file
@ -0,0 +1,79 @@
|
||||
#!/bin/sh
|
||||
|
||||
DOTS=$(dirname "$0")/..
|
||||
cd "$DOTS" || (echo "Directory not found: $DOTS"; exit 1)
|
||||
DOTS="$PWD"
|
||||
|
||||
install_xcode() {
|
||||
if [ "$(uname)" = "Darwin" ]
|
||||
then
|
||||
if ! (xcode-select --version > /dev/null 2>&1)
|
||||
then
|
||||
xcode-select --install
|
||||
fi
|
||||
echo "xcode ✓"
|
||||
fi
|
||||
}
|
||||
|
||||
install_homebrew() {
|
||||
if ! (which /usr/local/bin/brew > /dev/null)
|
||||
then
|
||||
printf "homebrew ✕\n\n"
|
||||
printf "\ninstalling homebrew..."
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "homebrew ✓"
|
||||
}
|
||||
|
||||
install_brews() {
|
||||
brewfile=$DOTS/homebrew/core.Brewfile
|
||||
if ! (/usr/local/bin/brew bundle check --file "$brewfile" > /dev/null)
|
||||
then
|
||||
/usr/local/bin/brew bundle --file "$brewfile"
|
||||
fi
|
||||
|
||||
echo "brews installed ✓"
|
||||
}
|
||||
|
||||
use_fish_shell() {
|
||||
if ! (which fish > /dev/null)
|
||||
then
|
||||
echo "Install fish before continuing"
|
||||
echo "You can do: brew install fish"
|
||||
echo "Or add fish to homebrew/Brewfile and rerun"
|
||||
exit 1
|
||||
fi
|
||||
FISH_SHELL=$(which fish)
|
||||
if ! (grep "$FISH_SHELL" /etc/shells > /dev/null)
|
||||
then
|
||||
echo "Modifying /etc/shells"
|
||||
echo "Requires sudo password"
|
||||
echo "$FISH_SHELL" | sudo tee -a /etc/shells
|
||||
fi
|
||||
if ! (echo "$SHELL" | grep fish > /dev/null)
|
||||
then
|
||||
echo "Changing default shell to fish"
|
||||
echo "Requires sudo password"
|
||||
sudo chsh -s "$FISH_SHELL"
|
||||
fi
|
||||
|
||||
echo "fish ✓"
|
||||
}
|
||||
|
||||
printf "\nbootstrapping...\n\n"
|
||||
install_xcode
|
||||
install_homebrew
|
||||
install_brews
|
||||
use_fish_shell
|
||||
("$DOTS/scripts/setup_symlinks")
|
||||
|
||||
echo ""
|
||||
echo "consider running other scripts:"
|
||||
echo " - brews"
|
||||
echo " - casks"
|
||||
echo " - configure_macos"
|
||||
echo " - rust"
|
||||
echo " - cargos"
|
||||
echo ""
|
15
macos/scripts/brews
Executable file
15
macos/scripts/brews
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
DOTS=$(dirname "$0")/..
|
||||
cd "$DOTS" || (echo "Directory not found: $DOTS"; exit 1)
|
||||
DOTS="$PWD"
|
||||
|
||||
all_brews() {
|
||||
find "$DOTS/homebrew" \
|
||||
-iname "*.Brewfile" \
|
||||
-exec \
|
||||
/usr/local/bin/brew bundle install --file "{}" \;
|
||||
echo "all brews installed ✓"
|
||||
}
|
||||
|
||||
all_brews
|
26
macos/scripts/cargos
Executable file
26
macos/scripts/cargos
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
DOTS=$(dirname "$0")/..
|
||||
cd "$DOTS" || (echo "Directory not found: $DOTS"; exit 1)
|
||||
DOTS="$PWD"
|
||||
|
||||
check_rust() {
|
||||
if ! (which ~/.cargo/bin/rustup > /dev/null)
|
||||
then
|
||||
echo "Install rust (cargo) before continuing"
|
||||
echo "Run the rust script before this one"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
all_cargos() {
|
||||
cargofile=$DOTS/cargo/Cargofile
|
||||
sed 's/#.*$//g;/^$/d' "$cargofile" | while read -r line
|
||||
do
|
||||
cargo install "$line"
|
||||
done \
|
||||
&& echo "all cargos installed ✓"
|
||||
}
|
||||
|
||||
check_rust
|
||||
all_cargos
|
11
macos/scripts/casks
Executable file
11
macos/scripts/casks
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
install_casks() {
|
||||
brewfile=$DOTS/homebrew/Caskfile
|
||||
if ! (/usr/local/bin/brew bundle check --file "$brewfile" > /dev/null)
|
||||
then
|
||||
/usr/local/bin/brew bundle --file "$brewfile"
|
||||
fi
|
||||
|
||||
echo "casks installed ✓"
|
||||
}
|
168
macos/scripts/configure_macos
Executable file
168
macos/scripts/configure_macos
Executable file
@ -0,0 +1,168 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Enable full keyboard access for all controls (e.g. enable Tab in modal dialogs)"
|
||||
defaults write NSGlobalDomain AppleKeyboardUIMode -int 3
|
||||
|
||||
echo "Automatically show and hide the dock"
|
||||
defaults write com.apple.dock autohide -bool true
|
||||
|
||||
echo "Automatically show and hide the menu bar"
|
||||
defaults write NSGlobalDomain _HIHideMenuBar -bool true
|
||||
|
||||
echo "Make Dock icons of hidden applications translucent"
|
||||
defaults write com.apple.dock showhidden -bool true
|
||||
|
||||
echo "Use current directory as default search scope in Finder"
|
||||
defaults write com.apple.finder FXDefaultSearchScope -string "SCcf"
|
||||
|
||||
echo "Expand save panel by default"
|
||||
defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true
|
||||
|
||||
echo "Expand print panel by default"
|
||||
defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true
|
||||
|
||||
echo "Disable the \"Are you sure you want to open this application?\" dialog"
|
||||
defaults write com.apple.LaunchServices LSQuarantine -bool false
|
||||
|
||||
echo "Enable highlight hover effect for the grid view of a stack (Dock)"
|
||||
defaults write com.apple.dock mouse-over-hilte-stack -bool true
|
||||
|
||||
echo "Enable spring loading for all Dock items"
|
||||
defaults write enable-spring-load-actions-on-all-items -bool true
|
||||
|
||||
echo "Disable press-and-hold for keys in favor of key repeat"
|
||||
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
|
||||
defaults write -g ApplePressAndHoldEnabled -bool false
|
||||
|
||||
echo "Set a blazingly fast keyboard repeat rate"
|
||||
defaults write NSGlobalDomain KeyRepeat -int 2
|
||||
|
||||
echo "Set a shorter Delay until key repeat"
|
||||
defaults write NSGlobalDomain InitialKeyRepeat -int 12
|
||||
|
||||
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 when changing a file extension"
|
||||
defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false
|
||||
|
||||
# echo "Enable snap-to-grid for desktop icons"
|
||||
# /usr/libexec/PlistBuddy -c "Set :DesktopViewSettings:IconViewSettings:arrangeBy grid" ~/Library/Preferences/com.apple.finder.plist
|
||||
|
||||
echo "Disable the warning before emptying the Trash"
|
||||
defaults write com.apple.finder WarnOnEmptyTrash -bool false
|
||||
|
||||
echo "Disable tap to click (Trackpad)"
|
||||
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool false
|
||||
|
||||
echo "Enable Safari’s debug menu"
|
||||
defaults write com.apple.Safari IncludeInternalDebugMenu -bool true
|
||||
|
||||
echo "Make Safari’s search banners default to Contains instead of Starts With"
|
||||
defaults write com.apple.Safari FindOnPageMatchesWordStartsOnly -bool false
|
||||
|
||||
echo "Add a context menu item for showing the Web Inspector in web views"
|
||||
defaults write NSGlobalDomain WebKitDeveloperExtras -bool true
|
||||
|
||||
echo "Save to disk (not to iCloud) by default"
|
||||
defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false
|
||||
|
||||
echo "Disable automatic capitalization as it’s annoying when typing code"
|
||||
defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false
|
||||
|
||||
echo "Disable smart dashes as they’re annoying when typing code"
|
||||
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
|
||||
|
||||
echo "Disable automatic period substitution as it’s annoying when typing code"
|
||||
defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false
|
||||
|
||||
echo "Disable smart quotes as they’re annoying when typing code"
|
||||
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
|
||||
|
||||
echo "Disable auto-correct"
|
||||
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
|
||||
|
||||
echo "Use scroll gesture with the Ctrl (^) modifier key to zoom"
|
||||
defaults write com.apple.universalaccess closeViewScrollWheelToggle -bool true
|
||||
defaults write com.apple.universalaccess HIDScrollZoomModifierMask -int 262144
|
||||
echo "Follow the keyboard focus while zoomed in"
|
||||
defaults write com.apple.universalaccess closeViewZoomFollowsFocus -bool true
|
||||
|
||||
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 "Save screenshots to downloads"
|
||||
defaults write com.apple.screencapture location -string "${HOME}/Downloads"
|
||||
|
||||
echo "Finder: allow quitting via ⌘ + Q; doing so will also hide desktop icons"
|
||||
defaults write com.apple.finder QuitMenuItem -bool true
|
||||
|
||||
echo "Show the ~/Library folder"
|
||||
chflags nohidden ~/Library && xattr -d com.apple.FinderInfo ~/Library
|
||||
|
||||
# Noah Prefs
|
||||
echo "Enable dock magnification"
|
||||
defaults write com.apple.dock magnification -bool true
|
||||
|
||||
echo "Set dock size"
|
||||
defaults write com.apple.dock largesize -int 48
|
||||
defaults write com.apple.dock tilesize -int 44
|
||||
|
||||
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\ 7.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 "No recent items in dock"
|
||||
defaults write com.apple.dock show-recents -bool FALSE
|
||||
|
||||
echo "Switch to dark mode"
|
||||
defaults write "Apple Global Domain" "AppleInterfaceStyle" "Dark"
|
||||
|
||||
echo "Turn on Scroll Reverser"
|
||||
open /Applications/Scroll\ Reverser.app
|
||||
osascript -e 'tell application "System Events" to make login item at end with properties {path:"/Applications/Scroll Reverser.app", hidden:false}'
|
||||
|
||||
echo "Allow apps from anywhere"
|
||||
SPCTL=$(spctl --status)
|
||||
if ! [ "$SPCTL" = "assessments disabled" ]
|
||||
then
|
||||
sudo spctl --master-disable
|
||||
fi
|
||||
|
||||
# ---
|
||||
|
||||
echo "Reset Launchpad"
|
||||
# [ -e ~/Library/Application\ Support/Dock/*.db ] && rm ~/Library/Application\ Support/Dock/*.db
|
||||
rm ~/Library/Application\ Support/Dock/*.db
|
||||
|
||||
echo "Show the ~/Library folder"
|
||||
chflags nohidden ~/Library
|
||||
|
||||
# Clean up
|
||||
echo "Kill affected applications"
|
||||
for app in Safari Finder Dock Mail SystemUIServer; do killall "$app" >/dev/null 2>&1; done
|
5
macos/scripts/npm
Executable file
5
macos/scripts/npm
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
npm update -g
|
||||
npm install -g pyright
|
||||
npm install -g diagnostic-languageserver
|
48
macos/scripts/rust
Executable file
48
macos/scripts/rust
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
|
||||
install_rust() {
|
||||
if ! (which ~/.cargo/bin/rustup > /dev/null)
|
||||
then
|
||||
echo "installing rustup"
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
fi
|
||||
|
||||
echo "rustup ✓"
|
||||
}
|
||||
|
||||
update_rust() {
|
||||
~/.cargo/bin/rustup update > /dev/null 2>&1
|
||||
rust_version=$(~/.cargo/bin/rustc --version | awk '{print $2}')
|
||||
|
||||
echo "latest rust: $rust_version ✓"
|
||||
}
|
||||
|
||||
download_rust_analyzer() {
|
||||
if ! (which rust-analyzer > /dev/null)
|
||||
then
|
||||
echo "downloading rust analyzer"
|
||||
rust_analyzer_bin=/usr/local/bin/rust-analyzer
|
||||
curl -s -L https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/rust-analyzer-mac -o $rust_analyzer_bin
|
||||
chmod +x $rust_analyzer_bin
|
||||
fi
|
||||
|
||||
echo "rust-analyzer ✓"
|
||||
}
|
||||
|
||||
# cargo-edit: quickly add and remove packages
|
||||
# whatfeatures: see optional features for a package
|
||||
install_cargos() {
|
||||
set -- \
|
||||
'cargo-edit' \
|
||||
'cargo-whatfeatures'
|
||||
for program do
|
||||
cargo install "$program"
|
||||
done
|
||||
|
||||
echo "cargos ✓"
|
||||
}
|
||||
|
||||
install_rust
|
||||
update_rust
|
||||
download_rust_analyzer
|
||||
install_cargos
|
6
macos/scripts/setup_cheatsheet
Executable file
6
macos/scripts/setup_cheatsheet
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "downloading cheatsheet"
|
||||
curl https://cht.sh/:cht.sh > ~/.local/bin/cheat
|
||||
chmod 755 ~/.local/bin/cheat
|
||||
echo "cheatsheet ✓"
|
46
macos/scripts/setup_fish
Executable file
46
macos/scripts/setup_fish
Executable file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env fish
|
||||
|
||||
set -U FISH_DIR (readlink ~/.config/fish) # Used for getting to this repo
|
||||
set -Ux DOTS (dirname $FISH_DIR) # Directory of this config repo
|
||||
set -U CDPATH . $HOME # Directories available for immediate cd
|
||||
set -Ux EDITOR nvim # Preferred text editor
|
||||
set -U PROJ $HOME/dev/work # Projects directory
|
||||
set -Ux NOTES_PATH "$HOME/dev/personal/notes" # Notes directory
|
||||
set -Ux MANPAGER "nvim +Man!" # Used for reading man pages
|
||||
set -Ux DIRENV_LOG_FORMAT "" # Disable direnv output
|
||||
set -Ux BROWSER "/Applications/Firefox.app/Contents/MacOS/firefox"
|
||||
|
||||
# Load abbreviations
|
||||
abbrs
|
||||
|
||||
# Turn off greeting
|
||||
set -U fish_greeting ""
|
||||
|
||||
# Set colors (Base16 Eighties)
|
||||
set -U fish_color_normal normal
|
||||
set -U fish_color_command 99cc99
|
||||
set -U fish_color_quote ffcc66
|
||||
set -U fish_color_redirection d3d0c8
|
||||
set -U fish_color_end cc99cc
|
||||
set -U fish_color_error f2777a
|
||||
set -U fish_color_selection white --bold --background=brblack
|
||||
set -U fish_color_search_match bryellow --background=brblack
|
||||
set -U fish_color_history_current --bold
|
||||
set -U fish_color_operator 6699cc
|
||||
set -U fish_color_escape 66cccc
|
||||
set -U fish_color_cwd green
|
||||
set -U fish_color_cwd_root red
|
||||
set -U fish_color_valid_path --underline
|
||||
set -U fish_color_autosuggestion 747369
|
||||
set -U fish_color_user brgreen
|
||||
set -U fish_color_host normal
|
||||
set -U fish_color_cancel -r
|
||||
set -U fish_pager_color_completion normal
|
||||
set -U fish_pager_color_description B3A06D yellow
|
||||
set -U fish_pager_color_prefix white --bold --underline
|
||||
set -U fish_pager_color_progress brwhite --background=cyan
|
||||
set -U fish_color_comment ffcc66
|
||||
set -U fish_color_param d3d0c8
|
||||
set -U fish_color_match 6699cc
|
||||
|
||||
echo "fish setup ✓"
|
29
macos/scripts/setup_symlinks
Executable file
29
macos/scripts/setup_symlinks
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
DOTS=$(dirname "$0")/..
|
||||
cd "$DOTS" || (echo "Directory not found: $DOTS"; exit 1)
|
||||
DOTS="$PWD"
|
||||
|
||||
setup_symlinks() {
|
||||
for source in $(find "$DOTS" -iname "*.symlink")
|
||||
do
|
||||
dest="$HOME/.`basename \"${source%.*}\"`"
|
||||
ln -sfn "$source" "$dest"
|
||||
done
|
||||
|
||||
echo "symlinks ✓"
|
||||
}
|
||||
|
||||
setup_configlinks() {
|
||||
for source in $(find "$DOTS" -iname "*.configlink")
|
||||
do
|
||||
dest="$HOME/.config/`basename \"${source%.*}\"`"
|
||||
ln -sfn "$source" "$dest"
|
||||
done
|
||||
|
||||
echo "configlinks ✓"
|
||||
}
|
||||
|
||||
setup_symlinks
|
||||
setup_configlinks
|
||||
|
7
macos/scripts/setup_ytfzf
Executable file
7
macos/scripts/setup_ytfzf
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "downloading ytfzf"
|
||||
mkdir -p ~/.local/bin
|
||||
curl -sL "https://raw.githubusercontent.com/pystardust/ytfzf/master/ytfzf" >~/.local/bin/ytfzf
|
||||
chmod 755 ~/.local/bin/ytfzf
|
||||
echo "ytfzf ✓"
|
19
macos/scripts/update_rust_analyzer
Executable file
19
macos/scripts/update_rust_analyzer
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
update_rust_analyzer() {
|
||||
if ! (which rust-analyzer > /dev/null)
|
||||
then
|
||||
echo "not installed"
|
||||
else
|
||||
echo "removing"
|
||||
rm /usr/local/bin/rust-analyzer
|
||||
fi
|
||||
echo "downloading rust analyzer"
|
||||
rust_analyzer_bin=/usr/local/bin/rust-analyzer
|
||||
curl -s -L https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/rust-analyzer-mac -o $rust_analyzer_bin
|
||||
chmod +x $rust_analyzer_bin
|
||||
|
||||
echo "rust-analyzer ✓"
|
||||
}
|
||||
|
||||
update_rust_analyzer
|
102
macos/tmux/tmux.conf.symlink
Normal file
102
macos/tmux/tmux.conf.symlink
Normal file
@ -0,0 +1,102 @@
|
||||
# Colors for CoC
|
||||
set-option -g default-terminal "screen-256color"
|
||||
|
||||
# Keep plenty of history for scrollback
|
||||
set -g history-limit 100000
|
||||
|
||||
# Remove delay for entering copy mode
|
||||
set-option -sg escape-time 0
|
||||
|
||||
# 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
|
||||
bind C-h resize-pane -L 10
|
||||
bind C-l resize-pane -R 10
|
||||
|
||||
# Copy mode works as Vim
|
||||
bind Escape copy-mode
|
||||
bind k copy-mode
|
||||
bind C-[ copy-mode
|
||||
|
||||
# Vi-style scrollback with prefix + C-[
|
||||
set-window-option -g mode-keys vi
|
||||
|
||||
# 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 base-index 1 # Set 1 for first window (easier to type)
|
||||
set-window-option -g pane-base-index 1 # Set 1 for first pane (easier to type)
|
||||
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 ""
|
||||
|
||||
WEATHER='#(weather_cached)'
|
||||
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]#[fg=colour237, nobold, bg=colour248] $WEATHER #[fg=colour237] "
|
||||
|
||||
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]"
|
Reference in New Issue
Block a user