Reorganize imports

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2024-12-21 23:32:29 +02:00
parent 0ae56e6e25
commit 98ce774210
189 changed files with 253 additions and 260 deletions

View File

@@ -0,0 +1,26 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
{
nixpkgs.overlays = [
(final: prev: {
android-tools = prev.android-tools.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./env-var-user-home.patch ];
});
})
];
programs.adb.enable = true;
services.gvfs.enable = true;
users.users.${user}.extraGroups = [ "adbusers" ];
environment.persistence."/persist" = {
"${home}/.local/share/android/adbkey" = { };
"${home}/.local/share/android/adbkey.pub" = { };
};
home-manager.users.${user}.home.sessionVariables.ANDROID_USER_HOME = "${home}/.local/share/android";
}

View File

@@ -0,0 +1,21 @@
--- a/vendor/adb/adb_utils.cpp
+++ b/vendor/adb/adb_utils.cpp
@@ -308,8 +308,16 @@
}
std::string adb_get_android_dir_path() {
- std::string user_dir = adb_get_homedir_path();
- std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android";
+ const char* android_user_home = getenv("ANDROID_USER_HOME");
+ std::string android_dir;
+
+ if (android_user_home) {
+ android_dir = std::string(android_user_home);
+ } else {
+ std::string user_dir = adb_get_homedir_path();
+ android_dir = user_dir + OS_PATH_SEPARATOR + ".android";
+ }
+
struct stat buf;
if (stat(android_dir.c_str(), &buf) == -1) {
if (adb_mkdir(android_dir, 0750) == -1) {

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
home-manager.users.${user}.programs.bashmount.enable = true;
}

View File

@@ -0,0 +1,32 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user}.systemd.user.services.mpris-proxy = {
Unit = {
Description = "MPRIS proxy";
Requires = [ "sound.target" ];
After = [
"network.target"
"sound.target"
];
};
Service.ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-mpris-proxy";
runtimeInputs = with pkgs; [ bluez ];
text = "exec mpris-proxy";
}
);
Install.WantedBy = [ "default.target" ];
};
}

View File

@@ -0,0 +1,13 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
users.users.${user}.extraGroups = [
"video"
"inputs"
];
home-manager.users.${user}.home.packages = with pkgs; [ brightnessctl ];
}

View File

@@ -0,0 +1,20 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ ... }:
{
home-manager.users.${user}.programs.btop = {
enable = true;
settings = {
theme_background = false;
presets = "";
vim_keys = true;
shown_boxes = "cpu mem net proc gpu0 gpu1";
update_ms = 1000;
proc_tree = true;
cpu_single_graph = true;
disks_filter = "/ /nix /persist /cache";
};
};
}

View File

@@ -0,0 +1,43 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
inputs,
utils,
pkgs,
...
}:
{
virtualisation.docker.rootless = {
enable = true;
setSocketVariable = true;
enableOnBoot = false;
storageDriver = "btrfs";
daemon.settings = {
experimental = true;
ipv6 = true;
fixed-cidr-v6 = "fd00::/80";
};
autoPrune = {
enable = true;
flags = [ "--all" ];
};
};
environment.persistence."/persist"."${home}/.local/share/docker" = { };
systemd.user = {
services.docker.after = [
config.environment.persistence."/persist"."${home}/.local/share/docker".mount
];
sockets.docker.after = [
config.environment.persistence."/persist"."${home}/.local/share/docker".mount
];
};
home-manager.users.${user}.home.packages = with pkgs; [ docker-compose ];
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ ... }:
{
home-manager.users.${user}.programs.fastfetch.enable = true;
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user}.home.packages = with pkgs; [ ffmpeg ];
}

View File

@@ -0,0 +1,3 @@
git interpret-trailers --if-exists doNothing --trailer \
"Signed-off-by: $(git config user.name) <$(git config user.email)>" \
--in-place "$1"

View File

@@ -0,0 +1,47 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
userConfig = config.users.users.${user};
in
{
home-manager.users.${user} = {
programs.git = {
enable = true;
lfs.enable = true;
userName = userConfig.fullName;
userEmail = userConfig.email;
signing = {
signByDefault = true;
key = null;
};
extraConfig = {
credential.helper = "store";
push.autoSetupRemote = true;
core.fsmonitor = true;
feature.manyFiles = true;
fetch.writeCommitGraph = true;
http.cookiefile = "${home}/.config/git/cookies";
};
hooks = {
commit-msg = lib.meta.getExe (
pkgs.writeShellApplication {
name = "git-commit-msg-hook";
runtimeInputs = with pkgs; [ git ];
text = builtins.readFile ./commit-msg.sh;
}
);
};
};
};
}

View File

@@ -0,0 +1,69 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
# gpg --full-generate-key
# gpg --list-secret-keys --keyid-format LONG
# gpg --export-secret-keys -a $signature > priv.key
# gpg --export -a $signature > pub.key
programs.gpg = {
enable = true;
homedir = "${home}/.local/share/gnupg";
};
services.gpg-agent = {
enable = true;
defaultCacheTtl = 31536000;
maxCacheTtl = 31536000;
};
systemd.user = {
services.gpg-agent-import =
let
init = lib.meta.getExe (
pkgs.writeShellApplication {
name = "import-gpg-keys";
runtimeInputs = with pkgs; [
coreutils
gnugrep
gnupg
];
runtimeEnv = {
GNUPGHOME = "${home}/.local/share/gnupg";
HOME = home;
};
text = builtins.readFile ./import-gpg-keys.sh;
}
);
in
{
Unit = {
Description = "Auto-import GPG keys";
Requires = [
"sops-nix.service"
"gpg-agent.socket"
];
After = [
"sops-nix.service"
"gpg-agent.socket"
];
};
Service = {
Type = "oneshot";
ExecStart = init;
};
Install.WantedBy = [ "default.target" ];
};
};
};
}

View File

@@ -0,0 +1,23 @@
install -d -m 700 "${GNUPGHOME}"
for dir in "${HOME}"/.config/sops-nix/secrets/gpg/*; do
keyfile="${dir}/key"
passfile="${dir}/pass"
if [[ ! -f "${keyfile}" ]]; then
continue
fi
if [[ -f "${passfile}" ]]; then
gpg2 --batch --yes --pinentry-mode loopback --passphrase-file "${passfile}" --import "${keyfile}"
else
gpg2 --batch --yes --import "${keyfile}"
fi
gpg2 --with-colons --import-options show-only --import "${keyfile}" | grep '^fpr' | cut -d: -f10 | while read -r KEY_ID; do
echo "${KEY_ID}:6:" >> "${GNUPGHOME}"/otrust.txt
done
done
gpg2 --import-ownertrust "${GNUPGHOME}"/otrust.txt
rm "${GNUPGHOME}"/otrust.txt

View File

@@ -0,0 +1,29 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, inputs, ... }:
{
imports = [ inputs.home-manager.nixosModules.default ];
programs.dconf.enable = true;
home-manager = {
extraSpecialArgs = {
inherit inputs;
};
backupFileExtension = "bak";
useUserPackages = true;
useGlobalPkgs = true;
users.${user} = {
home.stateVersion = "24.11";
systemd.user.startServices = true;
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
};
};
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user}.home.packages = with pkgs; [ imagemagick ];
}

View File

@@ -0,0 +1,16 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user}.dconf.settings = {
"org/virt-manager/virt-manager/connections" = {
autoconnect = [ "qemu:///system" ];
uris = [ "qemu:///system" ];
};
"org/virt-manager/virt-manager".xmleditor-enabled = true;
};
users.users.${user}.extraGroups = [ "libvirtd" ];
}

View File

@@ -0,0 +1,17 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user} = {
home.packages = with pkgs; [ ncdu ];
xdg.configFile."ncdu/config".text = ''
-1
-e
-t 0
--confirm-quit
'';
};
}

View File

@@ -0,0 +1,20 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ ... }:
{
home-manager.users.${user}.programs.neovim = {
enable = true;
defaultEditor = true;
viAlias = true;
vimAlias = true;
vimdiffAlias = true;
extraConfig = ''
set tabstop=2
set shiftwidth=2
set expandtab
set smartindent
'';
};
}

View File

@@ -0,0 +1,16 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ ... }:
{
home-manager.users.${user}.programs.zsh.initExtra = ''
nix-develop() {
if [ -z "$1" ]; then
echo "Usage: nix-develop <shell>"
return 1
fi
nix develop self#"$1" -c "$SHELL"
}
'';
}

View File

@@ -0,0 +1,33 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ inputs, ... }:
{
home-manager.users.${user} = {
programs.direnv = {
enable = true;
silent = true;
nix-direnv.enable = true;
enableZshIntegration = true;
};
# https://github.com/direnv/direnv/wiki/Customizing-cache-location
xdg.configFile."direnv/direnvrc".text = ''
declare -A direnv_layout_dirs
direnv_layout_dir() {
local hash path
echo "''${direnv_layout_dirs[$PWD]:=$(
hash="$(sha1sum - <<< "$PWD" | head -c40)"
path="''${PWD//[^a-zA-Z0-9]/-}"
echo "${home}/.cache/direnv/layouts/''${hash}''${path}"
)}"
}
'';
};
environment.persistence = {
"/persist"."${home}/.local/share/direnv/allow" = { };
"/cache"."${home}/.cache/direnv" = { };
};
}

View File

@@ -0,0 +1,10 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ inputs, ... }:
{
home-manager.users.${user} = {
imports = [ inputs.nur.modules.homeManager.default ];
};
}

View File

@@ -0,0 +1,21 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
{
environment.persistence."/persist"."${home}/.local/state/wireplumber" = { };
systemd.user.services.wireplumber.after = [
config.environment.persistence."/persist"."${home}/.local/state/wireplumber".mount
];
home-manager.users.${user} = {
home.packages = with pkgs; [
wireplumber
playerctl
];
services.playerctld.enable = true;
};
}

View File

@@ -0,0 +1,17 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ ... }:
{
environment.persistence."/cache"."${home}/.cache/ranger" = { };
home-manager.users.${user}.programs.ranger = {
enable = true;
settings = {
preview_images = true;
preview_images_method = "kitty";
};
};
}

View File

@@ -0,0 +1,18 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, inputs, ... }:
{
environment.persistence."/persist"."${home}/.config/sops-nix/key.txt" = { };
home-manager.users.${user} = {
imports = [ inputs.sops-nix.homeManagerModules.sops ];
sops.age.keyFile = "${home}/.config/sops-nix/key.txt";
home.sessionVariables.SOPS_AGE_KEY_FILE = "${home}/.config/sops-nix/key.txt";
systemd.user.services.sops-nix.Unit.After = [
config.environment.persistence."/persist"."${home}/.config/sops-nix/key.txt".mount
];
};
}

View File

@@ -0,0 +1,25 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
programs.ssh = {
enable = true;
addKeysToAgent = "yes";
userKnownHostsFile = lib.strings.concatStringsSep " " [
../../../../../installer/secrets/ssh_host_ed25519_key.pub
../../../../../eirene/secrets/ssh_host_ed25519_key.pub
../../../../../elara/secrets/ssh_host_ed25519_key.pub
];
};
services.ssh-agent.enable = true;
};
}

View File

@@ -0,0 +1,49 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, utils, ... }:
{
networking.firewall = {
allowedTCPPorts = [ 22000 ];
allowedUDPPorts = [
21027
22000
];
};
sops.secrets = {
# openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:3072
"syncthing/key" = {
owner = user;
group = "users";
};
# openssl req -new -x509 -key key.pem -out cert.pem -days 9999 -subj "/CN=syncthing"
"syncthing/cert" = {
owner = user;
group = "users";
};
};
home-manager.users.${user} = {
services.syncthing = {
enable = true;
key = config.sops.secrets."syncthing/key".path;
cert = config.sops.secrets."syncthing/cert".path;
extraOptions = [ "-no-default-folder" ];
settings = {
options.urAccepted = -1;
devices = {
amalthea.id = "2W7YT6Q-TO7CYMW-JH6QZXE-7Q6MDQQ-HPHKP4A-VI5HP7G-KLMGMST-MNRYHQG"; # Google Pixel 8 Pro
ganymede.id = "DXJPEJA-JNGF6I4-VIZYTX7-U345C5V-HIUTSFC-D36N2EM-Y3FAKJM-PRKYQAI"; # Samsung Galaxy Tab S7+
};
};
};
systemd.user.services.syncthing.Unit.After = [
"sops-nix.service"
"local-fs.target"
];
};
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ ... }:
{
home-manager.users.${user}.programs.tmux.enable = true;
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user}.home.packages = with pkgs; [ tree ];
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user}.home.packages = with pkgs; [ wget ];
}

View File

@@ -0,0 +1,40 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
{
environment.persistence."/persist" = {
"${home}/Desktop" = { };
"${home}/Documents" = { };
"${home}/Downloads" = { };
"${home}/Music" = { };
"${home}/Pictures" = { };
"${home}/Templates" = { };
"${home}/Videos" = { };
"${home}/Games" = { };
"${home}/VMs" = { };
"${home}/git" = { };
};
home-manager.users.${user} = {
imports = [ (import ./options.nix { inherit home; }) ];
xdg = {
enable = true;
mimeApps.enable = true;
userDirs = {
enable = true;
createDirectories = true;
extraConfig = {
XDG_GAME_DIR = "${home}/Games";
XDG_VM_DIR = "${home}/VMs";
XDG_GIT_DIR = "${home}/git";
};
};
};
home.packages = with pkgs; [ xdg-utils ];
};
}

View File

@@ -0,0 +1,112 @@
{
home ? throw "home argument is required",
}:
{ config, lib, ... }:
let
cfg = config.xdg;
in
{
options.xdg =
with lib;
with types;
{
relativeCacheHome = mkOption {
type = str;
readOnly = true;
default = ".cache";
description = "Relative path to directory holding application caches.";
};
relativeConfigHome = mkOption {
type = str;
readOnly = true;
default = ".config";
description = "Relative path to directory holding application configurations.";
};
relativeDataHome = mkOption {
type = str;
readOnly = true;
default = ".local/share";
description = "Relative path to directory holding application data.";
};
relativeStateHome = mkOption {
type = str;
readOnly = true;
default = ".local/state";
description = "Relative path to directory holding application states.";
};
userDirs = {
relativeDesktop = mkOption {
type = str;
readOnly = true;
default = "Desktop";
description = "Relative path to the Desktop directory.";
};
relativeDocuments = mkOption {
type = str;
readOnly = true;
default = "Documents";
description = "Relative path to the Documents directory.";
};
relativeDownload = mkOption {
type = str;
readOnly = true;
default = "Downloads";
description = "Relative path to the Downloads directory.";
};
relativeMusic = mkOption {
type = str;
readOnly = true;
default = "Music";
description = "Relative path to the Music directory.";
};
relativePictures = mkOption {
type = str;
readOnly = true;
default = "Pictures";
description = "Relative path to the Pictures directory.";
};
relativeTemplates = mkOption {
type = str;
readOnly = true;
default = "Templates";
description = "Relative path to the Templates directory.";
};
relativeVideos = mkOption {
type = str;
readOnly = true;
default = "Videos";
description = "Relative path to the Videos directory.";
};
};
};
config.xdg =
with lib;
with cfg;
{
cacheHome = mkDefault "${home}/${relativeCacheHome}";
configHome = mkDefault "${home}/${relativeConfigHome}";
dataHome = mkDefault "${home}/${relativeDataHome}";
stateHome = mkDefault "${home}/${relativeStateHome}";
userDirs = with userDirs; {
desktop = mkDefault "${home}/${relativeDesktop}";
documents = mkDefault "${home}/${relativeDocuments}";
download = mkDefault "${home}/${relativeDownload}";
music = mkDefault "${home}/${relativeMusic}";
pictures = mkDefault "${home}/${relativePictures}";
templates = mkDefault "${home}/${relativeTemplates}";
videos = mkDefault "${home}/${relativeVideos}";
};
};
}

View File

@@ -0,0 +1,20 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, ... }:
{
home-manager.users.${user}.programs.yt-dlp = {
enable = true;
settings = {
live-from-start = true;
concurrent-fragments = config.hardware.cpu.threads;
lazy-playlist = true;
cookies-from-browser = "firefox";
embed-subs = true;
sub-langs = "all,-live_chat";
embed-thumbnail = true;
fixup = "detect_or_warn";
};
};
}

View File

@@ -0,0 +1,249 @@
'builtin' 'local' '-a' 'p10k_config_opts'
[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases')
[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob')
[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand')
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
() {
emulate -L zsh -o extended_glob
unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR'
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
# =========================[ Line #1 ]=========================
dir
vcs
# =========================[ Line #2 ]=========================
newline
prompt_char
)
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(
# =========================[ Line #1 ]=========================
status
command_execution_time
background_jobs
direnv
ranger
vim_shell
nix_shell
per_directory_history
"${P10K_EXTRA_RIGHT_PROMPT_ELEMENTS[@]}"
context
# =========================[ Line #2 ]=========================
newline
)
typeset -g POWERLEVEL9K_MODE=ascii
typeset -g POWERLEVEL9K_ICON_PADDING=none
typeset -g POWERLEVEL9K_BACKGROUND=
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_{LEFT,RIGHT}_WHITESPACE=
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR=' '
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_SEPARATOR=
typeset -g POWERLEVEL9K_ICON_BEFORE_CONTENT=true
typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=true
typeset -g POWERLEVEL9K_SHOW_RULER=false
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' '
################################[ prompt_char: prompt symbol ]################################
typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=76
typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=196
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='>'
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='<'
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION='V'
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIOWR_CONTENT_EXPANSION='^'
typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=true
typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL=''
##################################[ dir: current directory ]##################################
typeset -g POWERLEVEL9K_DIR_FOREGROUND=31
typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique
typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=103
typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=39
typeset -g POWERLEVEL9K_DIR_ANCHOR_BOLD=true
local anchor_files=(
.git
flake.nix
Cargo.toml
go.mod
package.json
)
typeset -g POWERLEVEL9K_SHORTEN_FOLDER_MARKER="(${(j:|:)anchor_files})"
typeset -g POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=false
typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=1
typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=80
typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS=40
typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT=50
typeset -g POWERLEVEL9K_DIR_HYPERLINK=false
typeset -g POWERLEVEL9K_DIR_SHOW_WRITABLE=v3
typeset -g POWERLEVEL9K_DIR_CLASSES=()
#####################################[ vcs: git status ]######################################
typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON='?'
function my_git_formatter() {
emulate -L zsh
if [[ -n $P9K_CONTENT ]]; then
typeset -g my_git_format=$P9K_CONTENT
return
fi
if (( $1 )); then
local meta='%f'
local clean='%76F'
local modified='%178F'
local untracked='%39F'
local conflicted='%196F'
else
local meta='%244F'
local clean='%244F'
local modified='%244F'
local untracked='%244F'
local conflicted='%244F'
fi
local res
if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then
local branch=${(V)VCS_STATUS_LOCAL_BRANCH}
(( $#branch > 32 )) && branch[13,-13]=".."
res+="${clean}${(g::)POWERLEVEL9K_VCS_BRANCH_ICON}${branch//\%/%%}"
fi
if [[ -n $VCS_STATUS_TAG
&& -z $VCS_STATUS_LOCAL_BRANCH
]]; then
local tag=${(V)VCS_STATUS_TAG}
(( $#tag > 32 )) && tag[13,-13]=".."
res+="${meta}#${clean}${tag//\%/%%}"
fi
[[ -z $VCS_STATUS_LOCAL_BRANCH && -z $VCS_STATUS_TAG ]] &&
res+="${meta}@${clean}${VCS_STATUS_COMMIT[1,8]}"
if [[ -n ${VCS_STATUS_REMOTE_BRANCH:#$VCS_STATUS_LOCAL_BRANCH} ]]; then
res+="${meta}:${clean}${(V)VCS_STATUS_REMOTE_BRANCH//\%/%%}"
fi
if [[ $VCS_STATUS_COMMIT_SUMMARY == (|*[^[:alnum:]])(wip|WIP)(|[^[:alnum:]]*) ]]; then
res+=" ${modified}wip"
fi
if (( VCS_STATUS_COMMITS_AHEAD || VCS_STATUS_COMMITS_BEHIND )); then
(( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}<${VCS_STATUS_COMMITS_BEHIND}"
(( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" "
(( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}>${VCS_STATUS_COMMITS_AHEAD}"
fi
(( VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" ${clean}<-${VCS_STATUS_PUSH_COMMITS_BEHIND}"
(( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" "
(( VCS_STATUS_PUSH_COMMITS_AHEAD )) && res+="${clean}->${VCS_STATUS_PUSH_COMMITS_AHEAD}"
(( VCS_STATUS_STASHES )) && res+=" ${clean}*${VCS_STATUS_STASHES}"
[[ -n $VCS_STATUS_ACTION ]] && res+=" ${conflicted}${VCS_STATUS_ACTION}"
(( VCS_STATUS_NUM_CONFLICTED )) && res+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}"
(( VCS_STATUS_NUM_STAGED )) && res+=" ${modified}+${VCS_STATUS_NUM_STAGED}"
(( VCS_STATUS_NUM_UNSTAGED )) && res+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}"
(( VCS_STATUS_NUM_UNTRACKED )) && res+=" ${untracked}${(g::)POWERLEVEL9K_VCS_UNTRACKED_ICON}${VCS_STATUS_NUM_UNTRACKED}"
(( VCS_STATUS_HAS_UNSTAGED == -1 )) && res+=" ${modified}-"
typeset -g my_git_format=$res
}
functions -M my_git_formatter 2>/dev/null
typeset -g POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY=-1
typeset -g POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~'
typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter(1)))+${my_git_format}}'
typeset -g POWERLEVEL9K_VCS_LOADING_CONTENT_EXPANSION='${$((my_git_formatter(0)))+${my_git_format}}'
typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED,COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=-1
typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_COLOR=76
typeset -g POWERLEVEL9K_VCS_LOADING_VISUAL_IDENTIFIER_COLOR=244
typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_EXPANSION=
typeset -g POWERLEVEL9K_VCS_BACKENDS=(git)
typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND=76
typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND=76
typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND=178
##########################[ status: exit code of the last command ]###########################
typeset -g POWERLEVEL9K_STATUS_EXTENDED_STATES=true
typeset -g POWERLEVEL9K_STATUS_OK=true
typeset -g POWERLEVEL9K_STATUS_OK_FOREGROUND=70
typeset -g POWERLEVEL9K_STATUS_OK_VISUAL_IDENTIFIER_EXPANSION='ok'
typeset -g POWERLEVEL9K_STATUS_OK_PIPE=true
typeset -g POWERLEVEL9K_STATUS_OK_PIPE_FOREGROUND=70
typeset -g POWERLEVEL9K_STATUS_OK_PIPE_VISUAL_IDENTIFIER_EXPANSION='ok'
typeset -g POWERLEVEL9K_STATUS_ERROR=false
typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND=160
typeset -g POWERLEVEL9K_STATUS_ERROR_VISUAL_IDENTIFIER_EXPANSION='err'
typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL=true
typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_FOREGROUND=160
typeset -g POWERLEVEL9K_STATUS_VERBOSE_SIGNAME=true
typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_VISUAL_IDENTIFIER_EXPANSION=
typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE=true
typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_FOREGROUND=160
typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_VISUAL_IDENTIFIER_EXPANSION='err'
###################[ command_execution_time: duration of the last command ]###################
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=0
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=2
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=101
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s'
#######################[ background_jobs: presence of background jobs ]#######################
typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE=false
typeset -g POWERLEVEL9K_BACKGROUND_JOBS_FOREGROUND=70
#######################[ direnv: direnv status (https://direnv.net/) ]########################
typeset -g POWERLEVEL9K_DIRENV_FOREGROUND=178
#################[ ranger: ranger shell (https://github.com/ranger/ranger) ]##################
typeset -g POWERLEVEL9K_RANGER_FOREGROUND=178
###########################[ vim_shell: vim shell indicator (:sh) ]###########################
typeset -g POWERLEVEL9K_VIM_SHELL_FOREGROUND=34
#[ nix_shell: nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) ]##
typeset -g POWERLEVEL9K_NIX_SHELL_FOREGROUND=74
typeset -g POWERLEVEL9K_NIX_SHELL_INFER_FROM_PATH=true
######[ per_directory_history: Oh My Zsh per-directory-history local/global indicator ]#######
typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_FOREGROUND=135
typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_FOREGROUND=130
##################################[ context: user@hostname ]##################################
typeset -g POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND=178
typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_FOREGROUND=180
typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND=180
typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%B%n@%m'
typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_TEMPLATE='%n@%m'
typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%n@%m'
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_{CONTENT,VISUAL_IDENTIFIER}_EXPANSION=
#####################################[ Other Settings ]#######################################
typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=always
typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet
typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true
(( ! $+functions[p10k] )) || p10k reload
}
typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a}
(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]}
'builtin' 'unset' 'p10k_config_opts'

View File

@@ -0,0 +1,39 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
{
environment = {
sessionVariables.ZDOTDIR = "$HOME/.config/zsh";
persistence."/persist"."${home}/.local/share/zsh" = { };
};
home-manager.users.${user} = {
programs.zsh = {
enable = true;
dotDir = ".config/zsh";
autocd = true;
history = {
path = "${home}/.local/share/zsh/history";
expireDuplicatesFirst = true;
append = true;
};
historySubstringSearch.enable = true;
autosuggestion.enable = true;
syntaxHighlighting.enable = true;
plugins = [
{
name = "powerlevel10k";
src = pkgs.zsh-powerlevel10k;
file = "share/zsh-powerlevel10k/powerlevel10k.zsh-theme";
}
];
initExtra = ''
source ${./.p10k.zsh}
'';
};
home.file.".zshenv".enable = false;
};
}

View File

@@ -0,0 +1,2 @@
node_modules/
@girs/

View File

@@ -0,0 +1,23 @@
import { App } from "astal/gtk3"
import Bar from "./widget/Bar"
import { monitorFile } from "astal/file"
import { exec } from "astal/process"
import GLib from "gi://GLib"
const HOME = GLib.getenv("HOME")
const css = `${HOME}/.config/astal/theme.css`;
const scss = `${HOME}/.config/astal/theme.sass`;
monitorFile(scss, () => {
exec(`sassc ${scss} ${css}`);
App.apply_css(css, true);
});
exec(`sassc ${scss} ${css}`);
App.start({
css,
main() {
App.get_monitors().map(Bar)
},
})

View File

@@ -0,0 +1,26 @@
export const SRC: string
declare module "inline:*" {
const content: string
export default content
}
declare module "*.scss" {
const content: string
export default content
}
declare module "*.sass" {
const content: string
export default content
}
declare module "*.blp" {
const content: string
export default content
}
declare module "*.css" {
const content: string
export default content
}

View File

@@ -0,0 +1,3 @@
export const range = (length: number, start = 1) => {
return Array.from({ length }, (n, i) => i + start);
};

View File

@@ -0,0 +1,20 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"experimentalDecorators": true,
"strict": true,
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"jsxImportSource": "/nix/store/ii2w7wv88fjvmldn8kzz8ni20kzpkld4-astal-gjs/share/astal/gjs/gtk3",
"paths": {
"astal": [
"/nix/store/ii2w7wv88fjvmldn8kzz8ni20kzpkld4-astal-gjs/share/astal/gjs"
],
"astal/*": [
"/nix/store/ii2w7wv88fjvmldn8kzz8ni20kzpkld4-astal-gjs/share/astal/gjs/*"
]
},
}
}

View File

@@ -0,0 +1,29 @@
import { App, Astal, Gtk, Gdk } from 'astal/gtk3'
import Launcher from './components/Launcher';
import Workspace from './components/Workspaces';
import Date from './components/Date';
import Systray from './components/Tray';
const anchor = Astal.WindowAnchor.TOP
| Astal.WindowAnchor.LEFT
| Astal.WindowAnchor.RIGHT;
export default (monitor: Gdk.Monitor) => <window
className='bar'
gdkmonitor={monitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE}
anchor={anchor}
application={App}>
<centerbox className='widgets'>
<box hexpand halign={Gtk.Align.START}>
<Launcher />
<Workspace />
</box>
<box hexpand halign={Gtk.Align.CENTER}>
<Date />
</box>
<box hexpand halign={Gtk.Align.END}>
<Systray />
</box>
</centerbox>
</window>

View File

@@ -0,0 +1,13 @@
import { Variable } from 'astal/variable';
import { GLib } from 'astal';
const time = Variable<string>("").poll(1000, () => GLib.DateTime.new_now_local().format('%H:%M - %A, %d %B %Y')!)
export default () => <button className='date'>
<label
className='label'
onDestroy={() => time.drop()}
label={time()}
/>
</button>;

View File

@@ -0,0 +1,7 @@
import { execAsync } from "astal/process"
export default () => <button
className="launcher"
onClickRelease={() => execAsync('bash -c "rofi -cache-dir $XDG_CACHE_HOME/rofi -show drun"')}>
<icon className="icon" icon="nix-snowflake-symbolic" />;
</button>;

View File

@@ -0,0 +1,30 @@
import { App, Gdk } from 'astal/gtk3'
import { bind } from 'astal'
import Tray from 'gi://AstalTray'
const tray = Tray.get_default()
const TrayButton = ({ item }: { item: Tray.TrayItem }) => {
const menu = item.create_menu();
return <button
className='item'
tooltipMarkup={bind(item, 'tooltipMarkup')}
onClickRelease={self => {
menu?.popup_at_widget(self, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null)
}}
onDestroy={() => menu?.destroy()}
>
<icon
className='icon'
gIcon={bind(item, 'gicon')} />
</button>;
}
export default () => <box className='systray'>
{
bind(tray, 'items').as(items => items.map(item => {
if (item.iconThemePath) App.add_icons(item.iconThemePath);
return <TrayButton item={item} />;
}))}
</box>;

View File

@@ -0,0 +1,44 @@
import { bind, Binding, Variable } from "astal";
import Hyprland from "gi://AstalHyprland";
import { range } from '../../lib';
const hyprland = Hyprland.get_default();
const Workspace = ({ id }: { id: number }) => {
const className = Variable.derive(
[bind(hyprland, "workspaces"), bind(hyprland, "focusedWorkspace")],
(workspaces, focused) => {
const workspace = workspaces.find((w) => w.id === id);
if (!workspace) return "button";
const occupied = workspace.get_clients().length > 0;
const active = focused.id === id;
return `button ${active ? "active" : occupied && "occupied"}`;
},
);
return <box vertical>
<box vexpand />
<eventbox
onClickRelease={() => hyprland.dispatch("workspace", `${id}`)}
>
<label
className={className()}
/>
</eventbox>
<box vexpand />
</box>;
};
export default () => <eventbox
className="workspaces"
onScroll={(_, e) => {
hyprland.dispatch("workspace", e.delta_y > 0 ? "+1" : "-1");
}}
>
<box>
{range(10).map((i) => <Workspace id={i} />)}
</box>
</eventbox>

View File

@@ -0,0 +1,43 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
inputs,
...
}:
{
home-manager.users.${user} = {
imports = [ inputs.ags.homeManagerModules.default ];
programs.ags = {
enable = true;
configDir = ./config;
systemd.enable = true;
extraPackages = with pkgs; [
inputs.ags.packages.${pkgs.system}.hyprland
inputs.ags.packages.${pkgs.system}.tray
sassc
hyprland
nixos-icons
(pkgs.callPackage ../cliphist/rofi.nix { })
];
};
theme.template."${home}/.config/astal/theme.sass".source = ./theme.sass;
systemd.user = {
targets.tray.Unit = {
BindsTo = [ "ags.service" ];
After = [
"graphical-session.target"
"ags.service"
];
};
};
};
}

View File

@@ -0,0 +1,73 @@
.bar
background-color: {{colors.surface.default.hex}}
@mixin interactive
min-height: {{custom.font_size}}pt
border-radius: .5 * {{custom.font_size}}pt
padding: 2pt
margin: 0 2pt 0
transition: .25s
background-color: {{colors.surface.default.hex}}
&:hover
background-color: {{colors.surface_container_high.default.hex}}
&:active
background-color: {{colors.surface_container_highest.default.hex}}
.widgets
padding: .2 * {{custom.padding}}pt
.launcher
@include interactive
min-width: {{custom.font_size}}pt
.icon
font-size: {{custom.font_size}}pt
padding: 0 .3 * {{custom.padding}}pt
color: {{colors.on_surface.default.hex}}
.workspaces
@include interactive
.button
font-size: 0
transition: .5s
margin: 0 .3 * {{custom.padding}}pt
background-color: {{colors.outline_variant.default.hex}}
min-width: .4 * {{custom.font_size}}pt
min-height: .4 * {{custom.font_size}}pt
border-radius: .5 * {{custom.font_size}}pt
&.occupied
background-color: {{colors.on_surface.default.hex}}
min-width: .6 * {{custom.font_size}}pt
min-height: .6 * {{custom.font_size}}pt
border-radius: .5 * {{custom.font_size}}pt
&.active
background-color: {{colors.primary.default.hex}}
min-width: 1.67 * {{custom.font_size}}pt
min-height: {{custom.font_size}}pt
border-radius: .4 * {{custom.font_size}}pt
.date
@include interactive
.label
color: {{colors.on_surface.default.hex}}
font-size: {{custom.font_size}}pt
font-family: {{custom.font_sans_serif_all}}
font-weight: 500
margin: 0 .5 * {{custom.padding}}pt
.systray
.item
@include interactive
.icon
font-size: {{custom.font_size}}pt
padding: 0 .3 * {{custom.padding}}pt
color: {{colors.on_surface.default.hex}}

View File

@@ -0,0 +1,18 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
services.blueman.enable = true;
home-manager.users.${user} = {
services.blueman-applet.enable = true;
systemd.user.services.blueman-applet.Unit.After = [ "graphical-session.target" ];
};
}

View File

@@ -0,0 +1,20 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
users.users.${user}.extraGroups = [
"video"
"inputs"
];
home-manager.users.${user}.wayland.windowManager.hyprland.settings.bindle =
let
brightnessctl = lib.meta.getExe pkgs.brightnessctl;
in
[
", XF86MonBrightnessUp, exec, ${brightnessctl} -q s 5%+"
", XF86MonBrightnessDown, exec, ${brightnessctl} -q s 5%-"
];
}

View File

@@ -0,0 +1,29 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
programs.btop.settings.color_theme = "matugen";
theme = {
template."${home}/.config/btop/themes/matugen.theme".source = ./theme.theme;
reloadExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-btop";
runtimeInputs = with pkgs; [ procps ];
text = "exec pkill btop -SIGUSR2";
}
)
} &";
};
};
}

View File

@@ -0,0 +1,50 @@
theme[main_bg]="{{colors.surface.default.hex}}"
theme[main_fg]="{{colors.on_surface.default.hex}}"
theme[title]="{{colors.on_surface.default.hex}}"
theme[hi_fg]="{{colors.primary.default.hex}}"
theme[selected_bg]="{{colors.primary_container.default.hex}}"
theme[selected_fg]="{{colors.on_primary_container.default.hex}}"
theme[inactive_fg]="{{colors.surface_variant.default.hex}}"
theme[graph_text]="{{colors.on_surface_variant.default.hex}}"
theme[proc_misc]="{{colors.primary.default.hex}}"
theme[cpu_box]="{{colors.outline.default.hex}}"
theme[mem_box]="{{colors.outline.default.hex}}"
theme[net_box]="{{colors.outline.default.hex}}"
theme[proc_box]="{{colors.outline.default.hex}}"
theme[div_line]="{{colors.outline_variant.default.hex}}"
theme[temp_start]="{{colors.primary.default.hex}}"
theme[temp_mid]=""
theme[temp_end]="{{colors.error.default.hex}}"
theme[cpu_start]="{{colors.primary.default.hex}}"
theme[cpu_mid]=""
theme[cpu_end]="{{colors.error.default.hex}}"
theme[used_start]="{{colors.primary.default.hex}}"
theme[used_mid]=""
theme[used_end]="{{colors.secondary.default.hex}}"
theme[available_start]="{{colors.tertiary.default.hex}}"
theme[available_mid]=""
theme[available_end]="{{colors.secondary.default.hex}}"
theme[cached_start]="{{colors.primary.default.hex}}"
theme[cached_mid]=""
theme[cached_end]="{{colors.secondary.default.hex}}"
theme[free_start]="{{colors.tertiary.default.hex}}"
theme[free_mid]=""
theme[free_end]="{{colors.secondary.default.hex}}"
theme[download_start]="{{colors.primary.default.hex}}"
theme[download_mid]=""
theme[download_end]="{{colors.secondary.default.hex}}"
theme[upload_start]="{{colors.primary.default.hex}}"
theme[upload_mid]=""
theme[upload_end]="{{colors.tertiary.default.hex}}"

View File

@@ -0,0 +1,21 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
services.cbatticon = {
enable = true;
lowLevelPercent = 20;
criticalLevelPercent = 10;
};
systemd.user.services.cbatticon.Unit.After = [ "graphical-session.target" ];
};
}

View File

@@ -0,0 +1,44 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, ... }:
{
programs.chromium = {
enable = true;
extraOpts = {
DefaultSearchProviderEnabled = true;
DefaultSearchProviderName = "DuckDuckGo";
DefaultSearchProviderIconURL = "https://duckduckgo.com/favicon.ico";
DefaultSearchProviderSearchURL = "https://duckduckgo.com/?q={searchTerms}";
DefaultSearchProviderSuggestURL = "https://duckduckgo.com/ac/?q={searchTerms}&type=list";
DefaultBrowserSettingEnabled = false;
DefaultDownloadDirectory = "$HOME/Downloads";
PasswordManagerEnabled = false;
HomepageIsNewTabPage = true;
};
};
environment.persistence = {
"/persist"."${home}/.config/chromium" = { };
"/cache"."${home}/.cache/chromium" = { };
};
home-manager.users.${user} = {
programs.chromium = {
enable = true;
extensions = [
"oldceeleldhonbafppcapldpdifcinji" # LanguageTool
"nngceckbapebfimnlniiiahkandclblb" # Bitwarden
"eimadpbcbfnmbkopoojfekhnkhdbieeh" # Dark Reader
"doojmbjmlfjjnbmnoijecmcbfeoakpjm" # NoScript
"gebbhagfogifgggkldgodflihgfeippi" # Return YouTube Dislike
"mnjggcdmjocbbbhaepdhchncahnbgone" # Sponsorblock
"cjpalhdlnbpafiamejdnhcphjbkeiagm" # uBlock Origin
"jinjaccalgkegednnccohejagnlnfdag" # Violentmonkey
"fpnmgdkabkmnadcjpehmlllkndpkmiak" # Wayback Machine
];
};
};
}

View File

@@ -0,0 +1,85 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.cache/cliphist" = { };
home-manager.users.${user} = {
home.packages = with pkgs; [
wl-clipboard
cliphist
];
systemd.user.services = {
cliphist = {
Unit = {
Description = "Clipboard manager";
BindsTo = [ "graphical-session.target" ];
After = [
"graphical-session.target"
config.environment.persistence."/cache"."${home}/.cache/cliphist".mount
];
};
Service.ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-cliphist";
runtimeInputs = with pkgs; [
wl-clipboard
cliphist
];
text = "exec wl-paste --watch cliphist store";
}
);
Install.WantedBy = [ "graphical-session.target" ];
};
cliphist-image = {
Unit = {
Description = "Clipboard manager (images)";
BindsTo = [ "graphical-session.target" ];
After = [
"graphical-session.target"
config.environment.persistence."/cache"."${home}/.cache/cliphist".mount
];
};
Service.ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-cliphist-image";
runtimeInputs = with pkgs; [
wl-clipboard
cliphist
];
text = "exec wl-paste --type image --watch cliphist store";
}
);
Install.WantedBy = [ "graphical-session.target" ];
};
};
wayland.windowManager.hyprland.settings.bind =
let
cliphist-rofi = lib.meta.getExe (
pkgs.callPackage ./rofi.nix { rofi = hmConfig.programs.rofi.finalPackage; }
);
cliphist = lib.meta.getExe pkgs.cliphist;
in
[
"$mod, v, exec, ${cliphist-rofi}"
"$mod_Ctrl, v, exec, ${cliphist} wipe"
];
};
}

View File

@@ -0,0 +1,31 @@
{
rofi ? throw "rofi package is required",
lib,
pkgs,
...
}:
let
copy = lib.meta.getExe (
pkgs.writeShellApplication {
name = "copy";
runtimeInputs = with pkgs; [
cliphist
wl-clipboard
];
text = builtins.readFile ./scripts/copy.sh;
}
);
delete = lib.meta.getExe (
pkgs.writeShellApplication {
name = "delete";
runtimeInputs = with pkgs; [ cliphist ];
text = builtins.readFile ./scripts/delete.sh;
}
);
in
pkgs.writeShellApplication {
name = "cliphist-rofi";
runtimeInputs = [ rofi ];
text = "rofi -modi \"copy:${copy},delete:${delete}\" -show copy";
}

View File

@@ -0,0 +1,13 @@
list() {
echo -en "\0keep-selection\x1ftrue\n"
cliphist list
}
handle() {
cliphist decode <<< "$1" | wl-copy
}
case ${ROFI_RETV} in
0) list ;;
1) handle "$@" ;;
esac

View File

@@ -0,0 +1,13 @@
list() {
echo -en "\0keep-selection\x1ftrue\n"
cliphist list
}
handle() {
cliphist delete <<< "$1"
}
case ${ROFI_RETV} in
0) list ;;
1) handle "$@" && list ;;
esac

View File

@@ -0,0 +1,265 @@
diff --git a/data/darktableconfig.xml.in b/data/darktableconfig.xml.in
index 83eadf8a35..39ed8d43d7 100644
--- a/data/darktableconfig.xml.in
+++ b/data/darktableconfig.xml.in
@@ -1524,6 +1524,22 @@
<longdescription>file naming pattern used for a import session</longdescription>
</dtconfig>
+ <dtconfig prefs="import" section="session">
+ <name>session/conflict_padding</name>
+ <type>int</type>
+ <default>2</default>
+ <shortdescription>burst file name conflict number padding</shortdescription>
+ <longdescription>set the padding length for conflict resolution (e.g., 001, 002).</longdescription>
+ </dtconfig>
+
+ <dtconfig prefs="import" section="session">
+ <name>session/import_existing_sidecar</name>
+ <type>bool</type>
+ <default>true</default>
+ <shortdescription>import existing sidecar files</shortdescription>
+ <longdescription>import existing sidecar files (XMP, IPTC, etc.) when importing images</longdescription>
+ </dtconfig>
+
<dtconfig>
<name>plugins/lighttable/layout</name>
<type>int</type>
diff --git a/src/common/import_session.c b/src/common/import_session.c
index e83ef4de62..4d0c4efa0c 100644
--- a/src/common/import_session.c
+++ b/src/common/import_session.c
@@ -266,48 +266,42 @@ const char *dt_import_session_filename(struct dt_import_session_t *self, gboolea
char *pattern = _import_session_filename_pattern();
if(pattern == NULL)
{
- dt_print(DT_DEBUG_ALWAYS, "[import_session] Failed to get session filaname pattern.\n");
+ dt_print(DT_DEBUG_ALWAYS, "[import_session] Failed to get session filename pattern.\n");
return NULL;
}
+ self->vp->retry_count = 0;
+
/* verify that expanded path and filename yields a unique file */
const char *path = dt_import_session_path(self, TRUE);
if(use_filename)
result_fname = g_strdup(self->vp->filename);
else
- result_fname = _import_session_filename_from_pattern(self, pattern);
-
- char *fname = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
- char *previous_fname = fname;
- if(g_file_test(fname, G_FILE_TEST_EXISTS) == TRUE)
{
- dt_print(DT_DEBUG_ALWAYS, "[import_session] File %s exists.\n", fname);
do
{
- /* file exists, yield a new filename */
+ /* generate filename based on the current retry_count */
g_free(result_fname);
result_fname = _import_session_filename_from_pattern(self, pattern);
- fname = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
- dt_print(DT_DEBUG_ALWAYS, "[import_session] Testing %s.\n", fname);
- /* check if same filename was yielded as before */
- if(strcmp(previous_fname, fname) == 0)
+ char *test_path = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
+
+ if(g_file_test(test_path, G_FILE_TEST_EXISTS) == TRUE)
{
- g_free(previous_fname);
- g_free(fname);
- dt_control_log(_(
- "couldn't expand to a unique filename for session, please check your import session settings."));
- return NULL;
+ dt_print(DT_DEBUG_ALWAYS, "[import_session] File %s exists, retrying.\n", test_path);
+ self->vp->retry_count++;
+ g_free(test_path);
+ }
+ else
+ {
+ g_free(test_path);
+ break;
}
- g_free(previous_fname);
- previous_fname = fname;
-
- } while(g_file_test(fname, G_FILE_TEST_EXISTS) == TRUE);
+ } while(TRUE);
}
- g_free(previous_fname);
g_free(pattern);
self->current_filename = result_fname;
diff --git a/src/common/variables.c b/src/common/variables.c
index 1474cc32e8..820f88414b 100644
--- a/src/common/variables.c
+++ b/src/common/variables.c
@@ -914,6 +914,14 @@ static char *_get_base_value(dt_variables_params_t *params, char **variable)
else if(_has_prefix(variable, "DARKTABLE.NAME")
|| _has_prefix(variable, "DARKTABLE_NAME"))
result = g_strdup(PACKAGE_NAME);
+
+ else if(_has_prefix(variable, "CONFLICT_PADDING"))
+ {
+ int pad_length = dt_conf_get_int("session/conflict_padding");
+ if(pad_length < 0) pad_length = 0;
+ result = g_strdup_printf("%0*u", pad_length, params->retry_count);
+ }
+
else
{
// go past what looks like an invalid variable. we only expect to
diff --git a/src/common/variables.h b/src/common/variables.h
index 86052a9a3d..a5d616a94c 100644
--- a/src/common/variables.h
+++ b/src/common/variables.h
@@ -29,6 +29,9 @@ typedef struct dt_variables_params_t
/** used for expanding variables that uses filename $(FILE_FOLDER) $(FILE_NAME) and $(FILE_EXTENSION). */
const gchar *filename;
+ /** used for conflict resolution in filename expansion */
+ int retry_count;
+
/** used for expanding variable $(JOBCODE) */
const gchar *jobcode;
diff --git a/src/control/jobs/control_jobs.c b/src/control/jobs/control_jobs.c
index a9fab6f0ea..27bceab782 100644
--- a/src/control/jobs/control_jobs.c
+++ b/src/control/jobs/control_jobs.c
@@ -1566,7 +1566,7 @@ static int32_t dt_control_export_job_run(dt_job_t *job)
{
// IPTC character encoding not set by user, so we set the default utf8 here
settings->metadata_export = dt_util_dstrcat(settings->metadata_export,
- "\1%s\1%s",
+ "\1%s\1%s",
iptc_envelope_characterset,
"\x1b%G"); // ESC % G
}
@@ -2265,6 +2265,59 @@ void dt_control_write_sidecar_files()
FALSE));
}
+static gboolean _copy_file(const char *source, const char *destination)
+{
+ gchar *data = NULL;
+ gsize size = 0;
+
+ if(!g_file_get_contents(source, &data, &size, NULL))
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to read file `%s`", source);
+ return FALSE;
+ }
+
+ if(!g_file_set_contents(destination, data, size, NULL))
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to write file `%s`", destination);
+ g_free(data);
+ return FALSE;
+ }
+
+ g_free(data);
+ return TRUE;
+}
+
+static void _copy_timestamps(const char *source, const char *destination)
+{
+ struct stat statbuf;
+ if(stat(source, &statbuf) == 0)
+ {
+#ifdef _WIN32
+ struct utimbuf times;
+ times.actime = statbuf.st_atime;
+ times.modtime = statbuf.st_mtime;
+ utime(destination, &times);
+#else
+ struct timeval times[2];
+ times[0].tv_sec = statbuf.st_atime;
+ times[1].tv_sec = statbuf.st_mtime;
+#ifdef __APPLE__
+#ifndef _POSIX_SOURCE
+ times[0].tv_usec = statbuf.st_atimespec.tv_nsec * 0.001;
+ times[1].tv_usec = statbuf.st_mtimespec.tv_nsec * 0.001;
+#else
+ times[0].tv_usec = statbuf.st_atimensec * 0.001;
+ times[1].tv_usec = statbuf.st_mtimensec * 0.001;
+#endif
+#else
+ times[0].tv_usec = statbuf.st_atim.tv_nsec * 0.001;
+ times[1].tv_usec = statbuf.st_mtim.tv_nsec * 0.001;
+#endif
+ utimes(destination, times);
+#endif
+ }
+}
+
static int _control_import_image_copy(const char *filename,
char **prev_filename,
char **prev_output,
@@ -2308,37 +2361,37 @@ static int _control_import_image_copy(const char *filename,
g_free(basename);
}
- if(!g_file_set_contents(output, data, size, NULL))
+ if(!_copy_file(filename, output))
{
- dt_print(DT_DEBUG_CONTROL, "[import_from] failed to write file %s\n", output);
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to copy file %s", filename);
res = FALSE;
}
else
{
-#ifdef _WIN32
- struct utimbuf times;
- times.actime = statbuf.st_atime;
- times.modtime = statbuf.st_mtime;
- utime(output, &times); // set origin file timestamps
-#else
- struct timeval times[2];
- times[0].tv_sec = statbuf.st_atime;
- times[1].tv_sec = statbuf.st_mtime;
-#ifdef __APPLE__
-#ifndef _POSIX_SOURCE
- times[0].tv_usec = statbuf.st_atimespec.tv_nsec * 0.001;
- times[1].tv_usec = statbuf.st_mtimespec.tv_nsec * 0.001;
-#else
- times[0].tv_usec = statbuf.st_atimensec * 0.001;
- times[1].tv_usec = statbuf.st_mtimensec * 0.001;
-#endif
-#else
- times[0].tv_usec = statbuf.st_atim.tv_nsec * 0.001;
- times[1].tv_usec = statbuf.st_mtim.tv_nsec * 0.001;
-#endif
- utimes(output, times); // set origin file timestamps
-#endif
+ _copy_timestamps(filename, output);
+ }
+ gboolean import_existing_sidecar = dt_conf_get_bool("session/import_existing_sidecar");
+ if(import_existing_sidecar)
+ {
+ char *xml_filename = g_strdup_printf("%s.xmp", filename);
+ if(g_file_test(xml_filename, G_FILE_TEST_EXISTS))
+ {
+ char *xml_output = g_strdup_printf("%s.xmp", output);
+ if(_copy_file(xml_filename, xml_output))
+ _copy_timestamps(xml_filename, xml_output);
+ else
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to copy sidecar %s", xml_filename);
+ res = FALSE;
+ }
+ g_free(xml_output);
+ }
+ g_free(xml_filename);
+ }
+
+ if(res)
+ {
const dt_imgid_t imgid = dt_image_import(dt_import_session_film_id(session),
output, FALSE, FALSE);
if(!imgid) dt_control_log(_("error loading file `%s'"), output);

View File

@@ -0,0 +1,56 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
nixpkgs.overlays = [
(final: prev: {
darktable = prev.darktable.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./better-copy-and-import.patch ];
});
})
];
environment.persistence = {
"/persist"."${home}/.config/darktable" = { };
"/cache"."${home}/.cache/darktable" = { };
};
home-manager.users.${user} =
let
hald-clut = pkgs.fetchFromGitHub {
owner = "cedeber";
repo = "hald-clut";
rev = "3b3180f82d4dcea1e6e8c5648473539a910d7f49";
sha256 = "sha256-R8vyYmcsfk49QsSV3v0QblXcO6U0oIfDyxbHPLwSMdo=";
};
in
{
home.packages = with pkgs; [ darktable ];
xdg.configFile = {
"darktable/darktablerc".source = (pkgs.formats.keyValue { }).generate "darktablerc" {
"compress_xmp_tags" = "never";
"database/create_snapshot" = "once a day";
"rating_one_double_tap" = true;
"run_crawler_on_start" = true;
"ui_last/theme" = "darktable-elegant-darker";
"ui_last/grouping" = true;
"plugins/darkroom/lut3d/def_path" = "${home}/.config/darktable/luts";
"opencl" = false;
"plugins/lighttable/overlays/1/0" = 0;
"plugins/lighttable/overlays/1/1" = 3;
"plugins/lighttable/overlays/1/2" = 3;
"plugins/darkroom/modulegroups/last_preset" = "modules: all";
"session/base_directory_pattern" = "${home}/Pictures/Darktable";
"session/filename_pattern" =
"$(EXIF.YEAR)-$(EXIF.MONTH)-$(EXIF.DAY)_$(EXIF.HOUR)-$(EXIF.MINUTE)-$(EXIF.SECOND)_$(CONFLICT_PADDING).$(FILE_EXTENSION)";
"session/sub_directory_pattern" = "";
"setup_import_directory" = true;
};
"darktable/luts".source = "${hald-clut}/HaldCLUT";
};
};
}

View File

@@ -0,0 +1,73 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
nixpkgs.overlays = [
(final: prev: {
vesktop = prev.vesktop.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./readonly-fix.patch ];
});
})
];
environment.persistence = {
"/persist"."${home}/.config/vesktop" = { };
"/cache" = {
"${home}/.config/vesktop/sessionData/Cache" = { };
"${home}/.config/vesktop/sessionData/Code Cache" = { };
"${home}/.config/vesktop/sessionData/DawnGraphiteCache" = { };
"${home}/.config/vesktop/sessionData/DawnWebGPUCache" = { };
"${home}/.config/vesktop/sessionData/GPUCache" = { };
};
};
home-manager.users.${user} = {
home.packages = with pkgs; [ vesktop ];
xdg.configFile."vesktop/state.json".source = (pkgs.formats.json { }).generate "state.json" {
firstLaunch = false;
};
xdg.configFile."vesktop/settings.json".source = (pkgs.formats.json { }).generate "settings.json" {
discordBranch = "stable";
minimizeToTray = false;
arRPC = false;
};
xdg.configFile."vesktop/settings/settings.json".source =
(pkgs.formats.json { }).generate "settings.json"
{
autoUpdate = false;
tray = false;
plugins = {
MessageEventsAPI.enabled = true;
MessageUpdaterAPI.enabled = true;
UserSettingsAPI.enabled = true;
AlwaysTrust.enabled = true;
BetterGifAltText.enabled = true;
BetterRoleContext = {
enabled = true;
roleIconFileFormat = "png";
};
ClearURLs.enabled = true;
FakeNitro.enabled = true;
MessageClickActions.enabled = true;
MessageLogger = {
enabled = true;
deleteStyle = "overlay";
};
NoF1.enabled = true;
NoOnboardingDelay.enabled = true;
NoReplyMention = {
enabled = true;
userList = "";
};
};
enabledThemes = [ "matugen.theme.css" ];
};
theme.template."${home}/.config/vesktop/themes/matugen.theme.css".source = ./theme.css;
};
}

View File

@@ -0,0 +1,17 @@
diff --git a/src/main/settings.ts b/src/main/settings.ts
index 6fad97f..dfc64e3 100644
--- a/src/main/settings.ts
+++ b/src/main/settings.ts
@@ -26,8 +26,10 @@ function loadSettings<T extends object = any>(file: string, name: string) {
const store = new SettingsStore(settings);
store.addGlobalChangeListener(o => {
- mkdirSync(dirname(file), { recursive: true });
- writeFileSync(file, JSON.stringify(o, null, 4));
+ try {
+ mkdirSync(dirname(file), { recursive: true });
+ writeFileSync(file, JSON.stringify(o, null, 4));
+ } catch {}
});
return store;

View File

@@ -0,0 +1,76 @@
/*
@name Matugen
@author Matugen
@version 0.0.1
@description Theme configured via NixOS or Home Manager.
*/
.theme-dark {
--bg-overlay-2: {{colors.surface_container_high.dark.hex}};
--home-background: {{colors.surface_container_high.dark.hex}};
--background-primary: {{colors.surface_container_high.dark.hex}};
--background-secondary: {{colors.surface_container.dark.hex}};
--background-secondary-alt: {{colors.surface_container.dark.hex}};
--background-accent: {{colors.surface_container.dark.hex}};
--background-modifier-hover: {{colors.surface_container.dark.hex}};
--background-tertiary: {{colors.surface_container_low.dark.hex}};
--background-floating: {{colors.surface_container_low.dark.hex}};
--background-modifier-selected: {{colors.primary_container.dark.hex}};
--background-modifier-accent: {{colors.outline_variant.dark.hex}};
--channeltextarea-background: {{colors.surface_container.dark.hex}};
--text-normal: {{colors.on_surface.dark.hex}};
--text-secondary: {{colors.on_surface_variant.dark.hex}};
--text-muted: {{colors.outline.dark.hex}};
--text-link: {{colors.primary.dark.hex}};
--interactive-normal: {{colors.on_surface.dark.hex}};
--interactive-hover: {{colors.on_surface.dark.hex}};
--interactive-active: {{colors.on_primary_container.dark.hex}};
--interactive-muted: {{colors.outline_variant.dark.hex}};
--channels-default: {{colors.outline.dark.hex}};
--channel-icon: {{colors.outline.dark.hex}};
--header-primary: {{colors.on_surface.dark.hex}};
--header-secondary: {{colors.on_surface_variant.dark.hex}};
}
.theme-light {
--bg-overlay-2: {{colors.surface_container_high.light.hex}};
--home-background: {{colors.surface_container_high.light.hex}};
--background-primary: {{colors.surface_container_high.light.hex}};
--background-secondary: {{colors.surface_container.light.hex}};
--background-secondary-alt: {{colors.surface_container.light.hex}};
--background-accent: {{colors.surface_container.light.hex}};
--background-modifier-hover: {{colors.surface_container.light.hex}};
--background-tertiary: {{colors.surface_container_low.light.hex}};
--background-floating: {{colors.surface_container_low.light.hex}};
--background-modifier-selected: {{colors.primary_container.light.hex}};
--background-modifier-accent: {{colors.outline_variant.light.hex}};
--channeltextarea-background: {{colors.surface_container.light.hex}};
--text-normal: {{colors.on_surface.light.hex}};
--text-secondary: {{colors.on_surface_variant.light.hex}};
--text-muted: {{colors.outline.light.hex}};
--text-link: {{colors.primary.light.hex}};
--interactive-normal: {{colors.on_surface.light.hex}};
--interactive-hover: {{colors.on_surface.light.hex}};
--interactive-active: {{colors.on_primary_container.light.hex}};
--interactive-muted: {{colors.outline_variant.light.hex}};
--channels-default: {{colors.outline.light.hex}};
--channel-icon: {{colors.outline.light.hex}};
--header-primary: {{colors.on_surface.light.hex}};
--header-secondary: {{colors.on_surface_variant.light.hex}};
}

View File

@@ -0,0 +1,23 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
home-manager.users.${user} = {
programs.rofi.plugins = with pkgs; [ rofi-emoji-wayland ];
wayland.windowManager.hyprland.settings.bind = [
# Super + Shift + :
"$mod_Shift, code:47, exec, ${lib.meta.getExe hmConfig.programs.rofi.finalPackage} -cache-dir ${home}/.cache/rofi -modi emoji -show emoji"
];
};
}

View File

@@ -0,0 +1,101 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
environment.persistence = {
"/persist"."${home}/.mozilla" = { };
"/cache"."${home}/.cache/mozilla" = { };
};
home-manager.users.${user} = {
programs.firefox = {
enable = true;
policies = {
DisableTelemetry = true;
DisableFirefoxStudies = true;
DontCheckDefaultBrowser = true;
DisablePocket = true;
DefaultDownloadDirectory = "$HOME/Downloads";
OfferToSaveLogins = false;
AutofillAddressEnabled = false;
AutofillCreditCardEnabled = false;
Preferences = {
"browser.aboutConfig.showWarning" = false;
"browser.contentblocking.category" = "strict";
"browser.download.useDownloadDir" = false;
"browser.newtabpage.activity-stream.feeds.section.topstories" = false;
"browser.newtabpage.activity-stream.showSponsored" = false;
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
"browser.toolbars.bookmarks.visibility" = true;
"browser.sessionstore.restore_on_demand" = true;
"browser.sessionstore.restore_pinned_tabs_on_demand" = false;
"browser.translations.automaticallyPopup" = false;
};
};
profiles.default = {
settings."extensions.autoDisableScopes" = 0;
extensions = with pkgs.nur.repos.rycee.firefox-addons; [
languagetool
bitwarden
darkreader
noscript
sponsorblock
ublock-origin
violentmonkey
wayback-machine
];
search = {
default = "DuckDuckGo";
privateDefault = "DuckDuckGo";
order = [
"DuckDuckGo"
"Google"
"Wikipedia (en)"
"Nix Packages"
"Nix Options"
"Home Manager Options"
];
force = true;
engines = {
"Google".metaData.alias = "@g";
"DuckDuckGo".metaData.alias = "@d";
"Wikipedia (en)".metaData.alias = "@w";
"Nix" = {
urls = [
{
template = "https://mynixos.com/search";
params = [
{
name = "q";
value = "{searchTerms}";
}
];
}
];
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@n" ];
};
};
};
};
};
xdg.mimeApps.defaultApplications = lib.attrsets.genAttrs [
"text/html"
"x-scheme-handler/http"
"x-scheme-handler/https"
"x-scheme-handler/about"
"x-scheme-handler/unknown"
] (_: "firefox.desktop");
home.sessionVariables.DEFAULT_BROWSER = lib.meta.getExe pkgs.firefox;
wayland.windowManager.hyprland.settings.bind = [ "$mod, b, exec, ${lib.meta.getExe pkgs.firefox}" ];
};
}

View File

@@ -0,0 +1,85 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
environment.persistence."/persist" = {
"${home}/.steam" = { };
"${home}/.local/share/Steam" = { };
};
programs = {
steam = {
enable = true;
localNetworkGameTransfers.openFirewall = true;
extest.enable = true;
protontricks.enable = true;
};
gamescope = {
enable = true;
args = [
"--rt"
"-f"
];
};
gamemode.enable = true;
};
home-manager.users.${user} = {
systemd.user = {
services.steam-ln =
let
steamLn = lib.meta.getExe (
pkgs.writeShellApplication {
name = "steam-ln";
runtimeInputs = with pkgs; [ coreutils ];
text = builtins.readFile ./scripts/steam-ln.sh;
}
);
in
{
Unit = {
Description = "Sync Steam games with Games directory";
After = [
config.environment.persistence."/persist"."${home}/.local/share/Steam".mount
config.environment.persistence."/persist"."${home}/Games".mount
];
DefaultDependencies = false;
};
Service = {
ExecStart = steamLn;
Type = "oneshot";
};
Install.WantedBy = [ "graphical-session.target" ];
};
paths.steam-ln = {
Unit = {
Description = "Monitor Steam games directory for changes";
After = [
config.environment.persistence."/persist"."${home}/.local/share/Steam".mount
config.environment.persistence."/persist"."${home}/Games".mount
];
};
Path.PathChanged = "${home}/.local/share/Steam/steamapps/common";
Install.WantedBy = [ "graphical-session.target" ];
};
};
home = {
packages = with pkgs; [ protonup ];
sessionVariables.STEAM_EXTRA_COMPAT_TOOLS_PATHS = "${home}/.steam/root/compatibilitytools.d";
};
};
}

View File

@@ -0,0 +1,57 @@
STEAM="${HOME}/.local/share/Steam/steamapps/common"
GAMES="${HOME}/Games"
EXCLUDE=(
"Proton - Experimental"
"SteamLinuxRuntime_sniper"
"Steamworks Shared"
"Steam.dll"
)
is_excluded() {
local dir=$1
for exclude in "${EXCLUDE[@]}"; do
if [[ "${dir}" == "${exclude}" ]]; then
return 0
fi
done
return 1
}
for game in "${STEAM}"/*/; do
name=$(basename "${game}")
if is_excluded "${name}"; then
echo "Excluding ${name} from symlink creation."
continue
fi
if [[ -L "${GAMES}/${name}" ]]; then
continue
fi
if [[ -d "${GAMES}/${name}" || -f "${GAMES}/${name}" ]]; then
>&2 echo "Error: ${name} is already a regular directory or file."
continue
fi
echo "Creating symlink for ${name}..."
ln -s "${game}" "${GAMES}/${name}"
done
for link in "${GAMES}"/*; do
target=$(readlink "${link}")
if [[ ! "${target}" == "${STEAM}/"* ]]; then
continue
fi
name=$(basename "${target}")
if [[ -e "${target}" ]] && ! is_excluded "${name}"; then
continue
fi
echo "Removing symlink ${link}..."
rm "${link}"
done

View File

@@ -0,0 +1,108 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
# FIXME: https://github.com/lassekongo83/adw-gtk3/issues/267
nixpkgs.overlays = [
(final: prev: {
adw-gtk3 = prev.adw-gtk3.overrideAttrs (oldAttrs: rec {
pname = "adw-gtk3";
version = "5.3";
src = pkgs.fetchFromGitHub {
owner = "lassekongo83";
repo = pname;
rev = "v${version}";
sha256 = "sha256-DpJLX9PJX1Q8dDOx7YOXQzgNECsKp5uGiCVTX6iSlbI=";
};
});
})
];
home-manager.users.${user} = {
gtk = {
enable = true;
theme = {
package = pkgs.adw-gtk3;
name = "adw-gtk3-dark";
};
font = {
name = builtins.head hmConfig.theme.font.sansSerif.names;
package = builtins.head hmConfig.theme.font.sansSerif.packages;
inherit (hmConfig.theme.font) size;
};
iconTheme = {
name = builtins.head hmConfig.theme.icon.names;
package = builtins.head hmConfig.theme.icon.packages;
};
gtk2.configLocation = "${home}/.config/gtk-2.0/gtkrc";
gtk3.extraCss = "@import './theme.css';";
gtk4.extraCss = "@import './theme.css';";
};
home = {
pointerCursor.gtk.enable = true;
file =
{
".icons/default/index.theme".enable = false;
}
// builtins.listToAttrs (
builtins.map (name: {
name = ".icons/${name}";
value.enable = false;
}) (hmConfig.theme.icon.names ++ hmConfig.theme.cursor.names)
);
};
theme.template = {
"${home}/.config/gtk-3.0/theme.css".source = ./theme.css;
"${home}/.config/gtk-4.0/theme.css".source = ./theme.css;
};
theme.initExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "theme-gtk";
runtimeInputs = with pkgs; [
dbus
dconf
];
text = ''
MODE=$(cat "${hmConfig.theme.configDir}/mode")
if [ "$MODE" = "light" ]; then
GTK_THEME="adw-gtk3"
else
GTK_THEME="adw-gtk3-dark"
fi
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
DCONF_DBUS_RUN_SESSION=""
else
DCONF_DBUS_RUN_SESSION="dbus-run-session --dbus-daemon=dbus-daemon"
fi
$DCONF_DBUS_RUN_SESSION bash -c "
dconf write /org/gnome/desktop/interface/gtk-theme \"'$GTK_THEME'\"
dconf write /org/gnome/desktop/interface/color-scheme \"'prefer-$MODE'\"
"
'';
}
)
} &";
};
}

View File

@@ -0,0 +1,48 @@
@define-color window_bg_color alpha({{colors.surface.default.hex}}, {{custom.opacity}});
@define-color window_fg_color {{colors.on_surface.default.hex}};
@define-color view_bg_color @window_bg_color;
@define-color view_fg_color @window_fg_color;
@define-color accent_bg_color {{colors.primary_container.default.hex}};
@define-color accent_fg_color {{colors.on_primary_container.default.hex}};
@define-color accent_color {{colors.primary.default.hex}};
@define-color headerbar_bg_color @window_bg_color;
@define-color headerbar_fg_color @window_fg_color;
@define-color headerbar_backdrop_color alpha({{colors.surface_variant.default.hex}}, {{custom.opacity}});
@define-color headerbar_shade_color {{colors.shadow.default.hex}};
@define-color card_bg_color alpha({{colors.surface_container.default.hex}}, {{custom.opacity}});
@define-color card_fg_color {{colors.on_surface_variant.default.hex}};
@define-color card_shade_color {{colors.shadow.default.hex}};
@define-color popover_bg_color @window_bg_color;
@define-color popover_fg_color @window_fg_color;
@define-color dialog_bg_color @window_bg_color;
@define-color dialog_fg_color @window_fg_color;
@define-color sidebar_bg_color @card_bg_color;
@define-color sidebar_fg_color @card_fg_color;
@define-color sidebar_backdrop_color alpha({{colors.surface_variant.default.hex}}, {{custom.opacity}});
@define-color sidebar_shade_color @card_shade_color;
@define-color warning_bg_color {{colors.warning_container.default.hex}};
@define-color warning_fg_color {{colors.on_warning_container.default.hex}};
@define-color warning_color {{colors.warning.default.hex}};
@define-color error_bg_color {{colors.error_container.default.hex}};
@define-color error_fg_color {{colors.on_error_container.default.hex}};
@define-color error_color {{colors.error.default.hex}};
@define-color success_bg_color {{colors.success_container.default.hex}};
@define-color success_fg_color {{colors.on_success_container.default.hex}};
@define-color success_color {{colors.success.default.hex}};
@define-color destructive_bg_color {{colors.danger_container.default.hex}};
@define-color destructive_fg_color {{colors.on_danger_container.default.hex}};
@define-color destructive_color {{colors.danger.default.hex}};
@define-color panel_bg_color @window_bg_color;
@define-color panel_fg_color @window_fg_color;

View File

@@ -0,0 +1,156 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
programs.hyprland.enable = true;
home-manager.users.${user} = {
imports = [ ./options.nix ];
wayland.windowManager.hyprland = {
enable = true;
settings = {
"$mod" = "Super_L";
"$term" = lib.meta.getExe pkgs.kitty;
bind = [
"$mod, Return, exec, $term"
"$mod, `, togglespecialworkspace"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod_Shift, `, movetoworkspacesilent, special"
"$mod_Shift, 1, movetoworkspacesilent, 1"
"$mod_Shift, 2, movetoworkspacesilent, 2"
"$mod_Shift, 3, movetoworkspacesilent, 3"
"$mod_Shift, 4, movetoworkspacesilent, 4"
"$mod_Shift, 5, movetoworkspacesilent, 5"
"$mod_Shift, 6, movetoworkspacesilent, 6"
"$mod_Shift, 7, movetoworkspacesilent, 7"
"$mod_Shift, 8, movetoworkspacesilent, 8"
"$mod_Shift, 9, movetoworkspacesilent, 9"
"$mod_Shift, 0, movetoworkspacesilent, 10"
"$mod_Ctrl, Space, workspaceopt, allfloat"
"$mod, left, movefocus, l"
"$mod, h, movefocus, l"
"$mod, down, movefocus, d"
"$mod, j, movefocus, d"
"$mod, up, movefocus, u"
"$mod, k, movefocus, u"
"$mod, right, movefocus, r"
"$mod, l, movefocus, r"
"$mod_Shift, left, movewindow, l"
"$mod_Shift, h, movewindow, l"
"$mod_Shift, down, movewindow, d"
"$mod_Shift, j, movewindow, d"
"$mod_Shift, up, movewindow, u"
"$mod_Shift, k, movewindow, u"
"$mod_Shift, right, movewindow, r"
"$mod_Shift, l, movewindow, r"
"$mod, Tab, cyclenext"
"$mod, Tab, bringactivetotop"
"$mod_Shift, Tab, cyclenext, prev"
"$mod_Shift, Tab, bringactivetotop"
"$mod, f, fullscreen, 0"
"$mod, m, fullscreen, 1"
"$mod, p, pin"
"$mod, Space, togglefloating"
"$mod, Space, centerwindow"
"$mod, q, killactive"
"Ctrl_Alt, Delete, exit"
];
binde = [
"$mod_Ctrl, left, resizeactive, -20 0"
"$mod_Ctrl, h, resizeactive, -20 0"
"$mod_Ctrl, down, resizeactive, 0 20"
"$mod_Ctrl, j, resizeactive, 0 20"
"$mod_Ctrl, up, resizeactive, 0 -20"
"$mod_Ctrl, k, resizeactive, 0 -20"
"$mod_Ctrl, right, resizeactive, 20 0"
"$mod_Ctrl, l, resizeactive, 20 0"
];
bindm = [
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
];
input = {
accel_profile = "flat";
kb_layout = "us,gr";
kb_options = "grp:alt_shift_toggle";
};
gestures = {
workspace_swipe = true;
workspace_swipe_min_fingers = true;
workspace_swipe_forever = true;
workspace_swipe_cancel_ratio = 0.2;
};
misc = {
disable_hyprland_logo = true;
disable_splash_rendering = true;
new_window_takes_over_fullscreen = 2;
};
decoration.blur = {
passes = 2;
popups = true;
};
input.touchpad.natural_scroll = true;
xwayland.force_zero_scaling = true;
};
extraConfig = "source = ./theme.conf";
};
programs.zsh.loginExtra = lib.mkAfter ''
if [ -z "$WAYLAND_DISPLAY" ] && [ -n "$XDG_VTNR" ] && [ "$XDG_VTNR" -eq 1 ]; then
Hyprland &> /tmp/hyprland.log
fi
'';
theme = {
template."${home}/.config/hypr/theme.conf".source = ./theme.conf;
reloadExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-hyprland";
runtimeInputs = with pkgs; [ hyprland ];
text = "exec hyprctl reload";
}
)
} &";
};
home.sessionVariables.NIXOS_OZONE_WL = "1";
};
}

View File

@@ -0,0 +1,43 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.wayland.windowManager.hyprland;
in
{
options.wayland.windowManager.hyprland =
with lib;
with types;
{
initExtraConfig = mkOption {
type = lines;
default = "";
description = "Extra configuration lines to add to exec-once";
};
reloadExtraConfig = mkOption {
type = lines;
default = "";
description = "Extra configuration lines to add to exec";
};
};
config = {
wayland.windowManager.hyprland.settings.exec-once = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-hyprland";
text = cfg.initExtraConfig;
}
);
wayland.windowManager.hyprland.settings.exec = lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-hyprland";
text = cfg.reloadExtraConfig;
}
);
};
}

View File

@@ -0,0 +1,25 @@
general {
gaps_in = {{custom.padding}}
gaps_out = {{custom.padding_double}}
col.inactive_border = rgba({{colors.surface.default.hex_stripped}}{{custom.opacity_hex | to_lower}})
col.active_border = rgb({{colors.primary.default.hex_stripped}})
}
decoration {
rounding = {{custom.radius}}
shadow {
color = rgba({{colors.shadow.default.hex_stripped}}{{custom.opacity_shadow_hex | to_lower}})
}
blur {
size = {{custom.blur}}
}
}
misc {
col.splash = rgb({{colors.on_surface.default.hex_stripped}})
background_color = rgb({{colors.surface.default.hex_stripped}})
font_family = {{custom.font_sans_serif}}
splash_font_family = {{custom.font_monospace}}
}

View File

@@ -0,0 +1,42 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
home = {
packages = with pkgs; [
hyprshot
swappy
];
sessionVariables.HYPRSHOT_DIR = "Pictures/screenshots";
};
wayland.windowManager.hyprland.settings.bind =
let
hyprshot = lib.meta.getExe pkgs.hyprshot;
date = "${pkgs.coreutils}/bin/date";
filename = "\"$(${date} +'%Y-%m-%d-%H%M%S.png')\"";
swappyWrapper = lib.meta.getExe (
pkgs.writeShellApplication {
name = "swappy-wrapper";
runtimeInputs = with pkgs; [ swappy ];
text = "exec swappy -f \"$1\"";
}
);
in
[
", Print, exec, ${hyprshot} -m output -m active -f ${filename}"
"Shift, Print, exec, ${hyprshot} -m output -m active -f ${filename} -- ${swappyWrapper}"
", XF86SelectiveScreenshot, exec, ${hyprshot} -m region -z -f ${filename}"
"Shift, XF86SelectiveScreenshot, exec, ${hyprshot} -m region -z -f ${filename} -- ${swappyWrapper}"
];
};
}

View File

@@ -0,0 +1,47 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.cache/kitty" = { };
home-manager.users.${user} = {
programs.kitty = {
enable = true;
font = {
name = builtins.head hmConfig.theme.font.monospace.names;
package = builtins.head hmConfig.theme.font.monospace.packages;
inherit (hmConfig.theme.font) size;
};
extraConfig = ''
confirm_os_window_close 0
include theme.conf
'';
};
theme = {
template."${home}/.config/kitty/theme.conf".source = ./theme.conf;
reloadExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-kitty";
runtimeInputs = with pkgs; [ procps ];
text = "exec pkill kitty -SIGUSR1";
}
)
} &";
};
};
}

View File

@@ -0,0 +1,29 @@
background_tint 0.0
background_opacity {{custom.opacity}}
background {{colors.surface.default.hex}}
foreground {{colors.on_surface.default.hex}}
selection_background {{colors.primary.default.hex}}
selection_foreground {{colors.on_primary.default.hex}}
url_color {{colors.tertiary.default.hex}}
cursor {{colors.on_surface.default.hex}}
color0 {{colors.surface.default.hex}}
color1 {{colors.red.default.hex}}
color2 {{colors.green.default.hex}}
color3 {{colors.yellow.default.hex}}
color4 {{colors.blue.default.hex}}
color5 {{colors.magenta.default.hex}}
color6 {{colors.cyan.default.hex}}
color7 {{colors.on_surface.default.hex}}
color8 {{colors.outline_variant.default.hex}}
color9 {{colors.red.default.hex | set_lightness: 5.0}}
color10 {{colors.green.default.hex | set_lightness: 5.0}}
color11 {{colors.yellow.default.hex | set_lightness: 5.0}}
color12 {{colors.blue.default.hex | set_lightness: 5.0}}
color13 {{colors.magenta.default.hex | set_lightness: 5.0}}
color14 {{colors.cyan.default.hex | set_lightness: 5.0}}
color15 {{colors.on_surface_variant.default.hex}}

View File

@@ -0,0 +1,39 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
environment.persistence = {
"/persist"."${home}/.config/libreoffice/4/user" = { };
"/cache"."${home}/.config/libreoffice/4/cache" = { };
};
home-manager.users.${user} = {
home.packages = with pkgs; [
libreoffice-fresh
hunspell
hunspellDicts.en-us-large
hunspellDicts.el-gr
];
xdg.configFile."libreoffice/4/user/registrymodifications.xcu" = {
force = true;
text = ''
<?xml version="1.0" encoding="UTF-8"?>
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="ShowTipOfTheDay" oor:op="fuse"><value>false</value></prop></item>
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item>
<item oor:path="/org.openoffice.Setup/Office"><prop oor:name="ooSetupInstCompleted" oor:op="fuse"><value>true</value></prop></item>
<item oor:path="/org.openoffice.Setup/Product"><prop oor:name="ooSetupLastVersion" oor:op="fuse"><value>${lib.lists.last (lib.strings.splitString "/" pkgs.libreoffice-fresh.meta.changelog)}</value></prop></item>
<item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeDonateShown" oor:op="fuse"><value>0</value></prop></item>
<item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeGetInvolvedShown" oor:op="fuse"><value>0</value></prop></item>
'';
};
};
}

View File

@@ -0,0 +1,12 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user} = {
home.packages = with pkgs; [ networkmanagerapplet ];
services.network-manager-applet.enable = true;
systemd.user.services.network-manager-applet.Unit.After = [ "graphical-session.target" ];
};
}

View File

@@ -0,0 +1,45 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
let
hmConfig = config.home-manager.users.${user};
in
{
boot = {
kernelModules = [ "v4l2loopback" ];
extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
extraModprobeConfig = ''
options v4l2loopback devices=1 video_nr=1 card_label="OBS Cam" exclusive_caps=1
'';
};
environment.persistence = {
"/persist"."${home}/.config/obs-studio" = { };
};
home-manager.users.${user} = {
imports = [ ./options.nix ];
programs.obs-studio.enable = true;
xdg.configFile."obs-studio/basic/profiles/Untitled/basic.ini".source =
(pkgs.formats.ini { }).generate "basic.ini"
{
SimpleOutput = {
FilePath = "${home}/Videos";
VBitrate = 4000;
ABitrate = 320;
RecEncoder = "nvenc_hevc";
FileNameWithoutSpace = true;
};
Video = with hmConfig.programs.obs-studio.resolution; {
BaseCX = base.x;
BaseCY = base.y;
OutputCX = output.x;
OutputCY = output.y;
};
};
};
}

View File

@@ -0,0 +1,31 @@
{ lib, ... }:
{
options.programs.obs-studio.resolution =
with lib;
with types;
{
base = {
x = mkOption {
type = int;
description = "Base resolution width.";
};
y = mkOption {
type = int;
description = "Base resolution height.";
};
};
output = {
x = mkOption {
type = int;
description = "Output resolution width.";
};
y = mkOption {
type = int;
description = "Output resolution height.";
};
};
};
}

View File

@@ -0,0 +1,3 @@
!*/.obsidian/bookmarks.json
*/.obsidian
.nomedia

View File

@@ -0,0 +1,27 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.better-word-count";
version = "0.10.1";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "8ff00d7e9aed03d8cf38215b742a2a2251cc2ea2";
# owner = "lukeleppan";
repo = "better-word-count";
# rev = version;
hash = "sha256-wA0vycuUHr7icgAJ/d85j3bbwqlefXnSyRUXgCmqyOE=";
};
patches = [ ./package-lock.patch ];
makeCacheWritable = true;
npmDepsHash = "sha256-K+NGIKsSNzGHGcAofsl0WcNsTFt/y38zUdGUZL013xg=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
cp ./src/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,35 @@
diff --git a/package-lock.json b/package-lock.json
index 3fa99a5..71302ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,7 @@
},
"devDependencies": {
"@codemirror/commands": "^6.1.2",
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/search": "^6.2.2",
"@codemirror/state": "^6.1.2",
"@codemirror/view": "^6.4.0",
@@ -49,7 +49,7 @@
},
"node_modules/@codemirror/language": {
"version": "6.10.1",
- "resolved": "git+ssh://git@github.com/lishid/cm-language.git#2644bfc27afda707a7e1f3aedaf3ca7120f63cd9",
+ "resolved": "git+ssh://git@github.com/karaolidis/cm-language.git#d6238f0a9e17e20d604cee67a47d3a93b00dd41c",
"dev": true,
"dependencies": {
"@codemirror/state": "^6.0.0",
diff --git a/package.json b/package.json
index 2537f1e..ba6bfff 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"license": "MIT",
"devDependencies": {
"@codemirror/commands": "^6.1.2",
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/search": "^6.2.2",
"@codemirror/state": "^6.1.2",
"@codemirror/view": "^6.4.0",

View File

@@ -0,0 +1,30 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.custom-sort";
version = "2.1.14";
src = pkgs.fetchFromGitHub {
owner = "SebastianMC";
repo = "obsidian-custom-sort";
rev = version;
hash = "sha256-DM2aKCsFC2Z4a/ZX95ZMBzshBx2C2Z8a7j94ABS2UGI=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-RdR+S6WQj2AAoxJnAowNa1etr/Xfp6HnhM7rMYJh8o8=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
'';
}

View File

@@ -0,0 +1,25 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.dataview";
version = "0.5.67";
src = pkgs.fetchFromGitHub {
owner = "blacksmithgu";
repo = "obsidian-dataview";
rev = version;
hash = "sha256-AbK1J1a8bqkPCe9dqADAfR/q/j/kRGa8qouj9GJQErc=";
};
patches = [ ./package-lock.patch ];
makeCacheWritable = true;
npmDepsHash = "sha256-FsPLpWcS27VWrDm5G1ZT6zvfOfYmKNLHzmjiXEmpGKE=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./build/main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,90 @@
diff --git a/package-lock.json b/package-lock.json
index 0c1b0bd..df26135 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,15 @@
{
"name": "obsidian-dataview",
- "version": "0.5.66",
+ "version": "0.5.67",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "obsidian-dataview",
- "version": "0.5.66",
+ "version": "0.5.67",
"license": "MIT",
"dependencies": {
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"emoji-regex": "^10.0.0",
@@ -687,29 +687,28 @@
"dev": true
},
"node_modules/@codemirror/language": {
- "version": "6.6.0",
- "resolved": "git+ssh://git@github.com/lishid/cm-language.git#1aadcc247f20ccfda76424a9f853dbb4ee203fdc",
- "license": "MIT",
+ "version": "6.10.1",
+ "resolved": "git+ssh://git@github.com/karaolidis/cm-language.git#d6238f0a9e17e20d604cee67a47d3a93b00dd41c",
"dependencies": {
"@codemirror/state": "^6.0.0",
- "@codemirror/view": "^6.0.0",
- "@lezer/common": "^1.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/state": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.1.tgz",
- "integrity": "sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw=="
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
+ "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
},
"node_modules/@codemirror/view": {
- "version": "6.19.0",
- "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.19.0.tgz",
- "integrity": "sha512-XqNIfW/3GaaF+T7Q1jBcRLCPm1NbrR2DBxrXacSt1FG+rNsdsNn3/azAfgpUoJ7yy4xgd8xTPa3AlL+y0lMizQ==",
+ "version": "6.28.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.4.tgz",
+ "integrity": "sha512-QScv95fiviSQ/CaVGflxAvvvDy/9wi0RFyDl4LkHHWiMr/UPebyuTspmYSeN5Nx6eujcPYwsQzA6ZIZucKZVHQ==",
"dependencies": {
- "@codemirror/state": "^6.1.4",
+ "@codemirror/state": "^6.4.0",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
@@ -1133,9 +1132,9 @@
}
},
"node_modules/@lezer/common": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.4.tgz",
- "integrity": "sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg=="
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
+ "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
},
"node_modules/@lezer/highlight": {
"version": "1.1.6",
diff --git a/package.json b/package.json
index db15b53..d3605a0 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,7 @@
"rollup-plugin-web-worker-loader": "^1.6.1"
},
"dependencies": {
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"emoji-regex": "^10.0.0",

View File

@@ -0,0 +1,28 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.excalidraw";
version = "2.2.8";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "9f5811b0f849b0f1a6a842945a81b605f65a9bdb";
# owner = "zsviczian";
repo = "obsidian-excalidraw-plugin";
# rev = version;
hash = "sha256-/YbbGFYWkzBxdIFpFNn85D8oXJsFrgndq3KZmMSxcvw=";
};
npmDepsHash = "sha256-KgsmcGj8WbWLCxaXMNA8anGcmOq0BzuDtdeNqS8ra8E=";
npmPackFlags = [ "--ignore-scripts" ];
configurePhase = ''
mkdir dist
'';
installPhase = ''
mkdir -p $out
cp ./dist/manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
cp ./dist/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,24 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.folder-note";
version = "0.7.3";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "2d14ccb5179beb48c3df87108170aeda067584ac";
# owner = "xpgo";
repo = "obsidian-folder-note-plugin";
# rev = version;
hash = "sha256-Ub0u+hMbkzxeUjzVmA61S0ClXR9E3KrYTqhrJBQj0Wg=";
};
npmDepsHash = "sha256-4v6QwwooxsXy+mbiKriylpKa8NOK8pWZixezY+H6wxo=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.kanban";
version = "2.0.51";
src = pkgs.fetchFromGitHub {
owner = "mgmeyers";
repo = "obsidian-kanban";
rev = version;
hash = "sha256-NahypggwPrub2KxRBAn54ZpEInP1V+6l/xmUKUt6myA=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-eof2W9Ja4RlmjQ0SnaF/jadHX3GRkCRrMwZU2z0M/Jk=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,35 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.languagetool";
version = "0.3.7";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "a7bb62f767decbd55b14702c35e24954459e77ca";
# owner = "Clemens-E";
repo = "obsidian-languagetool-plugin";
# rev = version;
hash = "sha256-LeSK9ctdKW6P3AoOWHxHmGxIlOXDOVd1nhsWXdRSiZY=";
};
patches = [ ./settings-notification.patch ];
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-749RGQmg9Mte7TR6k3qP6xcb8+rj/C60LYLbF8j8gNc=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,12 @@
diff --git a/src/index.ts b/src/index.ts
index 00cccfe..43e6107 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -42,7 +42,6 @@ export default class LanguageToolPlugin extends Plugin {
try {
await this.saveSettings();
await this.loadSettings();
- new Notice('updated LanguageTool Settings, please confirm your server URL in the settings tab', 10000);
} catch (e) {
console.error(e);
}

View File

@@ -0,0 +1,22 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.linter";
version = "1.25.0";
src = pkgs.fetchFromGitHub {
owner = "platers";
repo = "obsidian-linter";
rev = version;
hash = "sha256-jf3tIE6zDD5VCrkWWgxpANqrYUqJunESD08bVJB2H54=";
};
npmDepsHash = "sha256-Bln8cD04ACdj73xXrcG6RVlET1D1bfMsRZqaejbAedo=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./src/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,24 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.map-view";
version = "5.0.2";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "22e13b87e43dc5a5e40240e7de216ed8f638e741";
# owner = "esm7";
repo = "obsidian-map-view";
# rev = version;
hash = "sha256-n++PIWsaxAFnbfzlD0sWMs5+ljOXjA+ft6d/m/p2oq8=";
};
npmDepsHash = "sha256-AzJfluB+KjGudESedQxX4BxStnELeFDHO+h+f73ihuA=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./dist/manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
cp ./dist/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,24 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.minimal-settings";
version = "8.0.2";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "2bdab8f00be4b98600e40d6a2ecac8be359c99dd";
# owner = "kepano";
repo = "obsidian-minimal-settings";
# rev = version;
hash = "sha256-JI7I1n6ZiWdzemoLFGt7C3RF+HQgh9BmmI3owZNm944=";
};
npmDepsHash = "sha256-N9wfFsbpcO53Lno6sM4OvXywUqn9L2DpS4HfmjL1Ld4=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,22 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.outliner";
version = "4.8.1";
src = pkgs.fetchFromGitHub {
owner = "vslinko";
repo = "obsidian-outliner";
rev = version;
hash = "sha256-LfkK1c3khA75UZQMJStvV2bccHTz4eMqtEIC8jPFKBM=";
};
npmDepsHash = "sha256-EVSunBtuOo93Zhq95u80j/MArRZaAyKdcwUz61qHXiQ=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,21 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.read-it-later";
version = "0.4.0";
src = pkgs.fetchFromGitHub {
owner = "DominikPieper";
repo = "obsidian-ReadItLater";
rev = version;
hash = "sha256-yaEgYH9jfjumZJ/kD/jj2NDTsuvP6EmyfYXEj5E8Q0Q=";
};
npmDepsHash = "sha256-OOhdusXBbxSl8S2uCGTqkTDYEbO5FxOlH8cehwU3LjY=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
'';
}

View File

@@ -0,0 +1,33 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.style-settings";
version = "1.0.8";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "57ef34b6d8903451311db63084eef80b7b7e1a62";
# owner = "mgmeyers";
repo = "obsidian-style-settings";
# rev = version;
hash = "sha256-ZxYkd0kyDnHwPt5Z1iFpRgQHLKhN4O9S5S7Izz5hd9E=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-Wf5pIbhSdo/rOs/TDqRjiS2JxWWbWsI2IOqCW78gFkU=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.tasks";
version = "7.6.1";
src = pkgs.fetchFromGitHub {
owner = "obsidian-tasks-group";
repo = "obsidian-tasks";
rev = version;
hash = "sha256-7VvoaX2WkKrg2WpR+JQcpT73rAhZXJ3FXr2BBUIwrmA=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-3ReJNZKgecKTbXTWZGSY2hBLHysdbr/iKFS9tgCJvW0=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,23 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.url-into-selection";
version = "1.7.0";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "9f85d59be28797b7ef16c452fa3c4093f60b3bab";
# owner = "denolehov";
repo = "obsidian-url-into-selection";
# rev = version;
hash = "sha256-MQV8CMzCha0MUGLh4c1WuHVXRiCPEwtSgd3Xoj/81hA=";
};
npmDepsHash = "sha256-tThyrhezHZ29JUzx5sy2SfoZIGYP0DOQBctxYB5O1P4=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
'';
}

View File

@@ -0,0 +1,18 @@
:root {
--replete-custom-separators-vertical-padding: 4px;
--replete-custom-separators-left-margin: -12px;
}
.nav-files-container [class*=nav-]:has(:is(
[data-path="Inbox"],
[data-path="Dreams"],
[data-path="Work"],
[data-path="Random"],
))::after {
content:'';
display:block;
height:1px;
width:calc(100% + 32px);
background:linear-gradient(to right, var(--tab-outline-color), transparent);
margin:var(--replete-custom-separators-vertical-padding) 0 var(--replete-custom-separators-vertical-padding) var(--replete-custom-separators-left-margin);
}

View File

@@ -0,0 +1,27 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.themes.minimal";
version = "7.7.7";
src = pkgs.fetchFromGitHub {
owner = "kepano";
repo = "obsidian-minimal";
rev = version;
hash = "sha256-Atb9ZVou4EkfppV7VvTEMG/UruKlADctbXL1M8vvhxQ=";
};
npmDepsHash = "sha256-PzsZv/On8ci6EkF3WE4aez3/jQu5AqyJxFUzJk+Pn0c=";
npmPackFlags = [ "--ignore-scripts" ];
nativeBuildInputs = with pkgs; [ sass ];
buildPhase = ''
npx grunt cssmin
'';
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./theme.css $out/theme.css
'';
}

View File

@@ -0,0 +1,720 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.config/obsidian" = { };
home-manager.users.${user} = {
imports = [ ./options.nix ];
programs.obsidian = {
enable = true;
sharedSettings = {
app = {
defaultViewMode = "preview";
livePreview = false;
readableLineLength = true;
showLineNumber = true;
tabSize = 2;
promptDelete = false;
trashOption = "local";
alwaysUpdateLinks = true;
newFileLocation = "folder";
newFileFolderPath = "inbox";
newLinkFormat = "absolute";
showUnsupportedFiles = true;
attachmentFolderPath = "./assets";
};
corePlugins = [
"bookmarks"
{
name = "canvas";
options = {
newFileLocation = "folder";
newFileFolderPath = "Inbox";
defaultWheelBehavior = "zoom";
};
}
"canvas"
{
name = "command-palette";
options = {
pinned = [
"file-explorer:new-file"
"canvas:new-file"
"obsidian-excalidraw-plugin:excalidraw-autocreate-on-current"
"obsidian-kanban:create-new-kanban-board"
"obsidian-read-it-later:save-clipboard-to-notice"
];
};
}
"editor-status"
"file-explorer"
"global-search"
"graph"
"note-composer"
"outgoing-link"
"outline"
"page-preview"
"slash-command"
"switcher"
"tag-pane"
];
communityPlugins = [
{
pkg = pkgs.callPackage ./config/plugins/better-word-count { };
options = {
statusBar = [
{
prefix = "";
suffix = " words";
metric = {
type = 0;
counter = 0;
};
}
];
altBar = [
{
prefix = "";
suffix = " files";
metric = {
type = 2;
counter = 6;
};
}
];
countComments = true; # Inverse
};
}
{
pkg = pkgs.callPackage ./config/plugins/custom-sort { };
options = {
suspended = false;
statusBarEntryEnabled = false;
notificationsEnabled = false;
customSortContextSubmenu = false;
bookmarksGroupToConsumeAsOrderingReference = "Sort";
bookmarksContextMenus = false;
};
}
{
pkg = pkgs.callPackage ./config/plugins/dataview { };
options = {
enableDataviewJs = true;
enableInlineDataviewJs = true;
warnOnEmptyResult = false;
defaultDateFormat = "dd/MM/yyyy";
defaultDateTimeFormat = "HH:mm - dd/MM/yyyy";
};
}
{
pkg = pkgs.callPackage ./config/plugins/excalidraw { };
options = {
folder = "Inbox";
templateFilePath = "Templates";
scriptFolderPath = "Scripts";
compress = false;
drawingFilenamePrefix = "";
drawingEmbedPrefixWithFilename = false;
drawingFilenameDateTime = "YYYY-MM-DD-HH.mm.ss";
previewImageType = "SVG";
previewMatchObsidianTheme = true;
defaultPenMode = "mobile";
parseTODO = true;
focusOnFileTab = true;
pngExportScale = 2;
exportWithTheme = false;
exportWithBackground = false;
exportEmbedScene = true;
showReleaseNotes = false;
showNewVersionNotification = false;
};
}
{
pkg = pkgs.callPackage ./config/plugins/folder-note { };
options = {
folderNoteHide = false;
folderNoteStrInit = "";
};
}
{
pkg = pkgs.callPackage ./config/plugins/kanban { };
options = {
move-tags = true;
move-dates = true;
date-display-format = "DD/MM/YYYY";
show-relative-date = true;
date-picker-week-start = 1;
inline-metadata-position = "footer";
move-task-metadata = true;
show-archive-all = false;
show-board-settings = false;
};
}
{
pkg = pkgs.callPackage ./config/plugins/languagetool { };
options = {
shouldAutoCheck = true;
pickyMode = true;
staticLanguage = "auto";
englishVariety = "en-US";
};
}
{
pkg = pkgs.callPackage ./config/plugins/linter { };
options = {
lintOnSave = true;
displayChanged = false;
lintOnFileChange = true;
ruleConfigs = {
add-blank-line-after-yaml.enabled = true;
dedupe-yaml-array-values.enabled = true;
escape-yaml-special-characters = {
enabled = true;
try-to-escape-single-line-arrays = true;
};
format-tags-in-yaml.enabled = true;
format-yaml-array = {
enabled = true;
default-array-style = "multi-line";
};
sort-yaml-array-values.enabled = true;
capitalize-headings = {
enabled = true;
ignore-words = "";
};
header-increment = {
enabled = true;
start-at-h2 = true;
};
headings-start-line.enabled = true;
remove-trailing-punctuation-in-heading.enabled = true;
auto-correct-common-misspellings.enabled = true;
blockquote-style.enabled = true;
convert-bullet-list-markers.enabled = true;
emphasis-style = {
enabled = true;
style = "asterisk";
};
no-bare-urls = {
enabled = true;
no-bare-uris = true;
};
ordered-list-style.enabled = true;
quote-style.enabled = true;
remove-consecutive-list-markers.enabled = true;
remove-empty-list-markers.enabled = true;
remove-hyphenated-line-breaks.enabled = true;
remove-multiple-spaces.enabled = true;
strong-style = {
enabled = true;
style = "asterisk";
};
two-spaces-between-lines-with-content.enabled = true;
unordered-list-style = {
enabled = true;
list-style = "-";
};
compact-yaml = {
enabled = true;
inner-new-lines = true;
};
consecutive-blank-lines.enabled = true;
empty-line-around-blockquotes.enabled = true;
empty-line-around-code-fences.enabled = true;
empty-line-around-math-blocks.enabled = true;
empty-line-around-tables.enabled = true;
heading-blank-lines.enabled = true;
line-break-at-document-end.enabled = true;
move-math-block-indicators-to-their-own-line.enabled = true;
paragraph-blank-lines.enabled = true;
remove-empty-lines-between-list-markers-and-checklists.enabled = true;
remove-link-spacing.enabled = true;
space-after-list-markers.enabled = true;
trailing-spaces.enabled = true;
add-blockquote-indentation-on-paste.enabled = true;
prevent-double-checklist-indicator-on-paste.enabled = true;
prevent-double-list-item-indicator-on-paste.enabled = true;
remove-hyphens-on-paste.enabled = true;
remove-leading-or-trailing-whitespace-on-paste.enabled = true;
remove-leftover-footnotes-from-quote-on-paste.enabled = true;
remove-multiple-blank-lines-on-paste.enabled = true;
};
customRegexes = [
{
label = "Open Double Quote";
find = "";
replace = "\"";
flags = "gm";
}
{
label = "Close Double Quote";
find = "";
replace = "\"";
flags = "gm";
}
{
label = "Elipsis";
find = "";
replace = "...";
flags = "gm";
}
{
label = "Open Quote";
find = "";
replace = "'";
flags = "gm";
}
{
label = "Close Quote";
find = "";
replace = "'";
flags = "gm";
}
{
label = "Long Dash";
find = "";
replace = "---";
flags = "gm";
}
{
label = "Short Dash";
find = "";
replace = "--";
flags = "gm";
}
{
label = "Long Dash with Text";
find = "([^\\s])---([^\\s])";
replace = "$1 --- $2";
flags = "gm";
}
{
label = "Short Dash with Text";
find = "([^\\s])--([^\\s])";
replace = "$1 -- $2";
flags = "gm";
}
];
commonStyles = {
removeUnnecessaryEscapeCharsForMultiLineArrays = true;
};
};
}
{
pkg = pkgs.callPackage ./config/plugins/map-view { };
options = {
"markerIconRules" = [
{
"ruleName" = "default";
"preset" = true;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-circle";
"markerColor" = "blue";
};
}
{
"ruleName" = "#restaurant";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-utensils";
"markerColor" = "red";
};
}
{
"ruleName" = "#bar";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-martini-glass";
"markerColor" = "purple";
};
}
{
"ruleName" = "#coffee";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-mug-hot";
"markerColor" = "purple";
};
}
{
"ruleName" = "#culture";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-building-columns";
"markerColor" = "black";
};
}
{
"ruleName" = "#shopping";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-shopping-bag";
"markerColor" = "yellow";
};
}
{
"ruleName" = "#entertainment";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-microphone";
"markerColor" = "pink";
};
}
{
"ruleName" = "#nature";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-tree";
"markerColor" = "green";
};
}
];
"searchProvider" = "google";
"geocodingApiMethod" = "path";
"geocodingApiPath" = hmConfig.sops.secrets."google/geocoding".path;
"useGooglePlaces" = true;
"letZoomBeyondMax" = true;
"showGeolinkPreview" = true;
"newNotePath" = "Inbox";
};
}
{
pkg = pkgs.callPackage ./config/plugins/minimal-settings { };
options = {
editorFont = "var(--font-monospace)";
};
}
{
pkg = pkgs.callPackage ./config/plugins/outliner { };
options = {
styleLists = false;
stickCursor = "never";
};
}
{
pkg = pkgs.callPackage ./config/plugins/read-it-later { };
options = {
inboxDir = "Inbox";
assetsDir = "Inbox/assets";
openNewNote = true;
youtubeNote = ''
---
source: %videoURL%
---
%videoPlayer%
'';
vimeoNote = ''
---
source: %videoURL%
---
%videoPlayer%
'';
bilibiliNote = ''
---
source: %videoURL%
---
%videoPlayer%
'';
twitterNote = ''
---
source: %tweetURL%
---
%tweetContent%
'';
parsableArticleNote = ''
---
source: %articleURL%
---
%articleContent%
'';
mastodonNote = ''
---
source: %tootURL%
---
> %tootContent%
'';
stackExchangeNote = ''
---
source: %questionURL%
---
Author: [%authorName%](%authorProfileURL%)
%questionContent%
***
%topAnswer%
%answers%
'';
stackExchangeAnswer = ''
Answered by: [%authorName%](%authorProfileURL%)
> %answerContent%
'';
tikTokNote = ''
---
source: %videoURL%
---
%videoDescription%
%videoPlayer%
'';
notParsableArticleNote = ''
---
source: %articleURL%
---
%previewURL%
'';
textSnippetNote = "%content%";
};
}
(pkgs.callPackage ./config/plugins/style-settings { })
{
pkg = pkgs.callPackage ./config/plugins/tasks { };
options = {
globalQuery = "short mode";
globalFilter = "#todo";
removeGlobalFilter = true;
setCreatedDate = true;
statusSettings = {
coreStatuses = [
{
symbol = " ";
name = "to-do";
nextStatusSymbol = "/";
type = "TODO";
}
{
symbol = "x";
name = "done";
nextStatusSymbol = " ";
type = "DONE";
}
];
customStatuses = [
{
symbol = "/";
name = "in-progress";
nextStatusSymbol = "x";
type = "IN_PROGRESS";
}
{
symbol = "-";
name = "canceled";
nextStatusSymbol = " ";
type = "CANCELLED";
}
{
symbol = ">";
name = "forwarded";
nextStatusSymbol = "/";
type = "IN_PROGRESS";
}
{
symbol = "<";
name = "scheduling";
nextStatusSymbol = "/";
type = "TODO";
}
{
symbol = "?";
name = "question";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "!";
name = "important";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "*";
name = "star";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "\"";
name = "quote";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "l";
name = "location";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "b";
name = "bookmark";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "i";
name = "information";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "S";
name = "savings";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "I";
name = "idea";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "p";
name = "pros";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "c";
name = "cons";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "f";
name = "fire";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "k";
name = "key";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "w";
name = "win";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "u";
name = "up";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "d";
name = "down";
nextStatusSymbol = " ";
type = "TODO";
}
];
};
};
}
(pkgs.callPackage ./config/plugins/url-into-selection { })
];
cssSnippets = [ ./config/snippets/file-explorer-separators.css ];
themes = [ (pkgs.callPackage ./config/themes/minimal { }) ];
hotkeys = {
"command-palette:open" = [ { key = "F1"; } ];
"app:open-help" = [ ];
"editor:swap-line-down" = [
{
modifiers = [ "Alt" ];
key = "ArrowDown";
}
];
"editor:swap-line-up" = [
{
modifiers = [ "Alt" ];
key = "ArrowUp";
}
];
"editor:fold-all" = [
{
modifiers = [
"Alt"
"Mod"
];
key = "T";
}
];
"editor:add-cursor-above" = [
{
modifiers = [
"Mod"
"Shift"
];
key = "ArrowUp";
}
];
"editor:add-cursor-below" = [
{
modifiers = [
"Mod"
"Shift"
];
key = "ArrowDown";
}
];
"obsidian-outliner:move-list-item-up" = [ ];
"obsidian-outliner:move-list-item-down" = [ ];
};
};
};
theme.template = lib.attrsets.mapAttrs' (
_: vault:
lib.attrsets.nameValuePair
"${home}/${vault.target}/.obsidian/plugins/obsidian-style-settings/data.json"
{
source = ./theme.json;
}
) hmConfig.programs.obsidian.vaults;
sops.secrets."google/geocoding".sopsFile = ../../../../../../secrets/personal/secrets.yaml;
wayland.windowManager.hyprland.settings.bind = [ "$mod, o, exec, ${pkgs.obsidian}/bin/obsidian" ];
};
}

View File

@@ -0,0 +1,504 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.programs.obsidian;
corePlugins = [
"audio-recorder"
"backlink"
"bookmarks"
"canvas"
"command-palette"
"daily-notes"
"editor-status"
"file-explorer"
"file-recovery"
"global-search"
"graph"
"markdown-importer"
"note-composer"
"outgoing-link"
"outline"
"page-preview"
"properties"
"publish"
"random-note"
"slash-command"
"slides"
"switcher"
"sync"
"tag-pane"
"templates"
"word-count"
"workspaces"
"zk-prefixer"
];
toCssName = path: lib.strings.removeSuffix ".css" (builtins.baseNameOf path);
in
{
options.programs.obsidian =
with lib;
with types;
let
corePluginsOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to enable the plugin.";
};
name = mkOption {
type = enum corePlugins;
description = "The plugin.";
};
options = mkOption {
type = attrsOf anything;
description = "Plugin options to include.";
default = { };
};
};
};
communityPluginsOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to enable the plugin.";
};
pkg = mkOption {
type = package;
description = "The plugin package.";
};
options = mkOption {
type = attrsOf anything;
description = "Options to include in the plugin's `data.json`.";
default = { };
};
};
};
checkCssPath = path: lib.filesystem.pathIsRegularFile path && lib.strings.hasSuffix ".css" path;
cssSnippetsOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to enable the snippet.";
};
name = mkOption {
type = str;
defaultText = literalExpression "lib.strings.removeSuffix \".css\" (builtins.baseNameOf source)";
description = "Name of the snippet.";
};
source = mkOption {
type = nullOr (addCheck path checkCssPath);
description = "Path of the source file.";
default = null;
};
text = mkOption {
type = nullOr str;
description = "Text of the file.";
default = null;
};
};
config.name = mkDefault (toCssName config.source);
};
themesOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to set the theme as active.";
};
pkg = mkOption {
type = package;
description = "The theme package.";
};
};
};
hotkeysOptions =
{ config, ... }:
{
options = {
modifiers = mkOption {
type = listOf str;
description = "The hotkey modifiers.";
default = [ ];
};
key = mkOption {
type = str;
description = "The hotkey.";
};
};
};
extraFilesOptions =
{ name, config, ... }:
{
options = {
source = mkOption {
type = nullOr path;
description = "Path of the source file or directory.";
default = null;
};
text = mkOption {
type = nullOr str;
description = "Text of the file.";
default = null;
};
target = mkOption {
type = str;
defaultText = literalExpression "name";
description = "Path to target relative to the vault's directory.";
};
};
config.target = mkDefault name;
};
in
{
enable = mkEnableOption "obsidian";
package = mkPackageOption pkgs "obsidian" { };
sharedSettings = {
app = mkOption {
description = "Settings to write to app.json.";
type = raw;
default = { };
};
appearance = mkOption {
description = "Settings to write to appearance.json.";
type = raw;
default = { };
};
corePlugins = mkOption {
description = "Core plugins to activate.";
type = raw;
default = [
"backlink"
"bookmarks"
"canvas"
"command-palette"
"daily-notes"
"editor-status"
"file-explorer"
"file-recovery"
"global-search"
"graph"
"note-composer"
"outgoing-link"
"outline"
"page-preview"
"switcher"
"tag-pane"
"templates"
"word-count"
];
};
communityPlugins = mkOption {
description = "Community plugins to install and activate.";
type = raw;
default = [ ];
};
cssSnippets = mkOption {
description = "CSS snippets to install.";
type = raw;
default = [ ];
};
themes = mkOption {
description = "Themes to install.";
type = raw;
default = [ ];
};
hotkeys = mkOption {
description = "Hotkeys to configure.";
type = raw;
default = { };
};
extraFiles = mkOption {
description = "Extra files to link to the vault directory.";
type = raw;
default = { };
};
};
vaults = mkOption {
description = "List of vaults to create.";
type = attrsOf (
submodule (
{ name, config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether this vault should be generated.";
};
target = mkOption {
type = str;
defaultText = literalExpression "name";
description = "Path to target vault relative to the user's {env}`HOME`.";
};
settings = {
app = mkOption {
description = "Settings to write to app.json.";
type = attrsOf anything;
default = cfg.sharedSettings.app;
};
appearance = mkOption {
description = "Settings to write to appearance.json.";
type = attrsOf anything;
default = cfg.sharedSettings.appearance;
};
corePlugins = mkOption {
description = "Core plugins to activate.";
type = listOf (coercedTo (enum corePlugins) (p: { name = p; }) (submodule corePluginsOptions));
default = cfg.sharedSettings.corePlugins;
};
communityPlugins = mkOption {
description = "Community plugins to install and activate.";
type = listOf (coercedTo package (p: { pkg = p; }) (submodule communityPluginsOptions));
default = cfg.sharedSettings.communityPlugins;
};
cssSnippets = mkOption {
description = "CSS snippets to install.";
type = listOf (
coercedTo (addCheck path checkCssPath) (p: { source = p; }) (submodule cssSnippetsOptions)
);
default = cfg.sharedSettings.cssSnippets;
};
themes = mkOption {
description = "Themes to install.";
type = listOf (coercedTo package (p: { pkg = p; }) (submodule themesOptions));
default = cfg.sharedSettings.themes;
};
hotkeys = mkOption {
description = "Hotkeys to configure.";
type = attrsOf (listOf (submodule hotkeysOptions));
default = cfg.sharedSettings.hotkeys;
};
extraFiles = mkOption {
description = "Extra files to link to the vault directory.";
type = attrsOf (submodule extraFilesOptions);
default = cfg.sharedSettings.extraFiles;
};
};
};
config.target = mkDefault name;
}
)
);
default = { };
};
};
config =
let
vaults = builtins.filter (vault: vault.enable == true) (builtins.attrValues cfg.vaults);
getManifest =
item:
let
manifest = builtins.fromJSON (builtins.readFile "${item.pkg}/manifest.json");
in
manifest.id or manifest.name;
in
lib.mkIf cfg.enable {
home = {
packages = [ cfg.package ];
file =
let
mkApp = vault: {
name = "${vault.target}/.obsidian/app.json";
value.source = (pkgs.formats.json { }).generate "app.json" vault.settings.app;
};
mkAppearance = vault: {
name = "${vault.target}/.obsidian/appearance.json";
value =
let
enabledCssSnippets = builtins.filter (snippet: snippet.enable) vault.settings.cssSnippets;
activeTheme = lib.lists.findSingle (
theme: theme.enable
) null (throw "Only one theme can be enabled at a time.") vault.settings.themes;
in
{
source = (pkgs.formats.json { }).generate "appearance.json" (
vault.settings.appearance
// {
enabledCssSnippets = builtins.map (snippet: snippet.name) enabledCssSnippets;
}
// lib.attrsets.optionalAttrs (activeTheme != null) { cssTheme = getManifest activeTheme; }
);
};
};
mkCorePlugins =
vault:
[
{
name = "${vault.target}/.obsidian/core-plugins.json";
value.source = (pkgs.formats.json { }).generate "core-plugins.json" (
builtins.map (plugin: plugin.name) vault.settings.corePlugins
);
}
{
name = "${vault.target}/.obsidian/core-plugins-migration.json";
value.source = (pkgs.formats.json { }).generate "core-plugins-migration.json" (
builtins.listToAttrs (
builtins.map (name: {
inherit name;
value = builtins.any (plugin: name == plugin.name && plugin.enable) vault.settings.corePlugins;
}) corePlugins
)
);
}
]
++ builtins.map (plugin: {
name = "${vault.target}/.obsidian/${plugin.name}.json";
value.source = (pkgs.formats.json { }).generate "${plugin.name}.json" plugin.options;
}) (builtins.filter (plugin: plugin.options != { }) vault.settings.corePlugins);
mkCommunityPlugins =
vault:
[
{
name = "${vault.target}/.obsidian/community-plugins.json";
value.source = (pkgs.formats.json { }).generate "community-plugins.json" (
builtins.map getManifest (builtins.filter (plugin: plugin.enable) vault.settings.communityPlugins)
);
}
]
++ builtins.map (plugin: {
name = "${vault.target}/.obsidian/plugins/${getManifest plugin}";
value = {
source = plugin.pkg;
recursive = true;
};
}) vault.settings.communityPlugins
++ builtins.map (plugin: {
name = "${vault.target}/.obsidian/plugins/${getManifest plugin}/data.json";
value.source = (pkgs.formats.json { }).generate "data.json" plugin.options;
}) (builtins.filter (plugin: plugin.options != { }) vault.settings.communityPlugins);
mkCssSnippets =
vault:
builtins.map (snippet: {
name = "${vault.target}/.obsidian/snippets/${snippet.name}.css";
value =
if snippet.source != null then { inherit (snippet) source; } else { inherit (snippet) text; };
}) vault.settings.cssSnippets;
mkThemes =
vault:
builtins.map (theme: {
name = "${vault.target}/.obsidian/themes/${getManifest theme}";
value.source = theme.pkg;
}) vault.settings.themes;
mkHotkeys = vault: {
name = "${vault.target}/.obsidian/hotkeys.json";
value.source = (pkgs.formats.json { }).generate "hotkeys.json" vault.settings.hotkeys;
};
mkExtraFiles =
vault:
builtins.map (file: {
name = "${vault.target}/.obsidian/${file.target}";
value = if file.source != null then { inherit (file) source; } else { inherit (file) text; };
}) (builtins.attrValues vault.settings.extraFiles);
in
builtins.listToAttrs (
lib.lists.flatten (
builtins.map (vault: [
(mkApp vault)
(mkAppearance vault)
(mkCorePlugins vault)
(mkCommunityPlugins vault)
(mkCssSnippets vault)
(mkThemes vault)
(mkHotkeys vault)
(mkExtraFiles vault)
]) vaults
)
);
};
xdg.configFile."obsidian/obsidian.json".source = (pkgs.formats.json { }).generate "obsidian.json" {
vaults = builtins.listToAttrs (
builtins.map (vault: {
name = builtins.hashString "md5" vault.target;
value = {
path = "${config.home.homeDirectory}/${vault.target}";
} // (lib.attrsets.optionalAttrs ((builtins.length vaults) == 1) { open = true; });
}) vaults
);
updateDisabled = true;
};
assertions = [
{
assertion = builtins.all (
vault:
builtins.all (snippet: snippet.source == null || snippet.text == null) vault.settings.cssSnippets
) (builtins.attrValues cfg.vaults);
message = "Only one of `source` and `text` must be set";
}
{
assertion = builtins.all (
vault:
builtins.all (file: file.source == null || file.text == null) (
builtins.attrValues vault.settings.extraFiles
)
) (builtins.attrValues cfg.vaults);
message = "Only one of `source` and `text` must be set";
}
];
};
}

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