commit 0a24ffcef1b881dd549554fb0fe7bb26b9182ee6 Author: Alex Selimov Date: Thu Aug 27 23:56:32 2026 -0400 Current working changes to configuration diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..1267bc2 --- /dev/null +++ b/configuration.nix @@ -0,0 +1,200 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ config, pkgs, ... }: +#let +# sops-nix = builtins.fetchTarball { +# # Pin this to a real commit rather than master. +# url = "https://github.com/Mic92/sops-nix/archive/.tar.gz"; +# sha256 = ""; +# }; +#in +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + + #"${sops-nix}/modules/sops" + ]; + + # Bootloader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Use latest kernel. + boot.kernelPackages = pkgs.linuxPackages_latest; + + networking.hostName = "nixos"; # Define your hostname. + networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Enable networking + networking.networkmanager.enable = true; + + # Set your time zone. + time.timeZone = "America/New_York"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + + i18n.extraLocaleSettings = { + LC_ADDRESS = "en_US.UTF-8"; + LC_IDENTIFICATION = "en_US.UTF-8"; + LC_MEASUREMENT = "en_US.UTF-8"; + LC_MONETARY = "en_US.UTF-8"; + LC_NAME = "en_US.UTF-8"; + LC_NUMERIC = "en_US.UTF-8"; + LC_PAPER = "en_US.UTF-8"; + LC_TELEPHONE = "en_US.UTF-8"; + LC_TIME = "en_US.UTF-8"; + }; + + # Configure keymap in X11 + services.xserver.xkb = { + layout = "us"; + variant = ""; + }; + + # Define a user account. Don't forget to set a password with ‘passwd’. + users.users."aselimov" = { + isNormalUser = true; + description = "Alex Selimov"; + extraGroups = [ "networkmanager" "wheel" "input" "uinput" ]; + packages = with pkgs; []; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKhECKhmRPyFn63AXALvKEaRtvPQn6lWbA8p7jaymwSj alex@alexselimov.xyz" + ]; + }; + + # Allow unfree packages + nixpkgs.config.allowUnfree = true; + + # List packages installed in system profile. To search, run: + # $ nix search wget + environment.systemPackages = with pkgs; [ + htop + killall + pinentry-gnome3 + ]; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + # programs.gnupg.agent = { + # enable = true; + # enableSSHSupport = true; + # }; + programs.niri.enable=true; + + services.displayManager.regreet = { + enable = true; + cageArgs = [ + "-s" + "-d" + "-m" + "last" + ]; + + settings = { + appearance = { + greeting_msg = "Welcome back!"; + }; + + widget.clock = { + format = "%a %H:%M"; + }; + }; + }; + programs.git.enable=true; + + services.keyd = { + enable = true; + keyboards = { + laptop = { + ids = [ "0001:0001"]; + + settings = { + main = { + leftalt = "leftmeta"; + leftmeta = "leftalt"; + }; + }; + }; + }; + }; + + programs.zsh.enable = true; + users.users = { + aselimov.shell = pkgs.zsh; + root.shell = pkgs.zsh; + }; + + # Changes needed to get unfied super+c copy + hardware.uinput.enable = true; + boot.kernelModules = [ + "uinput" + ]; + + services.udev.extraRules = '' + KERNEL=="uinput", GROUP="input", MODE:="0660", TAG+="uaccess", OPTIONS+="static_node=uinput" + ''; + + virtualisation.podman = { + enable = true; + dockerSocket.enable=true; + dockerCompat = true; + defaultNetwork.settings.dns_enabled = true; + }; + + # Set up doas + + security.sudo.enable = false; + security.doas = { + enable = true; + extraRules = [ + { + users = [ "aselimov" ]; + keepEnv = true; + persist = true; + } + ]; + }; + + security.sudo-rs.execWheelOnly = false; + + # List services that you want to enable: + + # Enable the OpenSSH daemon. + services.openssh.enable = true; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "26.05"; # Did you read the comment? + + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + + home-manager.users.aselimov = import ./home/aselimov/home.nix; + home-manager.users.root = import ./home/root/home.nix; + + # Getting gsettings working properly for systemd service + environment.sessionVariables.XDG_DATA_DIRS = [ + "${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}" + "${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}" + "${pkgs.gtk4}/share/gsettings-schemas/${pkgs.gtk4.name}" + ]; +} diff --git a/hardware-configuration.nix b/hardware-configuration.nix new file mode 100644 index 0000000..0f79d3b --- /dev/null +++ b/hardware-configuration.nix @@ -0,0 +1,45 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/mapper/luks-45dfbed5-ac16-4529-b851-2aa9a358e0b8"; + fsType = "btrfs"; + }; + + boot.initrd.luks.devices."luks-45dfbed5-ac16-4529-b851-2aa9a358e0b8".device = "/dev/disk/by-uuid/45dfbed5-ac16-4529-b851-2aa9a358e0b8"; + + fileSystems."/home" = + { device = "/dev/mapper/luks-45dfbed5-ac16-4529-b851-2aa9a358e0b8"; + fsType = "btrfs"; + options = [ "subvol=home" ]; + }; + + fileSystems."/nix" = + { device = "/dev/mapper/luks-45dfbed5-ac16-4529-b851-2aa9a358e0b8"; + fsType = "btrfs"; + options = [ "subvol=nix" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/9364-7648"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/home/aselimov/firefox/firefox.nix b/home/aselimov/firefox/firefox.nix new file mode 100644 index 0000000..5096d46 --- /dev/null +++ b/home/aselimov/firefox/firefox.nix @@ -0,0 +1,21 @@ +{config, pkgs, ... }: +{ + programs.firefox = { + enable = true; + + profiles.default = { + id = 0; + isDefault = true; + preConfig = builtins.readFile ./user.js; + + settings = { + "browser.startup.page" = 3; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + "sidebar.verticalTabs" = true; + "sidebar.revamp" = true; + }; + + userChrome = builtins.readFile ./userChrome.css; + }; + }; +} diff --git a/home/aselimov/firefox/user.js b/home/aselimov/firefox/user.js new file mode 100644 index 0000000..1e3ffb5 --- /dev/null +++ b/home/aselimov/firefox/user.js @@ -0,0 +1,1319 @@ +/****** +* name: arkenfox user.js +* date: 21 April 2026 +* version: 144 +* urls: https://github.com/arkenfox/user.js [repo] +* : https://arkenfox.github.io/gui/ [interactive] +* license: MIT: https://github.com/arkenfox/user.js/blob/master/LICENSE.txt + +* README: + + 1. Consider using Tor Browser if it meets your needs or fits your threat model + * https://2019.www.torproject.org/about/torusers.html + 2. Read the entire wiki + * https://github.com/arkenfox/user.js/wiki + 3. If you skipped step 2, return to step 2 + 4. Make changes in a user-overrides.js + * There are often trade-offs and conflicts between security vs privacy vs anti-tracking + and these need to be balanced against functionality & convenience & breakage + * Some site breakage and unintended consequences will happen. Everyone's experience will differ + e.g. some user data is erased on exit (section 2800), change this to suit your needs + * While not 100% definitive, search for "[SETUP" tags + 5. Some tag info + [SETUP-SECURITY] it's one item, read it + [SETUP-WEB] can cause some websites to break + [SETUP-CHROME] changes how Firefox itself behaves (i.e. not directly website related) + [SETUP-HARDEN] prefs you may like to add to overrides + 6. Override Recipes: https://github.com/arkenfox/user.js/issues/1080 + +* RELEASES: https://github.com/arkenfox/user.js/releases + + * Use the arkenfox release that matches your Firefox version + - DON'T wait for arkenfox to update Firefox, nothing major changes these days + * Each release + - run prefsCleaner to reset prefs made inactive, including deprecated (9999) + * ESR (Extended Support Release) + - It is recommended to not use the updater, or you will get a later version which may cause issues. + So you should manually append your overrides (and keep a copy), and manually update when you + change ESR releases (arkenfox is already past that release) + - If you decide to keep updating, then the onus is on you - also see section 9999 + +* INDEX: + + 0100: STARTUP + 0200: GEOLOCATION + 0300: QUIETER FOX + 0400: SAFE BROWSING + 0600: BLOCK IMPLICIT OUTBOUND + 0700: DNS / DoH / PROXY / SOCKS + 0800: LOCATION BAR / SEARCH BAR / SUGGESTIONS / HISTORY / FORMS + 0900: PASSWORDS / PASSKEYS + 1000: DISK AVOIDANCE + 1200: HTTPS (SSL/TLS / OCSP / CERTS / HPKP) + 1600: REFERERS + 1700: CONTAINERS + 2000: PLUGINS / MEDIA / WEBRTC + 2400: DOM (DOCUMENT OBJECT MODEL) + 2600: MISCELLANEOUS + 2700: ETP (ENHANCED TRACKING PROTECTION) + 2800: SHUTDOWN & SANITIZING + 4000: FPP (fingerprintingProtection) + 4500: OPTIONAL RFP (resistFingerprinting) + 5000: OPTIONAL OPSEC + 5500: OPTIONAL HARDENING + 6000: DON'T TOUCH + 7000: DON'T BOTHER + 8000: DON'T BOTHER: FINGERPRINTING + 8500: TELEMETRY + 9000: NON-PROJECT RELATED + 9999: DEPRECATED / RENAMED + +******/ + +/* START: internal custom pref to test for syntax errors + * [NOTE] Not all syntax errors cause parsing to abort i.e. reaching the last debug pref + * no longer necessarily means that all prefs have been applied. Check the console right + * after startup for any warnings/error messages related to non-applied prefs + * [1] https://blog.mozilla.org/nnethercote/2018/03/09/a-new-preferences-parser-for-firefox/ ***/ +user_pref( + "_user.js.parrot", + "START: Oh yes, the Norwegian Blue... what's wrong with it?", +); + +/* 0000: disable about:config warning ***/ +user_pref("browser.aboutConfig.showWarning", false); + +/*** [SECTION 0100]: STARTUP ***/ +user_pref("_user.js.parrot", "0100 syntax error: the parrot's dead!"); +/* 0102: set startup page [SETUP-CHROME] + * 0=blank, 1=home, 2=last visited page, 3=resume previous session + * [NOTE] Session Restore is cleared if history is also cleared (2811+), and not used in Private Browsing mode + * [SETTING] General>Startup>Restore previous session ***/ +user_pref("browser.startup.page", 0); +/* 0103: set HOME+NEWWINDOW page + * about:home=Firefox Home (default, see 0105), custom URLs..., Blank Page + * [SETTING] Home>New Windows and Tabs>Homepage and new windows ***/ +user_pref("browser.startup.homepage", "chrome://browser/content/blanktab.html"); +/* 0104: set NEWTAB page + * true=Firefox Home (default, see 0105), false=blank page + * [SETTING] Home>New Windows and Tabs>New tabs ***/ +user_pref("browser.newtabpage.enabled", false); +/* 0105: disable sponsored content on Firefox Home (Activity Stream) + * [SETTING] Home>Firefox Home Content ***/ +user_pref("browser.newtabpage.activity-stream.showSponsored", false); // [FF58+] Sponsored stories +user_pref("browser.newtabpage.activity-stream.showSponsoredTopSites", false); // [FF83+] Sponsored shortcuts +user_pref("browser.newtabpage.activity-stream.showSponsoredCheckboxes", false); // [FF140+] Support Firefox +/* 0106: clear default topsites + * [NOTE] This does not block you from adding your own ***/ +user_pref("browser.newtabpage.activity-stream.default.sites", ""); + +/*** [SECTION 0200]: GEOLOCATION ***/ +user_pref( + "_user.js.parrot", + "0200 syntax error: the parrot's definitely deceased!", +); +/* 0202: disable using the OS's geolocation service ***/ +user_pref("geo.provider.ms-windows-location", false); // [WINDOWS] +user_pref("geo.provider.use_corelocation", false); // [MAC] +user_pref("geo.provider.use_geoclue", false); // [FF102+] [LINUX] + +/*** [SECTION 0300]: QUIETER FOX ***/ +user_pref( + "_user.js.parrot", + "0300 syntax error: the parrot's not pinin' for the fjords!", +); +/** RECOMMENDATIONS ***/ +/* 0320: disable recommendation pane in about:addons (uses Google Analytics) ***/ +user_pref("extensions.getAddons.showPane", false); // [HIDDEN PREF] +/* 0321: disable recommendations in about:addons' Extensions and Themes panes [FF68+] ***/ +user_pref("extensions.htmlaboutaddons.recommendations.enabled", false); +/* 0322: disable personalized Extension Recommendations in about:addons and AMO [FF65+] + * [NOTE] This pref has no effect when Health Reports (8501) are disabled + * [SETTING] Privacy & Security>Firefox Data Collection and Use>Allow personalized extension recommendations + * [1] https://support.mozilla.org/kb/personalized-extension-recommendations ***/ +user_pref("browser.discovery.enabled", false); + +/** ACTIVITY STREAM ***/ +/* 0335: disable Firefox Home (Activity Stream) telemetry ***/ +user_pref("browser.newtabpage.activity-stream.feeds.telemetry", false); +user_pref("browser.newtabpage.activity-stream.telemetry", false); + +/** STUDIES ***/ +/* 0340: disable Studies + * [SETTING] Privacy & Security>Firefox Data Collection and Use>Install and run studies ***/ +user_pref("app.shield.optoutstudies.enabled", false); +/* 0341: disable Normandy/Shield [FF60+] + * Shield is a telemetry system that can push and test "recipes" + * [1] https://mozilla.github.io/normandy/ ***/ +user_pref("app.normandy.enabled", false); +user_pref("app.normandy.api_url", ""); + +/** CRASH REPORTS ***/ +/* 0350: disable Crash Reports ***/ +user_pref("breakpad.reportURL", ""); +user_pref("browser.tabs.crashReporting.sendReport", false); // [FF44+] +// user_pref("browser.crashReports.unsubmittedCheck.enabled", false); // [FF51+] [DEFAULT: false] +/* 0351: enforce no submission of backlogged Crash Reports [FF58+] + * [SETTING] Privacy & Security>Firefox Data Collection and Use>Send backlogged crash reports ***/ +user_pref("browser.crashReports.unsubmittedCheck.autoSubmit2", false); // [DEFAULT: false] + +/** OTHER ***/ +/* 0360: disable Captive Portal detection + * [1] https://www.eff.org/deeplinks/2017/08/how-captive-portals-interfere-wireless-security-and-privacy ***/ +user_pref("captivedetect.canonicalURL", ""); +user_pref("network.captive-portal-service.enabled", false); // [FF52+] +/* 0361: disable Network Connectivity checks [FF65+] + * [1] https://bugzilla.mozilla.org/1460537 ***/ +user_pref("network.connectivity-service.enabled", false); + +/*** [SECTION 0400]: SAFE BROWSING (SB) + SB has taken many steps to preserve privacy. If required, a full url is never sent + to Google, only a part-hash of the prefix, hidden with noise of other real part-hashes. + Firefox takes measures such as stripping out identifying parameters and since SBv4 (FF57+) + doesn't even use cookies. (#Turn on browser.safebrowsing.debug to monitor this activity). + + FF147+ uses SBv5 which incorporates Oblivous HTTP [5] and SBv5's local list mode [6] + + [1] https://feeding.cloud.geek.nz/posts/how-safe-browsing-works-in-firefox/ + [2] https://wiki.mozilla.org/Security/Safe_Browsing + [3] https://support.mozilla.org/kb/how-does-phishing-and-malware-protection-work + [4] https://educatedguesswork.org/posts/safe-browsing-privacy/ + [5] https://developers.google.com/safe-browsing/reference + [6] https://developers.google.com/safe-browsing/reference/Local.List.Mode +***/ +user_pref("_user.js.parrot", "0400 syntax error: the parrot's passed on!"); +/* 0401: disable SB (Safe Browsing) + * [WARNING] Do this at your own risk! These are the master switches + * [SETTING] Privacy & Security>Security>... Block dangerous and deceptive content ***/ +// user_pref("browser.safebrowsing.malware.enabled", false); +// user_pref("browser.safebrowsing.phishing.enabled", false); +/* 0402: disable SB checks for downloads (both local lookups + remote) + * This is the master switch for the safebrowsing.downloads* prefs (0403, 0404) + * [SETTING] Privacy & Security>Security>... "Block dangerous downloads" ***/ +// user_pref("browser.safebrowsing.downloads.enabled", false); +/* 0403: disable SB checks for downloads (remote) + * To verify the safety of certain executable files, Firefox may submit some information about the + * file, including the name, origin, size and a cryptographic hash of the contents, to the Google + * Safe Browsing service which helps Firefox determine whether or not the file should be blocked + * [SETUP-SECURITY] If you do not understand this, or you want this protection, then override this ***/ +user_pref("browser.safebrowsing.downloads.remote.enabled", false); +// user_pref("browser.safebrowsing.downloads.remote.url", ""); // Defense-in-depth +/* 0404: disable SB checks for unwanted software + * [SETTING] Privacy & Security>Security>... "Warn you about unwanted and uncommon software" ***/ +// user_pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false); +// user_pref("browser.safebrowsing.downloads.remote.block_uncommon", false); +/* 0405: disable "ignore this warning" on SB warnings [FF45+] + * If clicked, it bypasses the block for that session. This is a means for admins to enforce SB + * [TEST] see https://github.com/arkenfox/user.js/wiki/Appendix-A-Test-Sites#-mozilla + * [1] https://bugzilla.mozilla.org/1226490 ***/ +// user_pref("browser.safebrowsing.allowOverride", false); + +/*** [SECTION 0600]: BLOCK IMPLICIT OUTBOUND [not explicitly asked for - e.g. clicked on] ***/ +user_pref("_user.js.parrot", "0600 syntax error: the parrot's no more!"); +/* 0601: disable link prefetching + * [1] https://developer.mozilla.org/docs/Web/HTTP/Link_prefetching_FAQ ***/ +user_pref("network.prefetch-next", false); +/* 0602: disable DNS prefetching + * [1] https://developer.mozilla.org/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control ***/ +user_pref("network.dns.disablePrefetch", true); +user_pref("network.dns.disablePrefetchFromHTTPS", true); +/* 0604: disable link-mouseover opening connection to linked server + * [1] https://news.slashdot.org/story/15/08/14/2321202/how-to-quash-firefoxs-silent-requests ***/ +user_pref("network.http.speculative-parallel-limit", 0); +/* 0605: disable mousedown speculative connections on bookmarks and history [FF98+] ***/ +user_pref("browser.places.speculativeConnect.enabled", false); +/* 0610: enforce no "Hyperlink Auditing" (click tracking) + * [1] https://www.bleepingcomputer.com/news/software/major-browsers-to-prevent-disabling-of-click-tracking-privacy-risk/ ***/ +// user_pref("browser.send_pings", false); // [DEFAULT: false] + +/*** [SECTION 0700]: DNS / DoH / PROXY / SOCKS ***/ +user_pref( + "_user.js.parrot", + "0700 syntax error: the parrot's given up the ghost!", +); +/* 0702: set the proxy server to do any DNS lookups when using SOCKS + * e.g. in Tor, this stops your local DNS server from knowing your Tor destination + * as a remote Tor node will handle the DNS request + * [1] https://trac.torproject.org/projects/tor/wiki/doc/TorifyHOWTO/WebBrowsers ***/ +user_pref("network.proxy.socks_remote_dns", true); +/* 0703: disable using UNC (Uniform Naming Convention) paths [FF61+] + * [SETUP-CHROME] Can break extensions for profiles on network shares + * [1] https://bugzilla.mozilla.org/1413868 ***/ +user_pref("network.file.disable_unc_paths", true); // [HIDDEN PREF] +/* 0704: disable GIO as a potential proxy bypass vector + * Gvfs/GIO has a set of supported protocols like obex, network, archive, computer, + * dav, cdda, gphoto2, trash, etc. From FF87-117, by default only sftp was accepted + * [1] https://bugzilla.mozilla.org/1433507 + * [2] https://en.wikipedia.org/wiki/GVfs + * [3] https://en.wikipedia.org/wiki/GIO_(software) ***/ +user_pref("network.gio.supported-protocols", ""); // [HIDDEN PREF] [DEFAULT: ""] +/* 0705: disable proxy direct failover for system requests [FF91+] + * [WARNING] Default true is a security feature against malicious extensions [1] + * [SETUP-CHROME] If you use a proxy and you trust your extensions + * [1] https://blog.mozilla.org/security/2021/10/25/securing-the-proxy-api-for-firefox-add-ons/ ***/ +// user_pref("network.proxy.failover_direct", false); +/* 0706: disable proxy bypass for system request failures [FF95+] + * RemoteSettings, UpdateService, Telemetry [1] + * [WARNING] If false, this will break the fallback for some security features + * [SETUP-CHROME] If you use a proxy and you understand the security impact + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=1732792,1733994,1733481 ***/ +// user_pref("network.proxy.allow_bypass", false); +/* 0710: enable DNS-over-HTTPS (DoH) [FF60+] + * 0=default, 2=increased (TRR (Trusted Recursive Resolver) first), 3=max (TRR only), 5=off (no rollout) + * see "doh-rollout.home-region": USA 2019, Canada 2021, Russia/Ukraine 2022 [3] + * [SETTING] Privacy & Security>DNS over HTTPS + * [1] https://hacks.mozilla.org/2018/05/a-cartoon-intro-to-dns-over-https/ + * [2] https://wiki.mozilla.org/Security/DOH-resolver-policy + * [3] https://support.mozilla.org/kb/firefox-dns-over-https + * [4] https://www.eff.org/deeplinks/2020/12/dns-doh-and-odoh-oh-my-year-review-2020 ***/ +// user_pref("network.trr.mode", 3); +/* 0712: set DoH provider + * The custom uri is the value shown when you "Choose provider>Custom>" + * [NOTE] If you USE custom then "network.trr.uri" should be set the same + * [SETTING] Privacy & Security>DNS over HTTPS>Increased/Max>Choose provider ***/ +// user_pref("network.trr.uri", "https://example.dns"); +// user_pref("network.trr.custom_uri", "https://example.dns"); + +/*** [SECTION 0800]: LOCATION BAR / SEARCH BAR / SUGGESTIONS / HISTORY / FORMS ***/ +user_pref("_user.js.parrot", "0800 syntax error: the parrot's ceased to be!"); +/* 0801: disable location bar making speculative connections [FF56+] + * [1] https://bugzilla.mozilla.org/1348275 ***/ +user_pref("browser.urlbar.speculativeConnect.enabled", false); +/* 0802: disable location bar contextual suggestions + * [NOTE] The UI is controlled by the .enabled pref + * [SETTING] Search>Address Bar>Suggestions from... + * [1] https://blog.mozilla.org/data/2021/09/15/data-and-firefox-suggest/ ***/ +user_pref("browser.urlbar.quicksuggest.enabled", false); // [FF92+] +user_pref("browser.urlbar.suggest.quicksuggest.nonsponsored", false); // [FF95+] +user_pref("browser.urlbar.suggest.quicksuggest.sponsored", false); // [FF92+] +/* 0803: disable live search suggestions + * [NOTE] Both must be true for live search to work in the location bar + * [SETUP-CHROME] Override these if you trust and use a privacy respecting search engine + * [SETTING] Search>Show search suggestions | Show search suggestions in address bar results ***/ +user_pref("browser.search.suggest.enabled", false); +user_pref("browser.urlbar.suggest.searches", false); +/* 0805: disable urlbar trending search suggestions [FF118+] + * [SETTING] Search>Search Suggestions>Show trending search suggestions (FF119) ***/ +user_pref("browser.urlbar.trending.featureGate", false); +/* 0806: disable urlbar suggestions ***/ +user_pref("browser.urlbar.addons.featureGate", false); // [FF115+] +user_pref("browser.urlbar.amp.featureGate", false); // [FF141+] adMarketplace +user_pref("browser.urlbar.importantDates.featureGate", false); // [FF143+] +user_pref("browser.urlbar.market.featureGate", false); // [FF143+] stock market +user_pref("browser.urlbar.mdn.featureGate", false); // [FF117+] +user_pref("browser.urlbar.weather.featureGate", false); // [FF108+] +user_pref("browser.urlbar.wikipedia.featureGate", false); // [FF141+] +user_pref("browser.urlbar.yelp.featureGate", false); // [FF124+] +user_pref("browser.urlbar.yelpRealtime.featureGate", false); // [FF144+] +/* 0807: disable urlbar clipboard suggestions [FF118+] ***/ +// user_pref("browser.urlbar.clipboard.featureGate", false); +/* 0808: disable recent searches [FF120+] + * [NOTE] Recent searches are cleared if history is cleared (2811+) + * [1] https://support.mozilla.org/kb/search-suggestions-firefox ***/ +// user_pref("browser.urlbar.recentsearches.featureGate", false); +/* 0810: disable search and form history + * [NOTE] We also clear formdata on exit (2811+) + * [SETUP-WEB] Be aware that autocomplete form data can be read by third parties [1][2] + * [SETTING] Privacy & Security>History>Custom Settings>Remember search and form history + * [1] https://blog.mindedsecurity.com/2011/10/autocompleteagain.html + * [2] https://bugzilla.mozilla.org/381681 ***/ +user_pref("browser.formfill.enable", false); +/* 0815: disable tab-to-search [FF85+] + * Alternatively, you can exclude on a per-engine basis by unchecking them in Options>Search + * [SETTING] Search>Address Bar>When using the address bar, suggest>Search engines ***/ +// user_pref("browser.urlbar.suggest.engines", false); +/* 0820: disable coloring of visited links + * [SETUP-HARDEN] Bulk rapid history sniffing was mitigated in 2010 [1][2]. Slower and more expensive + * redraw timing attacks were largely mitigated in FF77+ [3]. Using RFP (4501) further hampers timing + * attacks. History can also be cleared on exit (2811+). However, social engineering [2#limits][4][5] + * and advanced targeted timing attacks could still produce usable results + * [1] https://developer.mozilla.org/docs/Web/CSS/Privacy_and_the_:visited_selector + * [2] https://dbaron.org/mozilla/visited-privacy + * [3] https://bugzilla.mozilla.org/1632765 + * [4] https://earthlng.github.io/testpages/visited_links.html (see github wiki APPENDIX A on how to use) + * [5] https://lcamtuf.blogspot.com/2016/08/css-mix-blend-mode-is-bad-for-keeping.html ***/ +// user_pref("layout.css.visited_links_enabled", false); +/* 0830: enable separate default search engine in Private Windows and its UI setting + * [SETTING] Search>Default Search Engine>Choose a different default search engine for Private Windows only ***/ +user_pref("browser.search.separatePrivateDefault", true); // [FF70+] +user_pref("browser.search.separatePrivateDefault.ui.enabled", true); // [FF71+] + +/*** [SECTION 0900]: PASSWORDS / PASSKEYS + [1] https://support.mozilla.org/kb/use-primary-password-protect-stored-logins-and-pas +***/ +user_pref("_user.js.parrot", "0900 syntax error: the parrot's expired!"); +/* 0903: disable auto-filling username & password form fields + * can leak in cross-site forms *and* be spoofed + * [NOTE] Username & password is still available when you enter the field + * [SETTING] Privacy & Security>Passwords>Autofill logins and passwords + * [1] https://freedom-to-tinker.com/2017/12/27/no-boundaries-for-user-identities-web-trackers-exploit-browser-login-managers/ + * [2] https://homes.esat.kuleuven.be/~asenol/leaky-forms/ ***/ +user_pref("signon.autofillForms", false); +/* 0904: disable formless login capture for Password Manager [FF51+] ***/ +user_pref("signon.formlessCapture.enabled", false); +/* 0905: limit (or disable) HTTP authentication credentials dialogs triggered by sub-resources [FF41+] + * hardens against potential credentials phishing + * 0 = don't allow sub-resources to open HTTP authentication credentials dialogs + * 1 = don't allow cross-origin sub-resources to open HTTP authentication credentials dialogs + * 2 = allow sub-resources to open HTTP authentication credentials dialogs (default) ***/ +user_pref("network.auth.subresource-http-auth-allow", 1); +/* 0906: enforce no automatic authentication on Microsoft sites [FF91+] [WINDOWS 10+] + * [SETTING] Privacy & Security>Logins and Passwords>Allow Windows single sign-on for... + * [1] https://support.mozilla.org/kb/windows-sso ***/ +// user_pref("network.http.windows-sso.enabled", false); // [DEFAULT: false] +/* 0907: enforce no automatic authentication on Microsoft sites [FF131+] [MAC] + * On macOS, SSO only works on corporate devices ***/ +// user_pref("network.http.microsoft-entra-sso.enabled", false); // [DEFAULT: false] +/* 0910: enforce no direct attestation in passkeys [FF144+] + // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1981587 ***/ +user_pref("security.webauthn.always_allow_direct_attestation", false); // [DEFAULT: false] + +/*** [SECTION 1000]: DISK AVOIDANCE ***/ +user_pref( + "_user.js.parrot", + "1000 syntax error: the parrot's gone to meet 'is maker!", +); +/* 1001: disable disk cache + * [NOTE] We also clear cache on exit (2811+) + * [SETUP-CHROME] If you think disk cache helps perf, then feel free to override this ***/ +user_pref("browser.cache.disk.enable", false); +/* 1002: set media cache in Private Browsing to in-memory and increase its maximum size + * [NOTE] MSE (Media Source Extensions) are already stored in-memory in PB ***/ +user_pref("browser.privatebrowsing.forceMediaMemoryCache", true); // [FF75+] +user_pref("media.memory_cache_max_size", 65536); +/* 1003: disable storing extra session data [SETUP-CHROME] + * define on which sites to save extra session data such as form content, cookies and POST data + * 0=everywhere, 1=unencrypted sites, 2=nowhere ***/ +user_pref("browser.sessionstore.privacy_level", 2); +/* 1005: disable automatic Firefox start and session restore after reboot [FF62+] [WINDOWS] + * [1] https://bugzilla.mozilla.org/603903 ***/ +user_pref("toolkit.winRegisterApplicationRestart", false); +/* 1006: disable favicons in shortcuts [WINDOWS] + * URL shortcuts use a cached randomly named .ico file which is stored in your + * profile/shortcutCache directory. The .ico remains after the shortcut is deleted + * If set to false then the shortcuts use a generic Firefox icon ***/ +user_pref("browser.shell.shortcutFavicons", false); + +/*** [SECTION 1200]: HTTPS (SSL/TLS / OCSP / CERTS / HPKP) + Your cipher and other settings can be used in server side fingerprinting + [TEST] https://www.ssllabs.com/ssltest/viewMyClient.html + [TEST] https://browserleaks.com/ssl + [TEST] https://ja3er.com/ + [1] https://www.securityartwork.es/2017/02/02/tls-client-fingerprinting-with-bro/ +***/ +user_pref("_user.js.parrot", "1200 syntax error: the parrot's a stiff!"); +/** SSL (Secure Sockets Layer) / TLS (Transport Layer Security) ***/ +/* 1201: require safe negotiation + * Blocks connections to servers that don't support RFC 5746 [2] as they're potentially vulnerable to a + * MiTM attack [3]. A server without RFC 5746 can be safe from the attack if it disables renegotiations + * but the problem is that the browser can't know that. Setting this pref to true is the only way for the + * browser to ensure there will be no unsafe renegotiations on the channel between the browser and the server + * [SETUP-WEB] SSL_ERROR_UNSAFE_NEGOTIATION: is it worth overriding this for that one site? + * [STATS] SSL Labs (Nov 2025) reports almost 99.85% of top sites have secure renegotiation [4] + * [1] https://wiki.mozilla.org/Security:Renegotiation + * [2] https://datatracker.ietf.org/doc/html/rfc5746 + * [3] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555 + * [4] https://www.ssllabs.com/ssl-pulse/ ***/ +user_pref("security.ssl.require_safe_negotiation", true); +/* 1206: disable TLS1.3 0-RTT (round-trip time) [FF51+] + * This data is not forward secret, as it is encrypted solely under keys derived using + * the offered PSK. There are no guarantees of non-replay between connections + * [1] https://github.com/tlswg/tls13-spec/issues/1001 + * [2] https://www.rfc-editor.org/rfc/rfc9001.html#name-replay-attacks-with-0-rtt + * [3] https://blog.cloudflare.com/tls-1-3-overview-and-q-and-a/ ***/ +user_pref("security.tls.enable_0rtt_data", false); + +/** CERTS / HPKP (HTTP Public Key Pinning) ***/ +/* 1223: enable strict PKP (Public Key Pinning) + * 0=disabled, 1=allow user MiTM (default; such as your antivirus), 2=strict + * [SETUP-WEB] MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE ***/ +user_pref("security.cert_pinning.enforcement_level", 2); +/* 1224: enable CRLite [FF73+] + * 0 = disabled + * 1 = consult CRLite but only collect telemetry + * 2 = consult CRLite and enforce both "Revoked" and "Not Revoked" results (default) + * 3 = consult CRLite and enforce "Not Revoked" results, but defer to OCSP for "Revoked" (removed FF145) + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=1429800,1670985,1753071 + * [2] https://blog.mozilla.org/security/tag/crlite/ + * [3] https://hacks.mozilla.org/2025/08/crlite-fast-private-and-comprehensive-certificate-revocation-checking-in-firefox/ ***/ +user_pref("security.remote_settings.crlite_filters.enabled", true); // [DEFAULT: true] +user_pref("security.pki.crlite_mode", 2); // [DEFAULT: 2 FF142+] + +/** MIXED CONTENT ***/ +/* 1241: disable insecure passive content (such as images) on https pages ***/ +// user_pref("security.mixed_content.block_display_content", true); // Defense-in-depth (see 1244) +/* 1244: enable HTTPS-Only mode in all windows + * When the top-level is HTTPS, insecure subresources are also upgraded (silent fail) + * [SETTING] to add site exceptions: Padlock>HTTPS-Only mode>On (after "Continue to HTTP Site") + * [SETTING] Privacy & Security>HTTPS-Only Mode (and manage exceptions) + * [TEST] http://example.com [upgrade] + * [TEST] http://httpforever.com/ | http://http.rip [no upgrade] ***/ +user_pref("dom.security.https_only_mode", true); // [FF76+] +// user_pref("dom.security.https_only_mode_pbm", true); // [FF80+] +/* 1245: enable HTTPS-Only mode for local resources [FF77+] ***/ +// user_pref("dom.security.https_only_mode.upgrade_local", true); +/* 1246: disable HTTP background requests [FF82+] + * When attempting to upgrade, if the server doesn't respond within 3 seconds, Firefox sends + * a top-level HTTP request without path in order to check if the server supports HTTPS or not + * This is done to avoid waiting for a timeout which takes 90 seconds + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=1642387,1660945 ***/ +user_pref("dom.security.https_only_mode_send_http_background_request", false); + +/** UI (User Interface) ***/ +/* 1270: display warning on the padlock for "broken security" (if 1201 is false) + * Bug: warning padlock not indicated for subresources on a secure page! [2] + * [1] https://wiki.mozilla.org/Security:Renegotiation + * [2] https://bugzilla.mozilla.org/1353705 ***/ +user_pref("security.ssl.treat_unsafe_negotiation_as_broken", true); +/* 1272: display advanced information on Insecure Connection warning pages + * only works when it's possible to add an exception + * i.e. it doesn't work for HSTS discrepancies (https://subdomain.preloaded-hsts.badssl.com/) + * [TEST] https://expired.badssl.com/ ***/ +user_pref("browser.xul.error_pages.expert_bad_cert", true); + +/*** [SECTION 1600]: REFERERS + full URI: https://example.com:8888/foo/bar.html?id=1234 + scheme+host+port+path: https://example.com:8888/foo/bar.html + scheme+host+port: https://example.com:8888 + [1] https://feeding.cloud.geek.nz/posts/tweaking-referrer-for-privacy-in-firefox/ +***/ +user_pref("_user.js.parrot", "1600 syntax error: the parrot rests in peace!"); +/* 1602: control the amount of cross-origin information to send [FF52+] + * 0=send full URI (default), 1=scheme+host+port+path, 2=scheme+host+port ***/ +user_pref("network.http.referer.XOriginTrimmingPolicy", 2); + +/*** [SECTION 1700]: CONTAINERS ***/ +user_pref("_user.js.parrot", "1700 syntax error: the parrot's bit the dust!"); +/* 1701: enable Container Tabs and its UI setting [FF50+] + * [SETTING] General>Tabs>Enable Container Tabs + * https://wiki.mozilla.org/Security/Contextual_Identity_Project/Containers ***/ +user_pref("privacy.userContext.enabled", true); +user_pref("privacy.userContext.ui.enabled", true); +/* 1702: set behavior on "+ Tab" button to display container menu on left click [FF74+] + * [NOTE] The menu is always shown on long press and right click + * [SETTING] General>Tabs>Enable Container Tabs>Settings>Select a container for each new tab ***/ +// user_pref("privacy.userContext.newTabContainerOnLeftClick.enabled", true); +/* 1703: set external links to open in site-specific containers [FF123+] + * [SETUP-WEB] Depending on your container extension(s) and their settings + * true=Firefox will not choose a container (so your extension can) + * false=Firefox will choose the container/no-container (default) + * [1] https://bugzilla.mozilla.org/1874599 ***/ +// user_pref("browser.link.force_default_user_context_id_for_external_opens", true); + +/*** [SECTION 2000]: PLUGINS / MEDIA / WEBRTC ***/ +user_pref("_user.js.parrot", "2000 syntax error: the parrot's snuffed it!"); +/* 2002: force WebRTC inside the proxy [FF70+] ***/ +user_pref("media.peerconnection.ice.proxy_only_if_behind_proxy", true); +/* 2003: force a single network interface for ICE candidates generation [FF42+] + * When using a system-wide proxy, it uses the proxy interface + * [1] https://developer.mozilla.org/docs/Web/API/RTCIceCandidate + * [2] https://wiki.mozilla.org/Media/WebRTC/Privacy ***/ +user_pref("media.peerconnection.ice.default_address_only", true); +/* 2004: force exclusion of private IPs from ICE candidates [FF51+] + * [SETUP-HARDEN] This will protect your private IP even in TRUSTED scenarios after you + * grant device access, but often results in breakage on video-conferencing platforms ***/ +// user_pref("media.peerconnection.ice.no_host", true); +/* 2020: disable GMP (Gecko Media Plugins) + * [1] https://wiki.mozilla.org/GeckoMediaPlugins ***/ +// user_pref("media.gmp-provider.enabled", false); + +/*** [SECTION 2400]: DOM (DOCUMENT OBJECT MODEL) ***/ +user_pref( + "_user.js.parrot", + "2400 syntax error: the parrot's kicked the bucket!", +); +/* 2402: prevent scripts from moving and resizing open windows ***/ +user_pref("dom.disable_window_move_resize", true); + +/*** [SECTION 2600]: MISCELLANEOUS ***/ +user_pref( + "_user.js.parrot", + "2600 syntax error: the parrot's run down the curtain!", +); +/* 2603: remove temp files opened from non-PB windows with an external application + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=302433,1738574 ***/ +user_pref("browser.download.start_downloads_in_tmp_dir", true); // [FF102+] +user_pref("browser.helperApps.deleteTempFileOnExit", true); +/* 2606: disable UITour backend so there is no chance that a remote page can use it ***/ +user_pref("browser.uitour.enabled", false); +// user_pref("browser.uitour.url", ""); // Defense-in-depth +/* 2608: reset remote debugging to disabled + * [1] https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/16222 ***/ +user_pref("devtools.debugger.remote-enabled", false); // [DEFAULT: false] +/* 2615: disable websites overriding Firefox's keyboard shortcuts [FF58+] + * 0 (default) or 1=allow, 2=block + * [SETTING] to add site exceptions: Ctrl+I>Permissions>Override Keyboard Shortcuts ***/ +// user_pref("permissions.default.shortcuts", 2); +/* 2616: remove special permissions for certain mozilla domains [FF35+] + * [1] resource://app/defaults/permissions ***/ +user_pref("permissions.manager.defaultsUrl", ""); +/* 2619: use Punycode in Internationalized Domain Names to eliminate possible spoofing + * [SETUP-WEB] Might be undesirable for non-latin alphabet users since legitimate IDN's are also punycoded + * [TEST] https://www.xn--80ak6aa92e.com/ (www.apple.com) + * [1] https://wiki.mozilla.org/IDN_Display_Algorithm + * [2] https://en.wikipedia.org/wiki/IDN_homograph_attack + * [3] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=punycode+firefox + * [4] https://www.xudongz.com/blog/2017/idn-phishing/ ***/ +user_pref("network.IDN_show_punycode", true); +/* 2620: enforce PDFJS, disable PDFJS scripting + * This setting controls if the option "Display in Firefox" is available in the setting below + * and by effect controls whether PDFs are handled in-browser or externally ("Ask" or "Open With") + * [WHY] pdfjs is lightweight, open source, and secure: In the last 10 years it has only had + * two known exploits, both in 2024: one 'Severe' and one 'Important' [1] + * It doesn't break "state separation" of browser content (by not sharing with OS, independent apps). + * It maintains disk avoidance and application data isolation. It's convenient. You can still save to disk. + * [NOTE] JS can still force a pdf to open in-browser by bundling its own code + * [SETUP-CHROME] You may prefer a different pdf reader for security/workflow reasons + * [SETTING] General>Applications>Portable Document Format (PDF) + * [1] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=pdf.js+firefox ***/ +user_pref("pdfjs.disabled", false); // [DEFAULT: false] +user_pref("pdfjs.enableScripting", false); // [FF86+] +/* 2624: disable middle click on new tab button opening URLs or searches using clipboard [FF115+] ***/ +user_pref("browser.tabs.searchclipboardfor.middleclick", false); // [DEFAULT: false NON-LINUX] +/* 2630: disable content analysis by DLP (Data Loss Prevention) agents + * DLP agents are background processes on managed computers that allow enterprises to monitor locally running + * applications for data exfiltration events, which they can allow/block based on customer defined DLP policies. + * 0=Block all requests, 1=Warn on all requests (which lets the user decide), 2=Allow all requests + * [1] https://github.com/chromium/content_analysis_sdk ***/ +user_pref("browser.contentanalysis.enabled", false); // [FF121+] [DEFAULT: false] +user_pref("browser.contentanalysis.default_result", 0); // [FF127+] [DEFAULT: 0] +/* 2635: disable referrer and storage access for resources injected by content scripts [FF139+] ***/ +user_pref("privacy.antitracking.isolateContentScriptResources", true); +/* 2640: disable CSP Level 2 Reporting [FF140+] ***/ +user_pref("security.csp.reporting.enabled", false); + +/** DOWNLOADS ***/ +/* 2651: enable user interaction for security by always asking where to download + * [SETUP-CHROME] On Android this blocks longtapping and saving images + * [SETTING] General>Downloads>Always ask you where to save files ***/ +user_pref("browser.download.useDownloadDir", false); +/* 2652: disable downloads panel opening on every download [FF96+] ***/ +user_pref("browser.download.alwaysOpenPanel", false); +/* 2653: disable adding downloads to the system's "recent documents" list ***/ +user_pref("browser.download.manager.addToRecentDocs", false); +/* 2654: enable user interaction for security by always asking how to handle new mimetypes [FF101+] + * [SETTING] General>Files and Applications>What should Firefox do with other files ***/ +user_pref("browser.download.always_ask_before_handling_new_types", true); + +/** EXTENSIONS ***/ +/* 2660: limit allowed extension directories + * 1=profile, 2=user, 4=application, 8=system, 16=temporary, 31=all + * The pref value represents the sum: e.g. 5 would be profile and application directories + * [SETUP-CHROME] Breaks usage of files which are installed outside allowed directories + * [1] https://archive.is/DYjAM ***/ +user_pref("extensions.enabledScopes", 5); // [HIDDEN PREF] +// user_pref("extensions.autoDisableScopes", 15); // [DEFAULT: 15] +/* 2661: disable bypassing 3rd party extension install prompts [FF82+] + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=1659530,1681331 ***/ +user_pref("extensions.postDownloadThirdPartyPrompt", false); +/* 2662: disable webextension restrictions on certain mozilla domains (you also need 4503) [FF60+] + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=1384330,1406795,1415644,1453988 ***/ +// user_pref("extensions.webextensions.restrictedDomains", ""); + +/*** [SECTION 2700]: ETP (ENHANCED TRACKING PROTECTION) ***/ +user_pref( + "_user.js.parrot", + "2700 syntax error: the parrot's joined the bleedin' choir invisible!", +); +/* 2701: enable ETP Strict Mode [FF86+] + * ETP Strict Mode enables Total Cookie Protection (TCP) + * [NOTE] Adding site exceptions disables all ETP protections for that site and increases the risk of + * cross-site state tracking e.g. exceptions for SiteA and SiteB means PartyC on both sites is shared + * [1] https://blog.mozilla.org/security/2021/02/23/total-cookie-protection/ + * [SETTING] to add site exceptions: Urlbar>ETP Shield + * [SETTING] to manage site exceptions: Options>Privacy & Security>Enhanced Tracking Protection>Manage Exceptions ***/ +user_pref("browser.contentblocking.category", "strict"); // [HIDDEN PREF] +/* 2702: disable ETP web compat features (about:compat) [FF93+] + * [SETUP-HARDEN] Includes skip lists, heuristics (SmartBlock) and automatic grants + * Opener and redirect heuristics are granted for 30 days, see [3] + * [1] https://blog.mozilla.org/security/2021/07/13/smartblock-v2/ + * [2] https://hg.mozilla.org/mozilla-central/rev/e5483fd469ab#l4.12 + * [3] https://developer.mozilla.org/docs/Web/Privacy/State_Partitioning#storage_access_heuristics ***/ +// user_pref("privacy.antitracking.enableWebcompat", false); +/* 2705: set ETP Strict/Custom exception lists (FF141+) + [SETTING] Options>Privacy & Security>Enhanced Tracking Protection>Strict/Custom>Fix major [baseline] | minor [convenience] + [1] https://support.mozilla.org/en-US/kb/manage-enhanced-tracking-protection-exceptions + [2] https://etp-exceptions.mozilla.org/ ***/ +user_pref("privacy.trackingprotection.allow_list.baseline.enabled", true); // [DEFAULT: true] +user_pref("privacy.trackingprotection.allow_list.convenience.enabled", true); // [DEFAULT: true] + +/*** [SECTION 2800]: SHUTDOWN & SANITIZING + We enable sanitizeOnShutdown to help prevent 1st party website tracking across sessions. + We consider history/downloads, which are not accessible to websites, as orthogonal and exempt these + + [SETUP-HARDEN] to clear all history/downloads on close, add the appropriate overrides from 2800's +***/ +user_pref( + "_user.js.parrot", + "2800 syntax error: the parrot's bleedin' demised!", +); +/* 2810: enable Firefox to clear items on shutdown + * [NOTE] In FF129+ clearing "siteSettings" on shutdown (2811+), or manually via site data (2820+) and + * via history (2830), will no longer remove sanitize on shutdown "cookie and site data" site exceptions (2815) + * [SETTING] Privacy & Security>History>Custom Settings>Clear history when Firefox closes | Settings ***/ +user_pref("privacy.sanitize.sanitizeOnShutdown", true); + +/** SANITIZE ON SHUTDOWN: IGNORES "ALLOW" SITE EXCEPTIONS ***/ +/* 2811: set/enforce clearOnShutdown items (if 2810 is true) [SETUP-CHROME] [FF128+] ***/ +user_pref("privacy.clearOnShutdown_v2.cache", true); // [DEFAULT: true] +user_pref("privacy.clearOnShutdown_v2.historyFormDataAndDownloads", false); // [DEFAULT: true] +// user_pref("privacy.clearOnShutdown_v2.siteSettings", false); // [DEFAULT: false] +/* 2812: set/enforce clearOnShutdown items [FF136+] ***/ +user_pref("privacy.clearOnShutdown_v2.browsingHistoryAndDownloads", false); // [DEFAULT: true] +user_pref("privacy.clearOnShutdown_v2.downloads", false); // [HIDDEN] +user_pref("privacy.clearOnShutdown_v2.formdata", true); +/* 2813: set Session Restore to clear on shutdown (if 2810 is true) [FF34+] + * [NOTE] Not needed if Session Restore is not used (0102) or it is already cleared with history (2811+) + * [NOTE] If true, this prevents resuming from crashes (also see 5008) ***/ +// user_pref("privacy.clearOnShutdown.openWindows", true); + +/** SANITIZE ON SHUTDOWN: RESPECTS "ALLOW" SITE EXCEPTIONS ***/ +/* 2815: set "Cookies" and "Site Data" to clear on shutdown (if 2810 is true) [SETUP-CHROME] [FF128+] + * [NOTE] Exceptions: For cross-domain logins, add exceptions for both sites + * e.g. https://www.youtube.com (site) + https://accounts.google.com (single sign on) + * [WARNING] Be selective with what sites you "Allow", as they also disable partitioning (1767271) + * [SETTING] to add site exceptions: Ctrl+I>Permissions>Cookies>Allow (when on the website in question) + * [SETTING] to manage site exceptions: Options>Privacy & Security>Permissions>Settings ***/ +user_pref("privacy.clearOnShutdown_v2.cookiesAndStorage", true); + +/** SANITIZE SITE DATA: IGNORES "ALLOW" SITE EXCEPTIONS ***/ +/* 2820: set manual "Clear Data" items [SETUP-CHROME] [FF128+] + * Firefox remembers your last choices. This will reset them when you start Firefox + * [SETTING] Privacy & Security>Browser Privacy>Cookies and Site Data>Clear Data ***/ +user_pref("privacy.clearSiteData.cache", true); // [DEFAULT: true] +user_pref("privacy.clearSiteData.cookiesAndStorage", false); // keep false until it respects "allow" site exceptions +user_pref("privacy.clearSiteData.historyFormDataAndDownloads", false); +// user_pref("privacy.clearSiteData.siteSettings", false); +/* 2821: set manual "Clear Data" items [FF136+] ***/ +user_pref("privacy.clearSiteData.browsingHistoryAndDownloads", false); +user_pref("privacy.clearSiteData.formdata", true); + +/** SANITIZE HISTORY: IGNORES "ALLOW" SITE EXCEPTIONS ***/ +/* 2830: set manual "Clear History" items, also via Ctrl-Shift-Del [SETUP-CHROME] [FF128+] + * Firefox remembers your last choices. This will reset them when you start Firefox + * [SETTING] Privacy & Security>History>Custom Settings>Clear History ***/ +user_pref("privacy.clearHistory.cache", true); // [DEFAULT: true] +user_pref("privacy.clearHistory.cookiesAndStorage", false); +user_pref("privacy.clearHistory.historyFormDataAndDownloads", false); // [DEFAULT: true] +// user_pref("privacy.clearHistory.siteSettings", false); // [DEFAULT: false] +/* 2831: set manual "Clear History" items [FF136+] ***/ +user_pref("privacy.clearHistory.browsingHistoryAndDownloads", false); // [DEFAULT: true] +user_pref("privacy.clearHistory.formdata", true); + +/** SANITIZE MANUAL: TIMERANGE ***/ +/* 2840: set "Time range to clear" for "Clear Data" (2820+) and "Clear History" (2830+) + * Firefox remembers your last choice. This will reset the value when you start Firefox + * 0=everything, 1=last hour, 2=last two hours, 3=last four hours, 4=today + * [NOTE] Values 5 (last 5 minutes) and 6 (last 24 hours) are not listed in the dropdown, + * which will display a blank value, and are not guaranteed to work ***/ +user_pref("privacy.sanitize.timeSpan", 0); + +/*** [SECTION 4000]: FPP (fingerprintingProtection) + RFP (4501) overrides FPP + + In FF118+ FPP is on by default in private windows (4001) and in FF119+ is controlled + by ETP (2701). FPP will also use Remote Services in future to relax FPP protections + on a per site basis for compatibility (4004). + + https://searchfox.org/mozilla-central/source/toolkit/components/resistfingerprinting/RFPTargetsDefault.inc + https://support.mozilla.org/en-US/kb/firefox-protection-against-fingerprinting#w_how-does-each-protection-work + + [NOTE] RFPTargets + granular overrides are somewhat experimental and may produce unexpected results + - e.g. FrameRate can only be controlled per process, not per origin + + 1826408 - restrict to system fonts (kBaseFonts + kLangPackFonts) (Windows, Mac, some Linux) (FF119+) + 1928705: android (FF134+) + https://searchfox.org/mozilla-central/search?path=StandardFonts*.inc + 1858181 - subtly randomize canvas per eTLD+1, per session and per window-mode (FF120+) + 1887682 - use fdlibm's sin, cos and tan in jsmath (FF134+) + 1954194 - available screen resolution: return a fixed offset height from screen per platform when not full screen (FF143+) + 1984333 - hardwareConcurrency: less than 8 return 4 else return 8 (FF143+) + 1977836 - maxTouchPoints: return multi-touch as 5 (FF143+) + 1917607 - subtly randomize WebGL's readPixels (FF145+) +***/ +user_pref("_user.js.parrot", "4000 syntax error: the parrot's bereft of life!"); +/* 4001: enable FPP in PB mode [FF114+] + * [NOTE] In FF119+, FPP for all modes (7016) is enabled with ETP Strict (2701) ***/ +// user_pref("privacy.fingerprintingProtection.pbmode", true); // [DEFAULT: true] +/* 4002: set global FPP overrides [FF114+] + * uses "RFPTargets" [1] which despite the name these are not used by RFP + * e.g. "+AllTargets,-CSSPrefersColorScheme,-JSDateTimeUTC" = all targets but allow prefers-color-scheme and do not change timezone + * e.g. "-AllTargets,+CanvasRandomization,+JSDateTimeUTC" = no targets but do use FPP canvas and change timezone + * [NOTE] Not supported by arkenfox. Either use RFP or FPP at defaults + * [1] https://searchfox.org/mozilla-central/source/toolkit/components/resistfingerprinting/RFPTargets.inc ***/ +// user_pref("privacy.fingerprintingProtection.overrides", ""); +/* 4003: set granular FPP overrides + * JSON format: e.g."[{\"firstPartyDomain\": \"netflix.com\", \"overrides\": \"-CanvasRandomization,-FrameRate,\"}]" + * [NOTE] Not supported by arkenfox. Either use RFP or FPP at defaults ***/ +// user_pref("privacy.fingerprintingProtection.granularOverrides", ""); +/* 4004: disable remote FPP overrides [FF127+] ***/ +// user_pref("privacy.fingerprintingProtection.remoteOverrides.enabled", false); + +/*** [SECTION 4500]: OPTIONAL RFP (resistFingerprinting) + RFP overrides FPP (4000) + + FF128+ Arkenfox by default uses FPP (automatically enabled with ETP Strict). For most people + this is all you need. To use RFP instead, add RFP (4501) to your overrides, and optionally + add letterboxing (4504), spoof_english (4506), and WebGL (4520). + + RFP is an all-or-nothing buy in: you cannot pick and choose what parts you want + + [WARNING] DO NOT USE extensions to alter RFP protected metrics + + 418986 - limit window.screen & CSS media queries (FF41) + FF56 + 1333651 - spoof User Agent & Navigator API + JS: spoofed as Windows 10, OS X 10.15, Android 10, or Linux + HTTP Header: spoofed as Windows 10 or Android 10 until FF136 then matches JS spoof + 1369319 - disable device sensor API + 1369357 - disable site specific zoom + 1337161 - hide gamepads from content + 1372072 - spoof network information API as "unknown" when dom.netinfo.enabled = true + 1333641 - reduce fingerprinting in WebSpeech API + FF57 + 1369309 - spoof media statistics + 1382499 - reduce screen co-ordinate fingerprinting in Touch API + 1217290 & 1409677 - enable some fingerprinting resistance for WebGL + 1354633 - limit MediaError.message to a whitelist + FF58+ + 1372073 - spoof/block fingerprinting in MediaDevices API (FF59) + Spoof: enumerate devices as one "Internal Camera" and one "Internal Microphone" + Block: suppresses the ondevicechange event + 1039069 - warn when language prefs are not set to "en*" (FF59) + 1222285 & 1433592 - spoof keyboard events and suppress keyboard modifier events (FF59) + Spoofing mimics the content language of the document. Currently it only supports en-US. + Modifier events suppressed are SHIFT and both ALT keys. Chrome is not affected. + 1459089 - disable OS locale in HTTP Accept-Language headers (ANDROID) (FF62) + 1479239 - return "no-preference" with prefers-reduced-motion (FF63) + 1492766 - spoof pointerEvent.pointerid (FF65) + 1485266 - disable exposure of system colors to CSS or canvas (FF67) + 1494034 - return "light" with prefers-color-scheme (FF67) + 1564422 - spoof audioContext outputLatency (FF70) + 1595823 - return audioContext sampleRate as 44100 (FF72) + 1607316 - spoof pointer as coarse and hover as none (ANDROID) (FF74) + 1621433 - randomize canvas (previously FF58+ returned an all-white canvas) (FF78) + 1506364 - return "no-preference" with prefers-contrast (FF80) + 1653987 - limit font visibility to bundled and "Base Fonts" (Windows, Mac, some Linux) (FF80) + 1461454 - spoof smooth=true and powerEfficient=false for supported media in MediaCapabilities (FF82) + 531915 - use fdlibm's sin, cos and tan in jsmath (FF93, ESR91.1) + 1692609 - reduce JS timing precision to 16.67ms (previously FF55+ was 100ms) (FF102) + 1422237 - return "srgb" with color-gamut (FF110) + 1794628 - return "none" with inverted-colors (FF114) + 1787790 - normalize system fonts (FF128) + 1835987 - spoof timezone as Atlantic/Reykjavik (previously FF55+ was UTC) (FF128) + 1656377 - spoof pointerEvents azimuthAngle and altitudeAngle (FF131) + 1826051 & 1957658 & 2021715 - spoof/suppress Pointer Events, spoof maxTouchPoints (FF132, FF143/ESR140.2, FF150) + previously FF64+ (1363508) it always returned maxTouchPoints as 0 + FF132: 0 = mac | 10 = windows, linux, mobile + FF143: 0 = mac, linux | 10 = windows | 5 = mobile | no longer spoof touch PointerEvents | backported to ESR140.2 + FF150: 5 = linux + 1834307 - always use smooth scrolling (FF132) + 1918202 - spoof screen orientation based on spoofed screen size and platform (FF132) + previously FF50+ it always returned landscape-primary and an angle of 0 + 1390465 - load all subtitles in WebVTT (Video Text Tracks) (FF133) + 1873382 - make spoofed devicePixelRatio and CSS media queries match (FF133) + previously FF41+ devicePixelRatio was hardcoded as 1 and FF127+ as 2 + previously FF41+ CSS media queries were spoofed as zoom level at a devicePixelRatio of 1 + 1955425 - return 128 for WebGPU subgroupMaxSize (FF138) + 1966860 - spoof WebGL debug renderer info (FF140) + previously FF60+ it was disabled + 1781277 - return 10GiB for storage estimate until persistent-storage granted (FF142, ESR140.1) + 1972600 - spoof network connection for HTMLMediaElement preload (FF142, ESR140.1) + 1975851 - return true for navigator.onLine (FF142, ESR140.1) + 1973265 - disable WebCodecs API (FF142) + 1984333 - spoof navigator.hardwareConcurrency as 4 except mac return 8 (FF143) + previously FF55+ it returned 2 + 1999126 - enforce navigator.pdfViewerEnabled as true and plugins/mimeTypes as hard-coded values (FF147) +***/ +user_pref( + "_user.js.parrot", + "4500 syntax error: the parrot's popped 'is clogs", +); +/* 4501: enable RFP + * [NOTE] pbmode applies if true and the original pref is false + * [SETUP-WEB] RFP can cause some website breakage: mainly canvas, use a canvas site exception via the urlbar. + * RFP also has a few side effects: mainly that timezone is GMT, and websites will prefer light theme ***/ +// user_pref("privacy.resistFingerprinting", true); // [FF41+] +// user_pref("privacy.resistFingerprinting.pbmode", true); // [FF114+] +/* 4502: set RFP new window size max rounded values [FF55+] + * [SETUP-CHROME] sizes round down in hundreds: width to 200s and height to 100s, to fit your screen + * [1] https://bugzilla.mozilla.org/1330882 ***/ +user_pref("privacy.window.maxInnerWidth", 1600); +user_pref("privacy.window.maxInnerHeight", 900); +/* 4503: disable mozAddonManager Web API [FF57+] + * [NOTE] To allow extensions to work on AMO, you also need 2662 + * [1] https://bugzilla.mozilla.org/buglist.cgi?bug_id=1384330,1406795,1415644,1453988 ***/ +user_pref("privacy.resistFingerprinting.block_mozAddonManager", true); +/* 4504: enable letterboxing [FF67+] + * Dynamically resizes the inner window by applying margins in stepped ranges [2] + * If you use the dimension pref, then it will only apply those resolutions. + * The format is "width1xheight1, width2xheight2, ..." (e.g. "800x600, 1000x1000") + * [SETUP-WEB] This is independent of RFP (4501). If you're using RFP, but dislike the + * margins, then don't enable this pref, keeping in mind that it is effectively fingerprintable + * [WARNING] DO NOT USE: the dimension pref is only meant for testing + * [1] https://bugzilla.mozilla.org/1407366 + * [2] https://hg.mozilla.org/mozilla-central/rev/7211cb4f58ff#l5.13 ***/ +// user_pref("privacy.resistFingerprinting.letterboxing", true); // [HIDDEN PREF] +// user_pref("privacy.resistFingerprinting.letterboxing.dimensions", ""); // [HIDDEN PREF] +/* 4505: disable RFP by domain [FF91+] + * [NOTE]: The pref takes comma separated values: e.g. "*domain1.tld, *domain2.tld" + * Working domain examples: "arkenfox.github.io", "*github.io" + * Non-working domain examples: "https://arkenfox.github.io", "github.io", "*arkenfox.github.io" ***/ +// user_pref("privacy.resistFingerprinting.exemptedDomains", "*.example.invalid"); +/* 4506: disable RFP spoof english prompt [FF59+] + * 0=prompt, 1=disabled, 2=enabled + * [NOTE] When changing from value 2, preferred languages ('intl.accept_languages') is not reset. + * [SETUP-WEB] when enabled, sets 'en-US, en' for displaying pages and 'en-US' as locale. + * [SETTING] General>Language>Choose your preferred language for displaying pages>Choose>Request English... ***/ +user_pref("privacy.spoof_english", 1); +/* 4507: skip browser.startup.blankWindow if RFP is used [FF136+] ***/ +// user_pref("privacy.resistFingerprinting.skipEarlyBlankFirstPaint", true); // [DEFAULT: true] +/* 4510: enforce Contrast Control off [FF138+] + * 0=automatic, 1=off, 2=custom + * [SETTING] General>Language and Appearance>Contrast Control ***/ +// user_pref("browser.display.document_color_use", 1); // [DEFAULT: 1 NON-WINDOWS] +/* 4511: disable using system accent colors ***/ +user_pref("widget.non-native-theme.use-theme-accent", false); // [DEFAULT: false WINDOWS] +/* 4512: enforce links targeting new windows to open in a new tab instead + * 1=most recent window or tab, 2=new window, 3=new tab + * Stops malicious window sizes and some screen resolution leaks. + * You can still right-click a link and open in a new window + * [SETTING] General>Tabs>Open links in tabs instead of new windows + * [1] https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/9881 ***/ +user_pref("browser.link.open_newwindow", 3); // [DEFAULT: 3] +/* 4513: set all open window methods to abide by "browser.link.open_newwindow" (4512) + * [1] https://searchfox.org/mozilla-central/source/dom/tests/browser/browser_test_new_window_from_content.js ***/ +user_pref("browser.link.open_newwindow.restriction", 0); +/* 4520: disable WebGL (Web Graphics Library) ***/ +// user_pref("webgl.disabled", true); + +/*** [SECTION 5000]: OPTIONAL OPSEC + Disk avoidance, application data isolation, eyeballs... +***/ +user_pref( + "_user.js.parrot", + "5000 syntax error: the parrot's taken 'is last bow", +); +/* 5001: start Firefox in PB (Private Browsing) mode + * [NOTE] In this mode all windows are "private windows" and the PB mode icon is not displayed + * [NOTE] The P in PB mode can be misleading: it means no "persistent" disk state such as history, + * caches, searches, cookies, localStorage, IndexedDB etc (which you can achieve in normal mode). + * In fact, PB mode limits or removes the ability to control some of these, and you need to quit + * Firefox to clear them. PB is best used as a one off window (Menu>New Private Window) to provide + * a temporary self-contained new session. Close all private windows to clear the PB session. + * [SETTING] Privacy & Security>History>Custom Settings>Always use private browsing mode + * [1] https://wiki.mozilla.org/Private_Browsing + * [2] https://support.mozilla.org/kb/common-myths-about-private-browsing ***/ +// user_pref("browser.privatebrowsing.autostart", true); +/* 5002: disable memory cache + * capacity: -1=determine dynamically (default), 0=none, n=memory capacity in kibibytes ***/ +// user_pref("browser.cache.memory.enable", false); +// user_pref("browser.cache.memory.capacity", 0); +/* 5003: disable saving passwords + * [NOTE] This does not clear any passwords already saved + * [SETTING] Privacy & Security>Logins and Passwords>Ask to save logins and passwords for websites ***/ +// user_pref("signon.rememberSignons", false); +/* 5004: disable permissions manager from writing to disk [FF41+] [RESTART] + * [NOTE] This means any permission changes are session only + * [1] https://bugzilla.mozilla.org/967812 ***/ +// user_pref("permissions.memory_only", true); // [HIDDEN PREF] +/* 5005: disable intermediate certificate caching [FF41+] [RESTART] + * [NOTE] This affects login/cert/key dbs. The effect is all credentials are session-only. + * Saved logins and passwords are not available. Reset the pref and restart to return them ***/ +// user_pref("security.nocertdb", true); +/* 5006: disable favicons in history and bookmarks + * [NOTE] Stored as data blobs in favicons.sqlite, these don't reveal anything that your + * actual history (and bookmarks) already do. Your history is more detailed, so + * control that instead; e.g. disable history, clear history on exit, use PB mode + * [NOTE] favicons.sqlite is sanitized on Firefox close ***/ +// user_pref("browser.chrome.site_icons", false); +/* 5007: exclude "Undo Closed Tabs" in Session Restore ***/ +// user_pref("browser.sessionstore.max_tabs_undo", 0); +/* 5008: disable resuming session from crash + * [TEST] about:crashparent ***/ +// user_pref("browser.sessionstore.resume_from_crash", false); +/* 5009: disable "open with" in download dialog [FF50+] + * Application data isolation [1] + * [1] https://bugzilla.mozilla.org/1281959 ***/ +// user_pref("browser.download.forbid_open_with", true); +/* 5010: disable location bar suggestion types + * [SETTING] Search>Address Bar>When using the address bar, suggest ***/ +// user_pref("browser.urlbar.suggest.history", false); +// user_pref("browser.urlbar.suggest.bookmark", false); +// user_pref("browser.urlbar.suggest.openpage", false); +// user_pref("browser.urlbar.suggest.topsites", false); // [FF78+] +/* 5011: disable location bar dropdown + * This value controls the total number of entries to appear in the location bar dropdown ***/ +// user_pref("browser.urlbar.maxRichResults", 0); +/* 5012: disable location bar autofill + * [1] https://support.mozilla.org/kb/address-bar-autocomplete-firefox#w_url-autocomplete ***/ +// user_pref("browser.urlbar.autoFill", false); +/* 5013: disable browsing and download history + * [NOTE] We also clear history and downloads on exit (2811+) + * [SETTING] Privacy & Security>History>Custom Settings>Remember browsing and download history ***/ +// user_pref("places.history.enabled", false); +/* 5014: disable Windows jumplist [WINDOWS] ***/ +// user_pref("browser.taskbar.lists.enabled", false); +// user_pref("browser.taskbar.lists.frequent.enabled", false); +// user_pref("browser.taskbar.lists.recent.enabled", false); +// user_pref("browser.taskbar.lists.tasks.enabled", false); +/* 5016: discourage downloading to desktop + * 0=desktop, 1=downloads (default), 2=custom + * [SETTING] To set your custom default "downloads": General>Downloads>Save files to ***/ +// user_pref("browser.download.folderList", 2); +/* 5017: disable Form Autofill + * If .supportedCountries includes your region (browser.search.region) and .supported + * is "detect" (default), then the UI will show. Stored data is not secure, uses JSON + * [SETTING] Privacy & Security>Forms and Autofill>Autofill addresses + * [1] https://wiki.mozilla.org/Firefox/Features/Form_Autofill ***/ +// user_pref("extensions.formautofill.addresses.enabled", false); // [FF55+] +// user_pref("extensions.formautofill.creditCards.enabled", false); // [FF56+] +/* 5018: limit events that can cause a pop-up ***/ +// user_pref("dom.popup_allowed_events", "click dblclick mousedown pointerdown"); +/* 5019: disable page thumbnail collection ***/ +// user_pref("browser.pagethumbnails.capturing_disabled", true); // [HIDDEN PREF] +/* 5020: disable Windows native notifications and use app notications instead [FF111+] [WINDOWS] ***/ +// user_pref("alerts.useSystemBackend.windows.notificationserver.enabled", false); + +/*** [SECTION 5500]: OPTIONAL HARDENING + Not recommended. Overriding these can cause breakage and performance issues, + they are mostly fingerprintable, and the threat model is practically nonexistent +***/ +user_pref("_user.js.parrot", "5500 syntax error: this is an ex-parrot!"); +/* 5501: disable MathML (Mathematical Markup Language) [FF51+] + * [1] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=mathml ***/ +// user_pref("mathml.disabled", true); // 1173199 +/* 5502: disable in-content SVG (Scalable Vector Graphics) [FF53+] + * [1] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=firefox+svg ***/ +// user_pref("svg.disabled", true); // 1216893 +/* 5503: disable graphite + * [1] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=firefox+graphite + * [2] https://en.wikipedia.org/wiki/Graphite_(SIL) ***/ +// user_pref("gfx.font_rendering.graphite.enabled", false); +/* 5504: disable asm.js [FF22+] + * [1] http://asmjs.org/ + * [2] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=asm.js + * [3] https://rh0dev.github.io/blog/2017/the-return-of-the-jit/ ***/ +// user_pref("javascript.options.asmjs", false); +/* 5505: disable Ion and baseline JIT to harden against JS exploits [RESTART] + * [NOTE] When both Ion and JIT are disabled, and trustedprincipals + * is enabled, then Ion can still be used by extensions (1599226) + * [1] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=firefox+jit + * [2] https://microsoftedge.github.io/edgevr/posts/Super-Duper-Secure-Mode/ ***/ +// user_pref("javascript.options.ion", false); +// user_pref("javascript.options.baselinejit", false); +// user_pref("javascript.options.jit_trustedprincipals", true); // [FF75+] [HIDDEN PREF] +/* 5506: disable WebAssembly [FF52+] + * Vulnerabilities [1] have increasingly been found, including those known and fixed + * in native programs years ago [2]. WASM has powerful low-level access, making + * certain attacks (brute-force) and vulnerabilities more possible + * [STATS] ~0.2% of websites, about half of which are for cryptomining / malvertising [2][3] + * [1] https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=wasm + * [2] https://spectrum.ieee.org/tech-talk/telecom/security/more-worries-over-the-security-of-web-assembly + * [3] https://www.zdnet.com/article/half-of-the-websites-using-webassembly-use-it-for-malicious-purposes ***/ +// user_pref("javascript.options.wasm", false); +/* 5507: disable rendering of SVG OpenType fonts ***/ +// user_pref("gfx.font_rendering.opentype_svg.enabled", false); +/* 5508: disable all DRM (Digital Rights Management) content (EME: Encryption Media Extension) + * Optionally hide the UI setting which also disables the DRM prompt + * [SETTING] General>DRM Content>Play DRM-controlled content + * [TEST] https://bitmovin.com/demos/drm + * [1] https://www.eff.org/deeplinks/2017/10/drms-dead-canary-how-we-just-lost-web-what-we-learned-it-and-what-we-need-do-next ***/ +// user_pref("media.eme.enabled", false); +// user_pref("browser.eme.ui.enabled", false); +/* 5509: disable IPv6 if using a VPN + * This is an application level fallback. Disabling IPv6 is best done at an OS/network + * level, and/or configured properly in system wide VPN setups. + * [NOTE] PHP defaults to IPv6 with "localhost". Use "php -S 127.0.0.1:PORT" + * [SETUP-WEB] PR_CONNECT_RESET_ERROR + * [TEST] https://ipleak.org/ + * [1] https://www.internetsociety.org/tag/ipv6-security/ (Myths 2,4,5,6) ***/ +// user_pref("network.dns.disableIPv6", true); +/* 5510: control when to send a cross-origin referer + * 0=always (default), 1=only if base domains match, 2=only if hosts match + * [NOTE] Will cause breakage: older modems/routers and some sites e.g banks, vimeo, icloud, instagram ***/ +// user_pref("network.http.referer.XOriginPolicy", 2); +/* 5511: set DoH bootstrap address [FF89+] + * Firefox uses the system DNS to initially resolve the IP address of your DoH server. + * When set to a valid, working value that matches your "network.trr.uri" (0712) Firefox + * won't use the system DNS. If the IP doesn't match then DoH won't work ***/ +// user_pref("network.trr.bootstrapAddr", "10.0.0.1"); // [HIDDEN PREF] + +/*** [SECTION 6000]: DON'T TOUCH ***/ +user_pref("_user.js.parrot", "6000 syntax error: the parrot's 'istory!"); +/* 6001: enforce Firefox blocklist + * [WHY] It includes updates for "revoked certificates" + * [1] https://blog.mozilla.org/security/2015/03/03/revoking-intermediate-certificates-introducing-onecrl/ ***/ +user_pref("extensions.blocklist.enabled", true); // [DEFAULT: true] +/* 6002: enforce no referer spoofing + * [WHY] Spoofing can affect CSRF (Cross-Site Request Forgery) protections ***/ +user_pref("network.http.referer.spoofSource", false); // [DEFAULT: false] +/* 6004: enforce a security delay on some confirmation dialogs such as install, open/save + * [1] https://www.squarefree.com/2004/07/01/race-conditions-in-security-dialogs/ ***/ +user_pref("security.dialog_enable_delay", 1000); // [DEFAULT: 1000] +/* 6008: enforce no First Party Isolation [FF51+] + * [WARNING] Replaced with network partitioning (FF85+) and TCP (2701), and enabling FPI + * disables those. FPI is no longer maintained except at Tor Project for Tor Browser's config ***/ +user_pref("privacy.firstparty.isolate", false); // [DEFAULT: false] +/* 6009: enforce SmartBlock shims (about:compat) [FF81+] + * [1] https://blog.mozilla.org/security/2021/03/23/introducing-smartblock/ ***/ +user_pref("extensions.webcompat.enable_shims", true); // [HIDDEN PREF] [DEFAULT: true] +/* 6010: enforce no TLS 1.0/1.1 downgrades + * [TEST] https://tls-v1-1.badssl.com:1010/ ***/ +user_pref("security.tls.version.enable-deprecated", false); // [DEFAULT: false] +/* 6011: enforce disabling of Web Compatibility Reporter [FF56+] + * Web Compatibility Reporter adds a "Report Site Issue" button to send data to Mozilla + * [WHY] To prevent wasting Mozilla's time with a custom setup ***/ +user_pref("extensions.webcompat-reporter.enabled", false); // [DEFAULT: false] +/* 6012: enforce Quarantined Domains [FF115+] + * [WHY] https://support.mozilla.org/kb/quarantined-domains ***/ +user_pref("extensions.quarantinedDomains.enabled", true); // [DEFAULT: true] +/* 6050: prefsCleaner: reset previously active items removed from arkenfox FF140+ ***/ +// user_pref("browser.display.use_system_colors", ""); +// user_pref("browser.urlbar.fakespot.featureGate", ""); +// user_pref("security.OCSP.enabled", ""); +// user_pref("security.OCSP.require", ""); + +/*** [SECTION 7000]: DON'T BOTHER ***/ +user_pref( + "_user.js.parrot", + "7000 syntax error: the parrot's pushing up daisies!", +); +/* 7001: disable APIs + * Location-Aware Browsing, Full Screen + * [WHY] The API state is easily fingerprintable. + * Geo is behind a prompt (7002). Full screen requires user interaction ***/ +// user_pref("geo.enabled", false); +// user_pref("full-screen-api.enabled", false); +/* 7002: set default permissions + * Location, Camera, Microphone, Notifications [FF58+] Virtual Reality [FF73+] + * 0=always ask (default), 1=allow, 2=block + * [WHY] These are fingerprintable via Permissions API, except VR. Just add site + * exceptions as allow/block for frequently visited/annoying sites: i.e. not global + * [SETTING] to add site exceptions: Ctrl+I>Permissions> + * [SETTING] to manage site exceptions: Options>Privacy & Security>Permissions>Settings ***/ +// user_pref("permissions.default.geo", 0); +// user_pref("permissions.default.camera", 0); +// user_pref("permissions.default.microphone", 0); +// user_pref("permissions.default.desktop-notification", 0); +// user_pref("permissions.default.xr", 0); // Virtual Reality +/* 7003: disable non-modern cipher suites [1] + * [WHY] Passive fingerprinting. Minimal/non-existent threat of downgrade attacks + * [1] https://browserleaks.com/ssl ***/ +// user_pref("security.ssl3.ecdhe_ecdsa_aes_128_sha", false); +// user_pref("security.ssl3.ecdhe_ecdsa_aes_256_sha", false); +// user_pref("security.ssl3.ecdhe_rsa_aes_128_sha", false); +// user_pref("security.ssl3.ecdhe_rsa_aes_256_sha", false); +// user_pref("security.ssl3.rsa_aes_128_gcm_sha256", false); // no PFS +// user_pref("security.ssl3.rsa_aes_256_gcm_sha384", false); // no PFS +// user_pref("security.ssl3.rsa_aes_128_sha", false); // no PFS +// user_pref("security.ssl3.rsa_aes_256_sha", false); // no PFS +/* 7004: control TLS versions + * [WHY] Passive fingerprinting and security ***/ +// user_pref("security.tls.version.min", 3); // [DEFAULT: 3] +// user_pref("security.tls.version.max", 4); +/* 7005: disable SSL session IDs [FF36+] + * [WHY] Passive fingerprinting and perf costs. These are session-only + * and isolated with network partitioning (FF85+) and/or containers ***/ +// user_pref("security.ssl.disable_session_identifiers", true); +/* 7007: referers + * [WHY] Only cross-origin referers (1602, 5510) matter ***/ +// user_pref("network.http.sendRefererHeader", 2); +// user_pref("network.http.referer.trimmingPolicy", 0); +/* 7008: set the default Referrer Policy [FF59+] + * 0=no-referer, 1=same-origin, 2=strict-origin-when-cross-origin, 3=no-referrer-when-downgrade + * [WHY] Defaults are fine. They can be overridden by a site-controlled Referrer Policy ***/ +// user_pref("network.http.referer.defaultPolicy", 2); // [DEFAULT: 2] +// user_pref("network.http.referer.defaultPolicy.pbmode", 2); // [DEFAULT: 2] +/* 7010: disable HTTP Alternative Services [FF37+] + * [WHY] Already isolated with network partitioning (FF85+) ***/ +// user_pref("network.http.altsvc.enabled", false); +/* 7011: disable website control over browser right-click context menu + * [WHY] Just use Shift-Right-Click ***/ +// user_pref("dom.event.contextmenu.enabled", false); +/* 7012: disable icon fonts (glyphs) and local fallback rendering + * [WHY] Breakage, font fallback is equivalency, also RFP + * [1] https://bugzilla.mozilla.org/789788 + * [2] https://gitlab.torproject.org/legacy/trac/-/issues/8455 ***/ +// user_pref("gfx.downloadable_fonts.enabled", false); // [FF41+] +// user_pref("gfx.downloadable_fonts.fallback_delay", -1); +/* 7013: disable Clipboard API + * [WHY] Fingerprintable. Breakage. Cut/copy/paste require user + * interaction, and paste is limited to focused editable fields ***/ +// user_pref("dom.event.clipboardevents.enabled", false); +/* 7014: disable System Add-on updates + * [WHY] It can compromise security. System addons ship with prefs, use those ***/ +// user_pref("extensions.systemAddon.update.enabled", false); // [FF62+] +// user_pref("extensions.systemAddon.update.url", ""); // [FF44+] +/* 7015: enable the DNT (Do Not Track) HTTP header + * [WHY] Fingerprintable. In FF141+ DNT is never enabled. DNT is slated for deprecation [1] + [NOTE] In FF140, DNT is enforced with Tracking Protection which is used in ETP Strict (2701) + [1] https://bugzilla.mozilla.org/1967420 ***/ +// user_pref("privacy.donottrackheader.enabled", true); +/* 7016: customize ETP settings + * [NOTE] FPP (fingerprintingProtection) is ignored when RFP (4501) is enabled + * [WHY] Arkenfox only supports strict (2701) which sets these at runtime ***/ +// user_pref("network.cookie.cookieBehavior", 5); // [DEFAULT: 5] +// user_pref("network.cookie.cookieBehavior.optInPartitioning", true); // [ETP FF132+] +// user_pref("network.http.referer.disallowCrossSiteRelaxingDefault", true); +// user_pref("network.http.referer.disallowCrossSiteRelaxingDefault.top_navigation", true); // [FF100+] +// user_pref("privacy.bounceTrackingProtection.mode", 1); // [FF131+] [ETP FF133+] +// user_pref("privacy.fingerprintingProtection", true); // [FF114+] [ETP FF119+] +// user_pref("privacy.partition.network_state.ocsp_cache", true); // [DEFAULT: true] +// user_pref("privacy.query_stripping.enabled", true); // [FF101+] +// user_pref("privacy.trackingprotection.enabled", true); +// user_pref("privacy.trackingprotection.socialtracking.enabled", true); +// user_pref("privacy.trackingprotection.cryptomining.enabled", true); // [DEFAULT: true] +// user_pref("privacy.trackingprotection.fingerprinting.enabled", true); // [DEFAULT: true] +/* 7017: disable service workers + * [WHY] Already isolated with TCP (2701) behind a pref ***/ +// user_pref("dom.serviceWorkers.enabled", false); +/* 7018: disable Web Notifications [FF22+] + * [WHY] Web Notifications are behind a prompt (7002) + * [1] https://blog.mozilla.org/en/products/firefox/block-notification-requests/ ***/ +// user_pref("dom.webnotifications.enabled", false); +/* 7019: disable Push Notifications [FF44+] + * [WHY] Website "push" requires subscription, and the API is required for CRLite (1224) + * [NOTE] To remove all subscriptions, reset "dom.push.userAgentID" + * [1] https://support.mozilla.org/kb/push-notifications-firefox ***/ +// user_pref("dom.push.enabled", false); +/* 7020: disable WebRTC (Web Real-Time Communication) + * [WHY] Firefox desktop uses mDNS hostname obfuscation and the private IP is never exposed until + * required in TRUSTED scenarios; i.e. after you grant device (microphone or camera) access + * [TEST] https://browserleaks.com/webrtc + * [1] https://groups.google.com/g/discuss-webrtc/c/6stQXi72BEU/m/2FwZd24UAQAJ + * [2] https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-mdns-ice-candidates#section-3.1.1 ***/ +// user_pref("media.peerconnection.enabled", false); +/* 7021: enable GPC (Global Privacy Control) in non-PB windows + * [WHY] Passive and active fingerprinting. Mostly redundant with Tracking Protection + * in ETP Strict (2701) and sanitizing on close (2800s) ***/ +// user_pref("privacy.globalprivacycontrol.enabled", true); +/* 7022: bFPP (baselineFingerprintingProtection) [FF139+] + * [WHY] Arkenfox only supports ETP Strict (2701) which enables FPP browser-wide (normal and private + * browsing window contexts). If FPP is enabled in the same context as bFPP, FPP takes precedence. + // user_pref("privacy.baselineFingerprintingProtection", true); + // user_pref("privacy.baselineFingerprintingProtection.granularOverrides", ""); + // user_pref("privacy.baselineFingerprintingProtection.overrides", ""); + +/*** [SECTION 8000]: DON'T BOTHER: FINGERPRINTING + [WHY] They are insufficient for fingerprinting protection and do more harm than good + [WARNING] DO NOT USE: they can interfere with built-in solutions such as RFP and FPP +***/ +user_pref( + "_user.js.parrot", + "8000 syntax error: the parrot's crossed the Jordan", +); +/* 8001: prefsCleaner: reset items useless for anti-fingerprinting ***/ +// user_pref("browser.display.use_document_fonts", ""); +// user_pref("browser.zoom.siteSpecific", ""); +// user_pref("device.sensors.enabled", ""); +// user_pref("dom.enable_performance", ""); +// user_pref("dom.enable_resource_timing", ""); +// user_pref("dom.gamepad.enabled", ""); +// user_pref("dom.maxHardwareConcurrency", ""); +// user_pref("dom.w3c_touch_events.enabled", ""); +// user_pref("dom.webaudio.enabled", ""); +// user_pref("font.system.whitelist", ""); +// user_pref("general.appname.override", ""); +// user_pref("general.appversion.override", ""); +// user_pref("general.buildID.override", ""); +// user_pref("general.oscpu.override", ""); +// user_pref("general.platform.override", ""); +// user_pref("general.useragent.override", ""); +// user_pref("media.navigator.enabled", ""); +// user_pref("media.video_stats.enabled", ""); +// user_pref("media.webspeech.synth.enabled", ""); +// user_pref("ui.use_standins_for_native_colors", ""); +// user_pref("webgl.enable-debug-renderer-info", ""); + +/*** [SECTION 8500]: TELEMETRY + Arkenfox does not consider Firefox telemetry to be a privacy or security concern - comments below. + But since most arkenfox users prefer it disabled, we'll do that rather than cause overrides. + + Opt-out + - Telemetry is essential: a browser engine is a _very_ large complex beast costing billions to maintain + - Opt-in telemetry _does not_ work and results in data that is unrepresentative and may be misleading + Choice + - Every new profile on first use provides data collection/use policy and the abillty to opt-out + - It can be disabled at any time (Settings>Privacy & Security>Data Collection and Use) + Data + - no PII (Personally Identifiable Information) + - can be viewed in about:telemetry + - uses Prio [1][2][3], Glean [4], Oblivious HTTP [5][6] + + [1] https://crypto.stanford.edu/prio/ + [2] https://hacks.mozilla.org/2018/10/testing-privacy-preserving-telemetry-with-prio/ + [3] https://blog.mozilla.org/security/2019/06/06/next-steps-in-privacy-preserving-telemetry-with-prio/ + [4] https://firefox-source-docs.mozilla.org/toolkit/components/glean/index.html + [5] https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/ohttp.html + [6] https://blog.mozilla.org/en/tag/oblivious-http/ +***/ +user_pref("_user.js.parrot", "8500 syntax error: the parrot's off the twig!"); +/* 8500: disable new data submission [FF41+] + * If disabled, no policy is shown or upload takes place, ever + * [1] https://bugzilla.mozilla.org/1195552 ***/ +user_pref("datareporting.policy.dataSubmissionEnabled", false); +/* 8501: disable Health Reports + * [SETTING] Privacy & Security>Firefox Data Collection and Use>Send technical... data ***/ +user_pref("datareporting.healthreport.uploadEnabled", false); +/* 8502: disable telemetry + * The "unified" pref affects the behavior of the "enabled" pref + * - If "unified" is false then "enabled" controls the telemetry module + * - If "unified" is true then "enabled" only controls whether to record extended data + * [NOTE] "toolkit.telemetry.enabled" is now LOCKED to reflect prerelease (true) or release builds (false) [2] + * [1] https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/internals/preferences.html + * [2] https://medium.com/georg-fritzsche/data-preference-changes-in-firefox-58-2d5df9c428b5 ***/ +user_pref("toolkit.telemetry.unified", false); +user_pref("toolkit.telemetry.enabled", false); // see [NOTE] +user_pref("toolkit.telemetry.server", "data:,"); +user_pref("toolkit.telemetry.archive.enabled", false); +user_pref("toolkit.telemetry.newProfilePing.enabled", false); // [FF55+] +user_pref("toolkit.telemetry.shutdownPingSender.enabled", false); // [FF55+] +user_pref("toolkit.telemetry.updatePing.enabled", false); // [FF56+] +user_pref("toolkit.telemetry.bhrPing.enabled", false); // [FF57+] Background Hang Reporter +user_pref("toolkit.telemetry.firstShutdownPing.enabled", false); // [FF57+] +/* 8503: disable Telemetry Coverage + * [1] https://blog.mozilla.org/data/2018/08/20/effectively-measuring-search-in-firefox/ ***/ +user_pref("toolkit.telemetry.coverage.opt-out", true); // [HIDDEN PREF] +user_pref("toolkit.coverage.opt-out", true); // [FF64+] [HIDDEN PREF] +user_pref("toolkit.coverage.endpoint.base", ""); + +/*** [SECTION 9000]: NON-PROJECT RELATED ***/ +user_pref( + "_user.js.parrot", + "9000 syntax error: the parrot's cashed in 'is chips!", +); +/* 9001: disable welcome notices ***/ +user_pref("browser.startup.homepage_override.mstone", "ignore"); // [HIDDEN PREF] +/* 9002: disable General>Browsing>Recommend extensions/features as you browse [FF67+] ***/ +user_pref( + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", + false, +); +user_pref( + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", + false, +); +/* 9004: disable search terms [FF110+] + * [SETTING] Search>Search Bar>Use the address bar for search and navigation>Show search terms instead of URL... ***/ +user_pref("browser.urlbar.showSearchTerms.enabled", false); + +/*** [SECTION 9999]: DEPRECATED / RENAMED ***/ +user_pref( + "_user.js.parrot", + "9999 syntax error: the parrot's shuffled off 'is mortal coil!", +); +/* ESR140.x still uses all the following prefs +// [NOTE] replace the * with a slash in the line above to re-enable active ones +// FF148 +// 0603: disable predictor / prefetching + // [-] https://bugzilla.mozilla.org/2006028 +user_pref("network.predictor.enabled", false); // [DEFAULT: false FF144+] +user_pref("network.predictor.enable-prefetch", false); // [FF48+] [DEFAULT: false] +// ***/ + +/* END: internal custom pref to test for syntax errors ***/ +user_pref( + "_user.js.parrot", + "SUCCESS: No no he's not dead, he's, he's restin'!", +); diff --git a/home/aselimov/firefox/userChrome.css b/home/aselimov/firefox/userChrome.css new file mode 100644 index 0000000..15bfcd2 --- /dev/null +++ b/home/aselimov/firefox/userChrome.css @@ -0,0 +1,13 @@ +/* Niri provides window management */ +.titlebar-buttonbox-container { + display: none !important; +} + +.titlebar-spacer { + display: none !important; +} + +/* Slightly more compact top toolbar */ +#nav-bar { + min-height: 32px !important; +} diff --git a/home/aselimov/fuzzel.nix b/home/aselimov/fuzzel.nix new file mode 100644 index 0000000..5604572 --- /dev/null +++ b/home/aselimov/fuzzel.nix @@ -0,0 +1,43 @@ +{config, pkgs, ... }: +{ + programs.fuzzel.enable = true; + + xdg.configFile."fuzzel/fuzzel.ini".text = '' + include=~/.config/fuzzel/colors.ini + + [main] + font=DepartureMono Nerd Font:size=10 + prompt=❯ + width=45 + lines=5 + horizontal-pad=20 + vertical-pad=12 + inner-pad=8 + + [border] + width=2 + radius=12 + ''; + + xdg.configFile."fuzzel/themes/zenwritten-light.ini".text = '' + [colors] + background=eeeeeeff + text=353535ff + match=286486ff + selection=cfcfcfff + selection-text=353535ff + selection-match=286486ff + border=787878ff + ''; + + xdg.configFile."fuzzel/themes/zenwritten-dark.ini".text = '' + [colors] + background=1c1c1cff + text=b9b9b9ff + match=8ba4b0ff + selection=3a3a3aff + selection-text=eeeeeeff + selection-match=a8c2ceff + border=666666ff + ''; +} diff --git a/home/aselimov/ghostty/config b/home/aselimov/ghostty/config new file mode 100644 index 0000000..7815f18 --- /dev/null +++ b/home/aselimov/ghostty/config @@ -0,0 +1,35 @@ +# --- Basics +auto-update-channel = tip +font-family = "DepartureMono Nerd Font Mono" +font-size = 11 +background-opacity = 1.0 +window-decoration = false +confirm-close-surface = false + +# Auto light/dark theme pair that matches your two palettes below +#theme = dark:my-dark,light:my-light +theme = dark:zenwritten-dark,light:zenwritten-light + +# Font-size keybindings (match Ctrl+Shift+j/k from WezTerm) +keybind = all:ctrl+shift+k=increase_font_size:1 +keybind = all:ctrl+shift+j=decrease_font_size:1 + +# Optional: make the split divider visible (newer Ghostty) +# split-divider-color = #444444 + +keybind = cmd+shift+j=goto_split:next +keybind = cmd+shift+k=goto_split:previous +keybind = cmd+shift+s=new_split:down +keybind = cmd+shift+v=new_split:right +keybind = cmd+shift+e=equalize_splits + +keybind = cmd+shift+u=scroll_page_up +keybind = cmd+shift+d=scroll_page_down +split-inherit-working-directory = true + +keybind = cmd+shift+p=ignore + +confirm-close-surface = true +keybind = cmd+shift+t=close_surface +keybind = ctrl+shift+c=copy_to_clipboard +keybind = ctrl+shift+v=paste_from_clipboard diff --git a/home/aselimov/ghostty/themes/zenwritten-dark b/home/aselimov/ghostty/themes/zenwritten-dark new file mode 100644 index 0000000..e89834e --- /dev/null +++ b/home/aselimov/ghostty/themes/zenwritten-dark @@ -0,0 +1,28 @@ +# Colors = your WezTerm dark palette +foreground = #BBBBBB +background = #191919 +cursor-color = #BBBBBB +cursor-text = #191919 +selection-foreground = #191919 +selection-background = #BBBBBB +bold-color = "#fefefe" + +# ANSI 0..15 +palette = 0=#191919 +palette = 1=#DE6E7C +palette = 2=#819B69 +palette = 3=#B77E64 +palette = 4=#6099C0 +palette = 5=#B279A7 +palette = 6=#66A5AD +palette = 7=#BBBBBB +palette = 8=#3d3839 +palette = 9=#E8838F +palette = 10=#8BAE68 +palette = 11=#D68C67 +palette = 12=#61ABDA +palette = 13=#CF86C1 +palette = 14=#65B8C1 +palette = 15=#8e8e8e + +unfocused-split-fill=#BBBBBB diff --git a/home/aselimov/ghostty/themes/zenwritten-light b/home/aselimov/ghostty/themes/zenwritten-light new file mode 100644 index 0000000..b09907a --- /dev/null +++ b/home/aselimov/ghostty/themes/zenwritten-light @@ -0,0 +1,28 @@ +# Colors = your WezTerm light palette +foreground = #4F5e68 +background = #F0EDEC +cursor-color = #2c363c +cursor-text = #F0EDEC +selection-foreground = #F0EDEC +selection-background = #2c363c +bold-color = "#010101" + +# ANSI 0..15 +palette = 0=#F0EDEC +palette = 1=#A8334C +palette = 2=#4F6C31 +palette = 3=#944927 +palette = 4=#286486 +palette = 5=#88507D +palette = 6=#3B8992 +palette = 7=#2C363C +palette = 8=#CFC1BA +palette = 9=#94253E +palette = 10=#3F5A22 +palette = 11=#803D1C +palette = 12=#1D5573 +palette = 13=#7B3B70 +palette = 14=#2B747C +palette = 15=#4F5E68 + +unfocused-split-fill=#CFC1BA diff --git a/home/aselimov/home.nix b/home/aselimov/home.nix new file mode 100644 index 0000000..3201004 --- /dev/null +++ b/home/aselimov/home.nix @@ -0,0 +1,125 @@ +{config, pkgs, ... }: +let + xremap-niri = pkgs.rustPlatform.buildRustPackage rec { + pname = "xremap"; + version = "0.15.11"; + + src = pkgs.fetchFromGitHub { + owner = "xremap"; + repo = "xremap"; + rev = "v${version}"; + hash = "sha256-N5JItxzg0nU9hsW+fOEJ9FHiq6L0rt8jXvieefuHc5k="; + }; + + cargoHash = "sha256-45YN1ZjM485phmvMNOna/hXE+EorZcz3xLpTVZIWZn8="; + + buildFeatures = [ "niri" ]; + }; +in +{ + imports = [ + ../shell/shell.nix + ../neovim/neovim.nix + ./firefox/firefox.nix + ./theme/theme.nix + ./fuzzel.nix + ./mako.nix + ]; + home.username = "aselimov"; + home.homeDirectory = "/home/aselimov"; + home.stateVersion = "26.05"; + + programs.home-manager.enable = true; + programs.ghostty.enable = true; + programs.mpv = { + enable = true; + + config = { + save-position-on-quit = true; + cache = true; + demuxer-max-bytes = "500MiB"; + demuxer-max-back-bytes = "200MiB"; + demuxer-readahead-secs = 300; + hr-seek = false; + ytdl-format="bestvideo[vcodec^=avc1]+bestaudio/best"; + gpu-context = "wayland"; + }; + }; + home.packages = with pkgs; [ + ripgrep + waybar + mako + wl-clipboard + pavucontrol + xremap-niri + zip + unzip + glib + jujutsu + gnupg + codex + awww + imv + yt-dlp + pass + dino + ]; + home.pointerCursor = { + enable = true; + package = pkgs.phinger-cursors; + name = "phinger-cursors-dark"; + size = 16; + + gtk.enable = true; + }; + gtk = { + enable = true; + + theme = { + name = "Adwaita"; + package = pkgs.gnome-themes-extra; + }; + }; + + dconf.enable = true; + + xdg.configFile."niri/config.kdl".source = ./niri/config.kdl; + xdg.configFile."ghostty" = { + source = ./ghostty; + recursive = true; + }; + xdg.configFile."waybar" = { + source = ./waybar; + recursive = true; + }; + + xdg.configFile."xremap/config.yml".source = ./xremap.yml; + + home.sessionPath = [ + "$HOME/bin" + ]; + + systemd.user.services.xremap = { + Unit = { + Description = "xremap"; + }; + + Service = { + ExecStart = + "${xremap-niri}/bin/xremap --watch --ignore 'AT Translated Set 2 keyboard' %h/.config/xremap/config.yml"; + + Restart = "on-failure"; + RestartSec = 1; + }; +}; + + services.gpg-agent = { + enable = true; + + pinentry.package = pkgs.pinentry-gnome3; + + defaultCacheTtl = 86400; + maxCacheTtl = 86400; + }; + +} diff --git a/home/aselimov/mako.nix b/home/aselimov/mako.nix new file mode 100644 index 0000000..efde831 --- /dev/null +++ b/home/aselimov/mako.nix @@ -0,0 +1,52 @@ +{config, pgs, ... }: +{ + services.mako = { + enable = true; + + settings = { + anchor = "top-right"; + layer = "overlay"; + + width = 360; + height = 110; + margin = 12; + padding = 14; + + font = "JetBrainsMono Nerd Font 11"; + + border-size = 2; + border-radius = 10; + + icons = true; + max-icon-size = 48; + + markup = true; + actions = true; + + default-timeout = 5000; + }; + + extraConfig = '' + include=~/.config/mako/theme.conf + + [urgency=low] + default-timeout=3000 + + [urgency=critical] + default-timeout=0 + ''; + }; + xdg.configFile."mako/themes/zenwritten-light.conf".text = '' + background-color=#eeeeee + text-color=#353535 + border-color=#787878 + progress-color=over #286486 + ''; + + xdg.configFile."mako/themes/zenwritten-dark.conf".text = '' + background-color=#1c1c1c + text-color=#b9b9b9 + border-color=#666666 + progress-color=over #8ba4b0 + ''; +} diff --git a/home/aselimov/niri/config.kdl b/home/aselimov/niri/config.kdl new file mode 100644 index 0000000..0817de8 --- /dev/null +++ b/home/aselimov/niri/config.kdl @@ -0,0 +1,623 @@ +// This config is in the KDL format: https://kdl.dev +// "/-" comments out the following node. +// Check the wiki for a full description of the configuration: +// https://niri-wm.github.io/niri/Configuration:-Introduction + +// Input device configuration. +// Find the full list of options on the wiki: +// https://niri-wm.github.io/niri/Configuration:-Input +input { + keyboard { + xkb { + // You can set rules, model, layout, variant and options. + // For more information, see xkeyboard-config(7). + + // For example: + // layout "us,ru" + // options "grp:win_space_toggle,compose:ralt,ctrl:nocaps" + + // If this section is empty, niri will fetch xkb settings + // from org.freedesktop.locale1. You can control these using + // localectl set-x11-keymap. + options "caps:escape" + } + + // Enable numlock on startup, omitting this setting disables it. + numlock + } + + // Next sections include libinput settings. + // Omitting settings disables them, or leaves them at their default values. + // All commented-out settings here are examples, not defaults. + touchpad { + // off + tap + // dwt + // dwtp + // drag false + // drag-lock + // natural-scroll + // accel-speed 0.2 + // accel-profile "flat" + // scroll-method "two-finger" + // disabled-on-external-mouse + } + + mouse { + // off + // natural-scroll + accel-speed -1.0 + accel-profile "flat" + // scroll-method "no-scroll" + } + + trackpoint { + // off + // natural-scroll + // accel-speed 0.2 + // accel-profile "flat" + // scroll-method "on-button-down" + // scroll-button 273 + // scroll-button-lock + // middle-emulation + } + + // Uncomment this to make the mouse warp to the center of newly focused windows. + warp-mouse-to-focus + + // Focus windows and outputs automatically when moving the mouse into them. + // Setting max-scroll-amount="0%" makes it work only on windows already fully on screen. + // focus-follows-mouse max-scroll-amount="0%" +} + +// You can configure outputs by their name, which you can find +// by running `niri msg outputs` while inside a niri instance. +// The built-in laptop monitor is usually called "eDP-1". +// Find more information on the wiki: +// https://niri-wm.github.io/niri/Configuration:-Outputs +// Remember to uncomment the node by removing "/-"! +output "eDP-1" { + // Uncomment this line to disable this output. + // off + + // Resolution and, optionally, refresh rate of the output. + // The format is "x" or "x@". + // If the refresh rate is omitted, niri will pick the highest refresh rate + // for the resolution. + // If the mode is omitted altogether or is invalid, niri will pick one automatically. + // Run `niri msg outputs` while inside a niri instance to list all outputs and their modes. + mode "1920x1080@120.030" + + // You can use integer or fractional scale, for example use 1.5 for 150% scale. + scale 1 + + // Transform allows to rotate the output counter-clockwise, valid values are: + // normal, 90, 180, 270, flipped, flipped-90, flipped-180 and flipped-270. + transform "normal" + + // Position of the output in the global coordinate space. + // This affects directional monitor actions like "focus-monitor-left", and cursor movement. + // The cursor can only move between directly adjacent outputs. + // Output scale and rotation has to be taken into account for positioning: + // outputs are sized in logical, or scaled, pixels. + // For example, a 3840×2160 output with scale 2.0 will have a logical size of 1920×1080, + // so to put another output directly adjacent to it on the right, set its x to 1920. + // If the position is unset or results in an overlap, the output is instead placed + // automatically. + position x=0 y=0 +} + +cursor { + xcursor-theme "phinger-cursors-dark" + xcursor-size 24 +} + +// Settings that influence how windows are positioned and sized. +// Find more information on the wiki: +// https://niri-wm.github.io/niri/Configuration:-Layout +layout { + // Set gaps around windows in logical pixels. + gaps 16 + + // When to center a column when changing focus, options are: + // - "never", default behavior, focusing an off-screen column will keep at the left + // or right edge of the screen. + // - "always", the focused column will always be centered. + // - "on-overflow", focusing a column will center it if it doesn't fit + // together with the previously focused column. + center-focused-column "never" + + // You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between. + preset-column-widths { + // Proportion sets the width as a fraction of the output width, taking gaps into account. + // For example, you can perfectly fit four windows sized "proportion 0.25" on an output. + // The default preset widths are 1/3, 1/2 and 2/3 of the output. + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + + // Fixed sets the width in logical pixels exactly. + // fixed 1920 + } + + // You can also customize the heights that "switch-preset-window-height" (Mod+Ctrl+Shift+R) toggles between. + // preset-window-heights { } + + // You can change the default width of the new windows. + default-column-width { proportion 0.5; } + // If you leave the brackets empty, the windows themselves will decide their initial width. + // default-column-width {} + + // By default focus ring and border are rendered as a solid background rectangle + // behind windows. That is, they will show up through semitransparent windows. + // This is because windows using client-side decorations can have an arbitrary shape. + // + // If you don't like that, you should uncomment `prefer-no-csd` below. + // Niri will draw focus ring and border *around* windows that agree to omit their + // client-side decorations. + // + // Alternatively, you can override it with a window rule called + // `draw-border-with-background`. + + // You can change how the focus ring looks. + focus-ring { + // Uncomment this line to disable the focus ring. + // off + + // How many logical pixels the ring extends out from the windows. + width 4 + + // Colors can be set in a variety of ways: + // - CSS named colors: "red" + // - RGB hex: "#rgb", "#rgba", "#rrggbb", "#rrggbbaa" + // - CSS-like notation: "rgb(255, 127, 0)", rgba(), hsl() and a few others. + + // Color of the ring on the active monitor. + active-color "#7fc8ff" + + // Color of the ring on inactive monitors. + // + // The focus ring only draws around the active window, so the only place + // where you can see its inactive-color is on other monitors. + inactive-color "#505050" + + // You can also use gradients. They take precedence over solid colors. + // Gradients are rendered the same as CSS linear-gradient(angle, from, to). + // The angle is the same as in linear-gradient, and is optional, + // defaulting to 180 (top-to-bottom gradient). + // You can use any CSS linear-gradient tool on the web to set these up. + // Changing the color space is also supported, check the wiki for more info. + // + // active-gradient from="#80c8ff" to="#c7ff7f" angle=45 + + // You can also color the gradient relative to the entire view + // of the workspace, rather than relative to just the window itself. + // To do that, set relative-to="workspace-view". + // + // inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view" + } + + // You can also add a border. It's similar to the focus ring, but always visible. + border { + // The settings are the same as for the focus ring. + // If you enable the border, you probably want to disable the focus ring. + off + + width 4 + active-color "#ffc87f" + inactive-color "#505050" + + // Color of the border around windows that request your attention. + urgent-color "#9b0000" + + // Gradients can use a few different interpolation color spaces. + // For example, this is a pastel rainbow gradient via in="oklch longer hue". + // + // active-gradient from="#e5989b" to="#ffb4a2" angle=45 relative-to="workspace-view" in="oklch longer hue" + + // inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view" + } + + // You can enable drop shadows for windows. + shadow { + // Uncomment the next line to enable shadows. + // on + + // By default, the shadow draws only around its window, and not behind it. + // Uncomment this setting to make the shadow draw behind its window. + // + // Note that niri has no way of knowing about the CSD window corner + // radius. It has to assume that windows have square corners, leading to + // shadow artifacts inside the CSD rounded corners. This setting fixes + // those artifacts. + // + // However, instead you may want to set prefer-no-csd and/or + // geometry-corner-radius. Then, niri will know the corner radius and + // draw the shadow correctly, without having to draw it behind the + // window. These will also remove client-side shadows if the window + // draws any. + // + // draw-behind-window true + + // You can change how shadows look. The values below are in logical + // pixels and match the CSS box-shadow properties. + + // Softness controls the shadow blur radius. + softness 30 + + // Spread expands the shadow. + spread 5 + + // Offset moves the shadow relative to the window. + offset x=0 y=5 + + // You can also change the shadow color and opacity. + color "#0007" + } + + // Struts shrink the area occupied by windows, similarly to layer-shell panels. + // You can think of them as a kind of outer gaps. They are set in logical pixels. + // Left and right struts will cause the next window to the side to always be visible. + // Top and bottom struts will simply add outer gaps in addition to the area occupied by + // layer-shell panels and regular gaps. + struts { + // left 64 + // right 64 + // top 64 + // bottom 64 + } +} + +// Add lines like this to spawn processes at startup. +// Note that running niri as a session supports xdg-desktop-autostart, +// which may be more convenient to use. +// See the binds section below for more spawn examples. + +// This line starts waybar, a commonly used bar for Wayland compositors. +spawn-at-startup "sh" "-c" "systemctl --user import-environment XDG_DATA_DIRS WAYLAND_DISPLAY XDG_RUNTIME_DIR DBUS_SESSION_BUS_ADDRESS NIRI_SOCKET && systemctl --user restart awww.service wallpaper.service" +spawn-at-startup "systemctl" "--user" "restart" "xremap" +spawn-at-startup "waybar" + + +// To run a shell command (with variables, pipes, etc.), use spawn-sh-at-startup: +// spawn-sh-at-startup "qs -c ~/source/qs/MyAwesomeShell" + +hotkey-overlay { + // Uncomment this line to disable the "Important Hotkeys" pop-up at startup. + skip-at-startup +} + +// Uncomment this line to ask the clients to omit their client-side decorations if possible. +// If the client will specifically ask for CSD, the request will be honored. +// Additionally, clients will be informed that they are tiled, removing some client-side rounded corners. +// This option will also fix border/focus ring drawing behind some semitransparent windows. +// After enabling or disabling this, you need to restart the apps for this to take effect. +// prefer-no-csd + +// You can change the path where screenshots are saved. +// A ~ at the front will be expanded to the home directory. +// The path is formatted with strftime(3) to give you the screenshot date and time. +screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + +// You can also set this to null to disable saving screenshots to disk. +// screenshot-path null + +// Animation settings. +// The wiki explains how to configure individual animations: +// https://niri-wm.github.io/niri/Configuration:-Animations +animations { + // Uncomment to turn off all animations. + // off + + // Slow down all animations by this factor. Values below 1 speed them up instead. + // slowdown 3.0 +} + +// Window rules let you adjust behavior for individual windows. +// Find more information on the wiki: +// https://niri-wm.github.io/niri/Configuration:-Window-Rules + + +// Open the Firefox picture-in-picture player as floating by default. +window-rule { + // This app-id regular expression will work for both: + // - host Firefox (app-id is "firefox") + // - Flatpak Firefox (app-id is "org.mozilla.firefox") + match app-id=r#"firefox$"# title="^Picture-in-Picture$" + open-floating true +} + +// Example: block out two password managers from screen capture. +// (This example rule is commented out with a "/-" in front.) +/-window-rule { + match app-id=r#"^org\.keepassxc\.KeePassXC$"# + match app-id=r#"^org\.gnome\.World\.Secrets$"# + + block-out-from "screen-capture" + + // Use this instead if you want them visible on third-party screenshot tools. + // block-out-from "screencast" +} + +// Example: enable rounded corners for all windows. +// (This example rule is commented out with a "/-" in front.) +window-rule { + geometry-corner-radius 12 + clip-to-geometry true +} + +window-rule { + match app-id="^mpv$" + open-floating true + default-floating-position x=10 y=10 relative-to="top-right" + default-column-width { + fixed 700 + } + + default-window-height { + fixed 394 + } +} + +binds { + // Keys consist of modifiers separated by + signs, followed by an XKB key name + // in the end. To find an XKB name for a particular key, you may use a program + // like wev. + // + // "Mod" is a special modifier equal to Super when running on a TTY, and to Alt + // when running as a winit window. + // + // Most actions that you can bind here can also be invoked programmatically with + // `niri msg action do-something`. + + // Mod-Shift-/, which is usually the same as Mod-?, + // shows a list of important hotkeys. + Mod+Shift+Slash { show-hotkey-overlay; } + + // Suggested binds for running programs: terminal, app launcher, screen locker. + Mod+Shift+Return hotkey-overlay-title="Open a Terminal: ghostty" { spawn "ghostty"; } + Mod+P hotkey-overlay-title="Run an Application: fuzzel" { spawn "fuzzel"; } + Super+Alt+L hotkey-overlay-title="Lock the Screen: swaylock" { spawn "swaylock"; } + + // Example volume keys mappings for PipeWire & WirePlumber. + // The allow-when-locked=true property makes them work even when the session is locked. + // Using spawn-sh allows to pass multiple arguments together with the command. + // "-l 1.0" limits the volume to 100%. + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+ -l 1.0"; } + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-"; } + XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; } + XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; } + + // Example media keys mapping using playerctl. + // This will work with any MPRIS-enabled media player. + XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; } + XF86AudioPause allow-when-locked=true { spawn-sh "playerctl play-pause"; } + XF86AudioStop allow-when-locked=true { spawn-sh "playerctl stop"; } + XF86AudioPrev allow-when-locked=true { spawn-sh "playerctl previous"; } + XF86AudioNext allow-when-locked=true { spawn-sh "playerctl next"; } + + // Example brightness key mappings for brightnessctl. + // You can use regular spawn with multiple arguments too (to avoid going through "sh"), + // but you need to manually put each argument in separate "" quotes. + XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "+10%"; } + XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "10%-"; } + + // Open/close the Overview: a zoomed-out view of workspaces and windows. + // You can also move the mouse into the top-left hot corner, + // or do a four-finger swipe up on a touchpad. + Mod+O repeat=false { toggle-overview; } + + Mod+Q repeat=false { close-window; } + + Mod+Left { focus-column-left; } + Mod+Down { focus-window-down; } + Mod+Up { focus-window-up; } + Mod+Right { focus-column-right; } + Mod+H { focus-column-left; } + Mod+L { focus-column-right; } + + Mod+Shift+Left { move-column-left; } + Mod+Shift+Down { move-window-down; } + Mod+Shift+Up { move-window-up; } + Mod+Shift+Right { move-column-right; } + Mod+Shift+H { move-column-left; } + Mod+Shift+L { move-column-right; } + + // Alternative commands that move across workspaces when reaching + // the first or last window in a column. + Mod+J { focus-window-or-workspace-down; } + Mod+K { focus-window-or-workspace-up; } + Mod+Shift+J { move-window-down-or-to-workspace-down; } + Mod+Shift+K { move-window-up-or-to-workspace-up; } + + Mod+Home { focus-column-first; } + Mod+End { focus-column-last; } + Mod+Ctrl+Home { move-column-to-first; } + Mod+Ctrl+End { move-column-to-last; } + + //Mod+Shift+Left { focus-monitor-left; } + //Mod+Shift+Down { focus-monitor-down; } + //Mod+Shift+Up { focus-monitor-up; } + //Mod+Shift+Right { focus-monitor-right; } + //Mod+Shift+H { focus-monitor-left; } + //Mod+Shift+J { focus-monitor-down; } + //Mod+Shift+K { focus-monitor-up; } + //Mod+Shift+L { focus-monitor-right; } + + //Mod+Shift+Ctrl+Left { move-column-to-monitor-left; } + //Mod+Shift+Ctrl+Down { move-column-to-monitor-down; } + //Mod+Shift+Ctrl+Up { move-column-to-monitor-up; } + //Mod+Shift+Ctrl+Right { move-column-to-monitor-right; } + //Mod+Shift+Ctrl+H { move-column-to-monitor-left; } + //Mod+Shift+Ctrl+J { move-column-to-monitor-down; } + //Mod+Shift+Ctrl+K { move-column-to-monitor-up; } + //Mod+Shift+Ctrl+L { move-column-to-monitor-right; } + + // Alternatively, there are commands to move just a single window: + // Mod+Shift+Ctrl+Left { move-window-to-monitor-left; } + // ... + + // And you can also move a whole workspace to another monitor: + // Mod+Shift+Ctrl+Left { move-workspace-to-monitor-left; } + // ... + + // Alternatively, there are commands to move just a single window: + // Mod+Ctrl+Page_Down { move-window-to-workspace-down; } + // ... + + // You can bind mouse wheel scroll ticks using the following syntax. + // These binds will change direction based on the natural-scroll setting. + // + // To avoid scrolling through workspaces really fast, you can use + // the cooldown-ms property. The bind will be rate-limited to this value. + // You can set a cooldown on any bind, but it's most useful for the wheel. + Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; } + Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; } + Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; } + Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; } + + Mod+WheelScrollRight { focus-column-right; } + Mod+WheelScrollLeft { focus-column-left; } + Mod+Ctrl+WheelScrollRight { move-column-right; } + Mod+Ctrl+WheelScrollLeft { move-column-left; } + + // Usually scrolling up and down with Shift in applications results in + // horizontal scrolling; these binds replicate that. + Mod+Shift+WheelScrollDown { focus-column-right; } + Mod+Shift+WheelScrollUp { focus-column-left; } + Mod+Ctrl+Shift+WheelScrollDown { move-column-right; } + Mod+Ctrl+Shift+WheelScrollUp { move-column-left; } + + // Similarly, you can bind touchpad scroll "ticks". + // Touchpad scrolling is continuous, so for these binds it is split into + // discrete intervals. + // These binds are also affected by touchpad's natural-scroll, so these + // example binds are "inverted", since we have natural-scroll enabled for + // touchpads by default. + // Mod+TouchpadScrollDown { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02+"; } + // Mod+TouchpadScrollUp { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02-"; } + + // You can refer to workspaces by index. However, keep in mind that + // niri is a dynamic workspace system, so these commands are kind of + // "best effort". Trying to refer to a workspace index bigger than + // the current workspace count will instead refer to the bottommost + // (empty) workspace. + // + // For example, with 2 workspaces + 1 empty, indices 3, 4, 5 and so on + // will all refer to the 3rd workspace. + Mod+1 { focus-workspace 1; } + Mod+2 { focus-workspace 2; } + Mod+3 { focus-workspace 3; } + Mod+4 { focus-workspace 4; } + Mod+5 { focus-workspace 5; } + Mod+6 { focus-workspace 6; } + Mod+7 { focus-workspace 7; } + Mod+8 { focus-workspace 8; } + Mod+9 { focus-workspace 9; } + Mod+Ctrl+1 { move-column-to-workspace 1; } + Mod+Ctrl+2 { move-column-to-workspace 2; } + Mod+Ctrl+3 { move-column-to-workspace 3; } + Mod+Ctrl+4 { move-column-to-workspace 4; } + Mod+Ctrl+5 { move-column-to-workspace 5; } + Mod+Ctrl+6 { move-column-to-workspace 6; } + Mod+Ctrl+7 { move-column-to-workspace 7; } + Mod+Ctrl+8 { move-column-to-workspace 8; } + Mod+Ctrl+9 { move-column-to-workspace 9; } + + // Alternatively, there are commands to move just a single window: + // Mod+Ctrl+1 { move-window-to-workspace 1; } + + // Switches focus between the current and the previous workspace. + // Mod+Tab { focus-workspace-previous; } + + // The following binds move the focused window in and out of a column. + // If the window is alone, they will consume it into the nearby column to the side. + // If the window is already in a column, they will expel it out. + Mod+BracketLeft { consume-or-expel-window-left; } + Mod+BracketRight { consume-or-expel-window-right; } + + // Consume one window from the right to the bottom of the focused column. + Mod+Comma { consume-window-into-column; } + // Expel the bottom window from the focused column to the right. + Mod+Period { expel-window-from-column; } + + // Cycle through widths set in preset-column-widths. + Mod+R { switch-preset-column-width; } + // Cycling through the presets in reverse order is also possible. + Mod+Shift+R { switch-preset-column-width-back; } + + Mod+Ctrl+Shift+R { switch-preset-window-height; } + Mod+Ctrl+R { reset-window-height; } + + Mod+F { maximize-column; } + Mod+Shift+F { fullscreen-window; } + + // While maximize-column leaves gaps and borders around the window, + // maximize-window-to-edges doesn't: the window expands to the edges of the screen. + // This bind corresponds to normal window maximizing, + // e.g. by double-clicking on the titlebar. + Mod+M { maximize-window-to-edges; } + + // Expand the focused column to space not taken up by other fully visible columns. + // Makes the column "fill the rest of the space". + Mod+Ctrl+F { expand-column-to-available-width; } + + Mod+C { center-column; } + + // Center all fully visible columns on screen. + Mod+Ctrl+C { center-visible-columns; } + + // Finer width adjustments. + // This command can also: + // * set width in pixels: "1000" + // * adjust width in pixels: "-5" or "+5" + // * set width as a percentage of screen width: "25%" + // * adjust width as a percentage of screen width: "-10%" or "+10%" + // Pixel sizes use logical, or scaled, pixels. I.e. on an output with scale 2.0, + // set-column-width "100" will make the column occupy 200 physical screen pixels. + Mod+Minus { set-column-width "-10%"; } + Mod+Equal { set-column-width "+10%"; } + + // Finer height adjustments when in column with other windows. + Mod+Shift+Minus { set-window-height "-10%"; } + Mod+Shift+Equal { set-window-height "+10%"; } + + // Move the focused window between the floating and the tiling layout. + Mod+U { toggle-window-floating; } + Mod+Shift+U { switch-focus-between-floating-and-tiling; } + + // Toggle tabbed column display mode. + // Windows in this column will appear as vertical tabs, + // rather than stacked on top of each other. + Mod+W { toggle-column-tabbed-display; } + + // Actions to switch layouts. + // Note: if you uncomment these, make sure you do NOT have + // a matching layout switch hotkey configured in xkb options above. + // Having both at once on the same hotkey will break the switching, + // since it will switch twice upon pressing the hotkey (once by xkb, once by niri). + // Mod+Space { switch-layout "next"; } + // Mod+Shift+Space { switch-layout "prev"; } + + Mod+S { screenshot; } + Ctrl+Print { screenshot-screen; } + Alt+Print { screenshot-window; } + + // Applications such as remote-desktop clients and software KVM switches may + // request that niri stops processing the keyboard shortcuts defined here + // so they may, for example, forward the key presses as-is to a remote machine. + // It's a good idea to bind an escape hatch to toggle the inhibitor, + // so a buggy application can't hold your session hostage. + // + // The allow-inhibiting=false property can be applied to other binds as well, + // which ensures niri always processes them, even when an inhibitor is active. + Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + + // The quit action will show a confirmation dialog to avoid accidental exits. + Mod+Shift+E { quit; } + Ctrl+Alt+Delete { quit; } + + // Powers off the monitors. To turn them back on, do any input like + // moving the mouse or pressing any other key. + //Mod+Shift+P { power-off-monitors; } +} diff --git a/home/aselimov/theme/theme.nix b/home/aselimov/theme/theme.nix new file mode 100644 index 0000000..215bc61 --- /dev/null +++ b/home/aselimov/theme/theme.nix @@ -0,0 +1,91 @@ +{config, pkgs, ... }: +{ + home.file."bin/themer.sh" = { + executable = true; + text = '' + #!/usr/bin/env bash + + set_theme() { + scheme="$(${pkgs.glib}/bin/gsettings get \ + org.gnome.desktop.interface color-scheme)" + + if [[ "$scheme" == *dark* ]]; then + wallpaper="$HOME/media/pics/wall-dark.png" + fuzzel="$HOME/.config/fuzzel/themes/zenwritten-dark.ini" + mako="$HOME/.config/mako/themes/zenwritten-dark.conf" + tmux="$HOME/.config/tmux/themes/zenwritten-dark.conf" + keys=$':silent! let g:light_mode=0 | set background=dark | doautocmd ColorScheme | redraw!' + + else + wallpaper="$HOME/media/pics/wall-light.png" + fuzzel="$HOME/.config/fuzzel/themes/zenwritten-light.ini" + mako="$HOME/.config/mako/themes/zenwritten-light.conf" + tmux="$HOME/.config/tmux/themes/zenwritten-light.conf" + keys=$':silent! let g:light_mode=1 | set background=light | doautocmd ColorScheme | redraw!' + fi + + ${pkgs.awww}/bin/awww img "$wallpaper" \ + --transition-type fade \ + --transition-duration 0.4 + + ln -sf "$fuzzel" "$HOME/.config/fuzzel/colors.ini" + ln -sf "$mako" "$HOME/.config/mako/theme.conf" + ln -sf "$tmux" $HOME/.config/tmux/theme.conf + makoctl reload + tmux source-file ~/.config/tmux/theme.conf + for dir in "$XDG_RUNTIME_DIR-}" "/tmp" "$HOME/.local/state/nvim"; do + [ -d "$dir" ] || continue + find "$dir" -type s -name 'nvim*' 2>/dev/null | while read -r sock; do + timeout 1s nvim --server "$sock" --remote-send "$keys" >/dev/null 2>&1 || true + done + done + + } + + set_theme + + ${pkgs.glib}/bin/gsettings monitor \ + org.gnome.desktop.interface color-scheme | + while read -r _; do + set_theme + done + ''; + }; + home.file."media/pics/wall-light.png".source = ./wall-light.png; + home.file."media/pics/wall-dark.png".source = ./wall-dark.png; + + systemd.user.services.awww = { + Unit = { + Description = "Awww wallpaper daemon"; + After = [ "graphical-session.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${pkgs.awww}/bin/awww-daemon"; + Restart = "on-failure"; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + }; + + systemd.user.services.themer = { + Unit = { + Description = "gsettings monitor to swap light/dark themes"; + After = [ "graphical-session.target" "awww.service"]; + Requires = [ "awww.service" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "/home/aselimov/bin/themer.sh"; + Restart = "always"; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + }; +} diff --git a/home/aselimov/theme/wall-dark.png b/home/aselimov/theme/wall-dark.png new file mode 100644 index 0000000..68cb7fb Binary files /dev/null and b/home/aselimov/theme/wall-dark.png differ diff --git a/home/aselimov/theme/wall-light.png b/home/aselimov/theme/wall-light.png new file mode 100644 index 0000000..714cf05 Binary files /dev/null and b/home/aselimov/theme/wall-light.png differ diff --git a/home/aselimov/waybar/config.jsonc b/home/aselimov/waybar/config.jsonc new file mode 100644 index 0000000..ba05fb9 --- /dev/null +++ b/home/aselimov/waybar/config.jsonc @@ -0,0 +1,64 @@ +{ + "reload_style_on_change": true, + "layer": "top", + "position": "top", + "height": 28, + "spacing": 8, + "modules-left": [ + "niri/workspaces" + ], + "modules-center": [ + "clock" + ], + "modules-right": [ + "pulseaudio", + "network", + "battery", + "tray" + ], + "niri/workspaces": { + "format": "{icon}", + "format-icons": { + "active": "●", + "default": "○" + } + }, + "niri/window": { + "format": "{title}", + "max-length": 45 + }, + "clock": { + "format": "{:%a %d %H:%M}", + "tooltip-format": "{:%A, %B %d, %Y}" + }, + "pulseaudio": { + "format": "{volume}% 󰕾", + "format-muted": "mute 󰖁", + "scroll-step": 5, + "on-click": "pavucontrol" + }, + "network": { + "format-wifi": "{signalStrength}% 󰖩", + "format-ethernet": "󰈀", + "format-disconnected": "󰖪", + "tooltip-format-wifi": "{essid}" + }, + "battery": { + "format": "{capacity}% {icon}", + "format-charging": "{capacity}% 󰂄", + "format-icons": [ + "󰁺", + "󰁼", + "󰁾", + "󰂀", + "󰁹" + ], + "states": { + "warning": 25, + "critical": 10 + } + }, + "tray": { + "spacing": 8 + } +} diff --git a/home/aselimov/waybar/style-dark.css b/home/aselimov/waybar/style-dark.css new file mode 100644 index 0000000..15d9f1e --- /dev/null +++ b/home/aselimov/waybar/style-dark.css @@ -0,0 +1,67 @@ +/* Ghostty: zenwritten-dark */ + +* { + font-family: "DepartureMono Nerd Font Mono"; + font-size: 12px; + min-height: 0; +} + +window#waybar { + background: #191919; + color: #bbbbbb; + border-bottom: 1px solid #3d3839; +} + +#workspaces, +#window, +#clock, +#pulseaudio, +#network, +#battery, +#tray { + padding: 0 7px; + margin: 0; + background: transparent; +} + +#workspaces button { + padding: 0 4px; + margin: 0; + color: #8e8e8e; + background: transparent; + border: none; + box-shadow: none; +} + +#workspaces button.active { + color: #bbbbbb; +} + +#workspaces button:hover { + color: #6099c0; + background: transparent; + box-shadow: none; + text-shadow: none; +} + +#window { + color: #8e8e8e; +} + +#clock { + font-weight: bold; +} + +#battery.warning { + color: #b77e64; +} + +#battery.critical { + color: #de6e7c; +} + +tooltip { + background: #191919; + color: #bbbbbb; + border: 1px solid #3d3839; +} diff --git a/home/aselimov/waybar/style-light.css b/home/aselimov/waybar/style-light.css new file mode 100644 index 0000000..2c97f57 --- /dev/null +++ b/home/aselimov/waybar/style-light.css @@ -0,0 +1,67 @@ +/* Ghostty: zenwritten-light */ + +* { + font-family: "DepartureMono Nerd Font Mono"; + font-size: 12px; + min-height: 0; +} + +window#waybar { + background: #f0edec; + color: #4f5e68; + border-bottom: 1px solid #cfc1ba; +} + +#workspaces, +#window, +#clock, +#pulseaudio, +#network, +#battery, +#tray { + padding: 0 7px; + margin: 0; + background: transparent; +} + +#workspaces button { + padding: 0 4px; + margin: 0; + color: #4f5e68; + background: transparent; + border: none; + box-shadow: none; +} + +#workspaces button.active { + color: #2c363c; +} + +#workspaces button:hover { + color: #286486; + background: transparent; + box-shadow: none; + text-shadow: none; +} + +#window { + color: #4f5e68; +} + +#clock { + font-weight: bold; +} + +#battery.warning { + color: #944927; +} + +#battery.critical { + color: #a8334c; +} + +tooltip { + background: #f0edec; + color: #4f5e68; + border: 1px solid #cfc1ba; +} diff --git a/home/aselimov/waybar/style.css b/home/aselimov/waybar/style.css new file mode 100644 index 0000000..5d2e04d --- /dev/null +++ b/home/aselimov/waybar/style.css @@ -0,0 +1,67 @@ +/* ~/.config/waybar/style.css */ + +* { + font-family: "DepartureMono Nerd Font Mono"; + font-size: 12px; + min-height: 0; +} + +window#waybar { + background: #f0edec; + color: #4f5e68; + border-bottom: 1px solid #cfc1ba; +} + +#workspaces, +#window, +#clock, +#pulseaudio, +#network, +#battery, +#tray { + padding: 0 7px; + margin: 0; + background: transparent; +} + +#workspaces button { + padding: 0 4px; + margin: 0; + color: #4f5e68; + background: transparent; + border: none; + box-shadow: none; +} + +#workspaces button.active { + color: #2c363c; +} + +#workspaces button:hover { + color: #286486; + background: transparent; + box-shadow: none; + text-shadow: none; +} + +#window { + color: #4f5e68; +} + +#clock { + font-weight: bold; +} + +#battery.warning { + color: #944927; +} + +#battery.critical { + color: #a8334c; +} + +tooltip { + background: #f0edec; + color: #4f5e68; + border: 1px solid #cfc1ba; +} diff --git a/home/aselimov/xremap.yml b/home/aselimov/xremap.yml new file mode 100644 index 0000000..359a32d --- /dev/null +++ b/home/aselimov/xremap.yml @@ -0,0 +1,23 @@ +keymap: + - name: macOS-style shortcuts + application: + not: + - com.mitchellh.ghostty + + remap: + Super-c: Ctrl-c + Super-v: Ctrl-v + Super-x: Ctrl-x + Super-a: Ctrl-a + Super-z: Ctrl-z + Super-f: Ctrl-f + Super-s: Ctrl-s + + - name: Ghostty shortcuts + application: + only: + - com.mitchellh.ghostty + + remap: + Super-c: Ctrl-Shift-c + Super-v: Ctrl-Shift-v diff --git a/home/neovim/neovim.nix b/home/neovim/neovim.nix new file mode 100644 index 0000000..4203342 --- /dev/null +++ b/home/neovim/neovim.nix @@ -0,0 +1,22 @@ +{config, pkgs, ... }: +{ + programs.neovim = { + enable = true; + defaultEditor = true; + + extraPackages = with pkgs; [ + fd + lua-language-server + stylua + tree-sitter + clang + deno + nodejs + shellcheck + ]; + }; + xdg.configFile."nvim" = { + source = ./neovim; + recursive = true; + }; +} diff --git a/home/neovim/neovim/GoogleStyle.xml b/home/neovim/neovim/GoogleStyle.xml new file mode 100644 index 0000000..1ad1036 --- /dev/null +++ b/home/neovim/neovim/GoogleStyle.xml @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/home/neovim/neovim/README.md b/home/neovim/neovim/README.md new file mode 100644 index 0000000..bd82b25 --- /dev/null +++ b/home/neovim/neovim/README.md @@ -0,0 +1,26 @@ +# Neovim Configuration + +This is a personal Neovim configuration tailored for a variety of programming languages. It uses `lazy.nvim` for plugin management. + +## Features + +* **Plugin Manager**: Plugins are managed using [lazy.nvim](https://github.com/folke/lazy.nvim). +* **LSP**: Language Server Protocol support is provided by [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig), with LSP management through [mason.nvim](https://github.com/williamboman/mason.nvim). +* **Completion**: Autocompletion is handled by [nvim-cmp](https://github.com/hrsh7th/nvim-cmp) with [LuaSnip](https://github.com/L3MON4D3/LuaSnip) for snippets. +* **Fuzzy Finder**: [Telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) is used for fuzzy finding files, buffers, and more. +* **Formatting**: Code formatting is done with [conform.nvim](https://github.com/stevearc/conform.nvim), supporting a range of formatters. +* **Themes**: The colorscheme is [zenbones.nvim](https://github.com/zenbones-theme/zenbones.nvim). + +## Supported Languages + +This configuration has specific support for the following languages: + +* C/C++ +* CUDA +* Java +* Python +* Lua +* LaTeX +* Markdown +* Shell +* Rust diff --git a/home/neovim/neovim/ftplugin/' b/home/neovim/neovim/ftplugin/' new file mode 100644 index 0000000..b38119d --- /dev/null +++ b/home/neovim/neovim/ftplugin/' @@ -0,0 +1,8 @@ +set spell spelllang=en_us +map : w % ! md2pdf % +map : w % ! md2docx % +map : !zathura %:r.pdf & +inoremap ;i ** <++>5hi +inoremap ;b **** <++>6hi +inoremap ;I ![](<++>)6hi +inoremap ;c ``````Oi diff --git a/home/neovim/neovim/ftplugin/cpp.lua b/home/neovim/neovim/ftplugin/cpp.lua new file mode 100644 index 0000000..93eb969 --- /dev/null +++ b/home/neovim/neovim/ftplugin/cpp.lua @@ -0,0 +1,2 @@ +vim.keymap.set({ "v", "n", "i" }, "", ": CMakeBuild") +vim.keymap.set({ "v", "n", "i" }, "", ": CMakeTest") diff --git a/home/neovim/neovim/ftplugin/cuda.lua b/home/neovim/neovim/ftplugin/cuda.lua new file mode 100644 index 0000000..93eb969 --- /dev/null +++ b/home/neovim/neovim/ftplugin/cuda.lua @@ -0,0 +1,2 @@ +vim.keymap.set({ "v", "n", "i" }, "", ": CMakeBuild") +vim.keymap.set({ "v", "n", "i" }, "", ": CMakeTest") diff --git a/home/neovim/neovim/ftplugin/gitcommit.vim b/home/neovim/neovim/ftplugin/gitcommit.vim new file mode 100644 index 0000000..9d9bb91 --- /dev/null +++ b/home/neovim/neovim/ftplugin/gitcommit.vim @@ -0,0 +1,2 @@ +set colorcolumn=72 +set tw=72 diff --git a/home/neovim/neovim/ftplugin/haskell.lua b/home/neovim/neovim/ftplugin/haskell.lua new file mode 100644 index 0000000..de76f40 --- /dev/null +++ b/home/neovim/neovim/ftplugin/haskell.lua @@ -0,0 +1,2 @@ +vim.opt.sw = 2 +vim.opt.ts = 2 diff --git a/home/neovim/neovim/ftplugin/html.vim b/home/neovim/neovim/ftplugin/html.vim new file mode 100644 index 0000000..db5897d --- /dev/null +++ b/home/neovim/neovim/ftplugin/html.vim @@ -0,0 +1,12 @@ +if &ft=="markdown" + finish +endif +map : w % ! firefox % & +inoremap ;d
<++>
kkf"a +inoremap ;a <++>2F"a +inoremap ;p

O +inoremap ;b <++>2F>a +inoremap ;li
  • F>a +inoremap ;ll
    O +inoremap ;i <++>5F"i +inoremap ;s
    kO diff --git a/home/neovim/neovim/ftplugin/java.lua b/home/neovim/neovim/ftplugin/java.lua new file mode 100644 index 0000000..7aa6bc5 --- /dev/null +++ b/home/neovim/neovim/ftplugin/java.lua @@ -0,0 +1,4 @@ +vim.opt_local.shiftwidth = 2 +vim.opt_local.tabstop = 2 +vim.opt_local.tw = 100 +vim.opt_local.colorcolumn = "+1" diff --git a/home/neovim/neovim/ftplugin/javascript.lua b/home/neovim/neovim/ftplugin/javascript.lua new file mode 100644 index 0000000..9dfd152 --- /dev/null +++ b/home/neovim/neovim/ftplugin/javascript.lua @@ -0,0 +1,2 @@ +vim.opt_local.shiftwidth = 2 +vim.opt_local.tabstop = 2 diff --git a/home/neovim/neovim/ftplugin/mail.viim b/home/neovim/neovim/ftplugin/mail.viim new file mode 100644 index 0000000..ebc6c9e --- /dev/null +++ b/home/neovim/neovim/ftplugin/mail.viim @@ -0,0 +1 @@ +set textwidth=0 diff --git a/home/neovim/neovim/ftplugin/markdown.vim b/home/neovim/neovim/ftplugin/markdown.vim new file mode 100644 index 0000000..62f3455 --- /dev/null +++ b/home/neovim/neovim/ftplugin/markdown.vim @@ -0,0 +1,20 @@ +set spell spellfile="~/.config/nvim/spell/wordlist" +setlocal conceallevel=0 +setlocal concealcursor= +let g:markdown_fenced_languages = ['html', 'python', 'bash=sh', 'fortran'] +let g:vim_markdown_math = 1 +let g:tex_conceal = "abdmg" +let g:tex_superscripts= "[]" +let g:tex_subscripts= "[]" +let g:tex_conceal_frac=1 +hi clear Conceal +map : w % AsyncRun md2pdf "%" +map : w % AsyncRun md2beamer "%" +map : w % AsyncRun md2docx % +map : !zathura %:r.pdf & +inoremap b ****hi +inoremap i **i +command Stab Tabularize /\s\+\zs\s/l1c0 +nnoremap ;t :Tabularize /\s\+\zs\s/l1c0 +set tw=1000 +set colorcolumn= diff --git a/home/neovim/neovim/ftplugin/python.lua b/home/neovim/neovim/ftplugin/python.lua new file mode 100644 index 0000000..dd78580 --- /dev/null +++ b/home/neovim/neovim/ftplugin/python.lua @@ -0,0 +1,4 @@ +vim.opt_local.colorcolumn = "88" +vim.opt_local.textwidth = 1000 +vim.keymap.set("n", "x", "[hv]h]hk$;sc", { buffer = true }) +vim.keymap.set("n", "r", ":!python3 %", { buffer = true }) diff --git a/home/neovim/neovim/ftplugin/sh.lua b/home/neovim/neovim/ftplugin/sh.lua new file mode 100644 index 0000000..5093592 --- /dev/null +++ b/home/neovim/neovim/ftplugin/sh.lua @@ -0,0 +1,37 @@ +vim.opt_local.colorcolumn = "100" +vim.opt_local.textwidth = 100 +vim.opt_local.expandtab = true + +local function detect_indent(bufnr) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, 100, false) + local counts = {} + for _, line in ipairs(lines) do + local spaces = line:match("^( +)[^ ]") + if spaces then + local n = #spaces + counts[n] = (counts[n] or 0) + 1 + end + end + -- find the smallest indent size with meaningful usage + for _, size in ipairs({ 2, 4, 8 }) do + if (counts[size] or 0) > 0 then + return size + end + end + return 4 -- default +end + +local bufnr = vim.api.nvim_get_current_buf() +local size = detect_indent(bufnr) + +vim.opt_local.shiftwidth = size +vim.opt_local.tabstop = size +vim.opt_local.softtabstop = size + +-- update beautysh indent size for this buffer +local ok, conform = pcall(require, "conform") +if ok then + conform.formatters.beautysh = { + prepend_args = { "--indent-size", tostring(size) }, + } +end diff --git a/home/neovim/neovim/ftplugin/tex.vim b/home/neovim/neovim/ftplugin/tex.vim new file mode 100644 index 0000000..b9b19a5 --- /dev/null +++ b/home/neovim/neovim/ftplugin/tex.vim @@ -0,0 +1,21 @@ +set spell +set spelllang=en_us +map : w % make! +map : !make read & +inoremap ;f \begin{figure}\centering\includegraphics[]{<++>}\caption{<++>}\end{figure}2kf[a +inoremap ;2f \begin{figure}\centering\begin{subfigure}[t]{0.49\textwidth}\centering\includegraphics[width=\textwidth]{<++>}\caption{<++>}\end{subfigure}\begin{subfigure}[t]{0.49\textwidth}\centering\includegraphics[width=\textwidth]{<++>}\caption{<++>}\end{subfigure}\end{figure}8k/<++>"_c4l +inoremap ;3f \begin{figure}\centering\begin{subfigure}[t]{0.32\textwidth}\centering\includegraphics[width=\textwidth]{<++>}\caption{<++>}\end{subfigure}\begin{subfigure}[t]{0.32\textwidth}\centering\includegraphics[width=\textwidth]{<++>}\caption{<++>}\end{subfigure}\begin{subfigure}[t]{0.32\textwidth}\centering\includegraphics[width=\textwidth]{<++>}\caption{<++>}\end{subfigure}\end{figure}13k/<++>"_c4l +inoremap ;F \begin{frame}{<++>}\end{frame}O<++>-i +inoremap ;b \textbf{} <++>F{a +inoremap ;c \caption{}i +inoremap ;C \begin{columns}\column{0.49\textwidth}\column{0.49\textwidth}<++>\end{columns}2kO +inoremap ;ig \includegraphics[width=\textwidth]{<++>}16hi +inoremap ;li \begin{itemize}\item\end{itemize}kA +inoremap ;le \begin{enumerate}\item\end{enumerate}kA +inoremap ;ll \item +inoremap ;2t \begin{table}[h!]\begin{center}\begin{tabular}{c c} \toprule\textbf{} & \textbf{<++>} \\\midrule<++> & <++> \\\bottomrule\end{tabular}\end{center}\end{table}6kf{a +inoremap ;e \begin{equation}\label{<++>}\end{equation}kO +inoremap ;fw width=\textwidthF\i +inoremap ;fh height=\textheightF\i + +set tw=5000 diff --git a/home/neovim/neovim/ftplugin/typescript.lua b/home/neovim/neovim/ftplugin/typescript.lua new file mode 100644 index 0000000..9dfd152 --- /dev/null +++ b/home/neovim/neovim/ftplugin/typescript.lua @@ -0,0 +1,2 @@ +vim.opt_local.shiftwidth = 2 +vim.opt_local.tabstop = 2 diff --git a/home/neovim/neovim/init.lua b/home/neovim/neovim/init.lua new file mode 100644 index 0000000..7dc21e8 --- /dev/null +++ b/home/neovim/neovim/init.lua @@ -0,0 +1,38 @@ +-- set to true for light mode +local handle = io.popen( + "gsettings get org.gnome.desktop.interface color-scheme" +) + +if handle then + local scheme = handle:read("*a") + handle:close() + + if scheme:match("prefer%-dark") then + vim.g.light_mode = false + else + vim.g.light_mode = true + end +end +vim.g.vim_markdown_conceal = 0 + +-- Neovim configuration +-- Modularized structure for better organization + +-- Load core configuration +require("config.options") +require("config.keymaps") +require("config.autocmds") +require("config.lazy") + +-- Setup lazy.nvim and load plugins +require("lazy").setup({ + -- Import all plugin configurations + { import = "plugins" }, +}) + +-- Load additional configuration +require("colorizer").setup() +require("config.formatting") + +-- Add configuration to listen so we can live reload +pcall(vim.fn.serverstart, vim.fn.stdpath("run") .. "/nvim-" .. vim.fn.getpid()) diff --git a/home/neovim/neovim/lazy-lock.json b/home/neovim/neovim/lazy-lock.json new file mode 100644 index 0000000..dd40571 --- /dev/null +++ b/home/neovim/neovim/lazy-lock.json @@ -0,0 +1,50 @@ +{ + "LuaSnip": { "branch": "master", "commit": "a62e1083a3cfe8b6b206e7d3d33a51091df25357" }, + "asyncrun.vim": { "branch": "master", "commit": "98d3c0fdeb983f0ef62fe3a49da440f6d2c045ce" }, + "claude-code.nvim": { "branch": "main", "commit": "55c0cb59828fbc3bec744288286a46f5d5750b83" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" }, + "cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" }, + "cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" }, + "conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" }, + "fidget.nvim": { "branch": "main", "commit": "889e2e96edef4e144965571d46f7a77bcc4d0ddf" }, + "git-blame.nvim": { "branch": "main", "commit": "5c536e2d4134d064aa3f41575280bc8a2a0e03d7" }, + "iron.nvim": { "branch": "master", "commit": "88cd340407b959f1168af2a6ae5a3d180e6df32c" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, + "lush.nvim": { "branch": "main", "commit": "9c60ec2279d62487d942ce095e49006af28eed6e" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "0a3b42c3e503df87aef6d6513e13148381495c3a" }, + "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, + "mason.nvim": { "branch": "main", "commit": "b03fb0f20bc1d43daf558cda981a2be22e73ac42" }, + "mini.nvim": { "branch": "main", "commit": "29447d7b0e1fc9bc9d0384953e63be3fae816736" }, + "neogen": { "branch": "main", "commit": "b2e78708876f4da507839726816010a68e33fec8" }, + "nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" }, + "nvim-cmp": { "branch": "main", "commit": "a1d504892f2bc56c2e79b65c6faded2fd21f3eca" }, + "nvim-colorizer.lua": { "branch": "master", "commit": "5cfe7fffbd01e17b3c1e14af85d5febdef88bd8c" }, + "nvim-jdtls": { "branch": "master", "commit": "77ccaeb422f8c81b647605da5ddb4a7f725cda90" }, + "nvim-lspconfig": { "branch": "master", "commit": "4b7fbaa239c5db6b36f424a4521ca9f1a401be33" }, + "nvim-markdown": { "branch": "master", "commit": "37850581fdaec153ce84af677d43bf8fce60813a" }, + "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, + "nvim-web-devicons": { "branch": "master", "commit": "c72328a5494b4502947a022fe69c0c47e53b6aa6" }, + "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, + "rainbow_csv": { "branch": "master", "commit": "3dbbfd7d17536aebfb80f571255548495574c32b" }, + "render-markdown.nvim": { "branch": "main", "commit": "0fd43fb4b1f073931c4b481f5f3b7cea3749e190" }, + "runst.nvim": { "branch": "main", "commit": "9760caf73d8f020b6054d34f5527a85836a11a24" }, + "rustaceanvim": { "branch": "master", "commit": "88575b98bb9937fb9983ddec5e532b67e75ce677" }, + "snacks.nvim": { "branch": "main", "commit": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e" }, + "tabular": { "branch": "master", "commit": "12437cd1b53488e24936ec4b091c9324cafee311" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, + "telescope-live-grep-args.nvim": { "branch": "master", "commit": "53e9df55b3651dd7cf77e172f1e8c9a17407acca" }, + "telescope.nvim": { "branch": "master", "commit": "471eebb1037899fd942cc0f52c012f8773505da1" }, + "tex-conceal.vim": { "branch": "master", "commit": "93ae39d9222b0892684d02324b85ee9d3647bf8e" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" }, + "vim-abolish": { "branch": "master", "commit": "dcbfe065297d31823561ba787f51056c147aa682" }, + "vim-cmake": { "branch": "master", "commit": "896bc2189c8ade62d00a0ebedc59c65d9d9b0d65" }, + "vim-gitgutter": { "branch": "main", "commit": "21c977e8597c468c7dc76001389b0b430d46a4b0" }, + "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" }, + "vim-table-mode": { "branch": "master", "commit": "bb025308a45c67c7c8f0763ba37bc2ee3f534df0" }, + "vim-textobj-hydrogen": { "branch": "master", "commit": "e6f9a6b26a3524615bac347503c35327636fab72" }, + "vim-textobj-user": { "branch": "master", "commit": "41a675ddbeefd6a93664a4dc52f302fe3086a933" }, + "vim-tmux-navigator": { "branch": "master", "commit": "e41c431a0c7b7388ae7ba341f01a0d217eb3a432" }, + "windsurf.vim": { "branch": "main", "commit": "a8d47ec54fe82df920b2545559f767003e8a7f8d" }, + "zenbones.nvim": { "branch": "main", "commit": "22b7fb75593412e0dc81b4bdefae718e9e84aa82" } +} diff --git a/home/neovim/neovim/lua/autopair.lua b/home/neovim/neovim/lua/autopair.lua new file mode 100644 index 0000000..acd6975 --- /dev/null +++ b/home/neovim/neovim/lua/autopair.lua @@ -0,0 +1,62 @@ +local remap = vim.api.nvim_set_keymap +local npairs = require('nvim-autopairs') + +npairs.setup({ map_bs = false, map_cr = false }) + +vim.g.coq_settings = { keymap = { recommended = false } } + +-- these mappings are coq recommended mappings unrelated to nvim-autopairs +remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) +remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) +remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) +remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) + +-- skip it, if you use another global object +_G.MUtils= {} + +MUtils.CR = function() + if vim.fn.pumvisible() ~= 0 then + if vim.fn.complete_info({ 'selected' }).selected ~= -1 then + return npairs.esc('') + else + return npairs.esc('') .. npairs.autopairs_cr() + end + else + return npairs.autopairs_cr() + end +end +remap('i', '', 'v:lua.MUtils.CR()', { expr = true, noremap = true }) + +MUtils.BS = function() + if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info({ 'mode' }).mode == 'eval' then + return npairs.esc('') .. npairs.autopairs_bs() + else + return npairs.autopairs_bs() + end +end +remap('i', '', 'v:lua.MUtils.BS()', { expr = true, noremap = true }) + + +-- put this to setup function and press to use fast_wrap +npairs.setup({ + fast_wrap = {}, +}) + +-- change default fast_wrap +npairs.setup({ + fast_wrap = { + map = '', + chars = { '{', '[', '(', '"', "'" }, + pattern = [=[[%'%"%>%]%)%}%,]]=], + end_key = '$', + before_key = 'h', + after_key = 'l', + cursor_pos_before = true, + keys = 'qwertyuiopzxcvbnmasdfghjkl', + manual_position = true, + highlight = 'Search', + highlight_grey='Comment' + }, +}) + +npairs.remove_rule('`') diff --git a/home/neovim/neovim/lua/config/autocmds.lua b/home/neovim/neovim/lua/config/autocmds.lua new file mode 100644 index 0000000..d1c5449 --- /dev/null +++ b/home/neovim/neovim/lua/config/autocmds.lua @@ -0,0 +1,35 @@ +-- Autocmds configuration + +-- Disable semantic tokens +vim.api.nvim_create_autocmd("LspAttach", { + callback = function(args) + local client = vim.lsp.get_client_by_id(args.data.client_id) + client.server_capabilities.semanticTokensProvider = nil + end, +}) + +-- Go back to last edited line when reopening file +vim.api.nvim_create_autocmd("BufRead", { + callback = function(opts) + vim.api.nvim_create_autocmd("BufWinEnter", { + once = true, + buffer = opts.buf, + callback = function() + local ft = vim.bo[opts.buf].filetype + local last_known_line = vim.api.nvim_buf_get_mark(opts.buf, '"')[1] + if + not (ft:match("gitcommit") and ft:match("gitrebase")) + and last_known_line > 1 + and last_known_line <= vim.api.nvim_buf_line_count(opts.buf) + then + vim.api.nvim_feedkeys([[g`"]], "nx", false) + end + end, + }) + end, +}) + +-- Disable semantic highlights +for _, group in ipairs(vim.fn.getcompletion("@lsp", "highlight")) do + vim.api.nvim_set_hl(0, group, {}) +end \ No newline at end of file diff --git a/home/neovim/neovim/lua/config/formatting.lua b/home/neovim/neovim/lua/config/formatting.lua new file mode 100644 index 0000000..5a4a5fb --- /dev/null +++ b/home/neovim/neovim/lua/config/formatting.lua @@ -0,0 +1,32 @@ +-- Formatting configuration + +-- Commands to disable/enable formatting +require("conform").setup({ + format_on_save = function(bufnr) + -- Disable with a global or buffer-local variable + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + return { timeout_ms = 500, lsp_fallback = true } + end, +}) + +vim.api.nvim_create_user_command("FormatDisable", function(args) + if args.bang then + -- FormatDisable! will disable formatting just for this buffer + vim.b.disable_autoformat = true + else + vim.g.disable_autoformat = true + end +end, { + desc = "Disable autoformat-on-save", + bang = true, +}) + +vim.api.nvim_create_user_command("FormatEnable", function() + vim.b.disable_autoformat = false + vim.g.disable_autoformat = false +end, { + desc = "Re-enable autoformat-on-save", +}) + diff --git a/home/neovim/neovim/lua/config/keymaps.lua b/home/neovim/neovim/lua/config/keymaps.lua new file mode 100644 index 0000000..d831f0a --- /dev/null +++ b/home/neovim/neovim/lua/config/keymaps.lua @@ -0,0 +1,20 @@ +-- Keymaps configuration + +-- Clear search highlight +vim.keymap.set("n", "", "nohlsearch") + +-- Diagnostic keymaps +vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Go to previous [D]iagnostic message" }) +vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Go to next [D]iagnostic message" }) +vim.keymap.set("n", "e", vim.diagnostic.open_float, { desc = "Show diagnostic [E]rror messages" }) +vim.keymap.set("n", "q", vim.diagnostic.setloclist, { desc = "Open diagnostic [Q]uickfix list" }) + +-- Window navigation +vim.keymap.set("n", "", "", { desc = "Move focus to the left window" }) +vim.keymap.set("n", "", "", { desc = "Move focus to the right window" }) +vim.keymap.set("n", "", "", { desc = "Move focus to the lower window" }) +vim.keymap.set("n", "", "", { desc = "Move focus to the upper window" }) + +-- LSP keymaps +vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Goto Definition" }) + diff --git a/home/neovim/neovim/lua/config/lazy.lua b/home/neovim/neovim/lua/config/lazy.lua new file mode 100644 index 0000000..0f79ac9 --- /dev/null +++ b/home/neovim/neovim/lua/config/lazy.lua @@ -0,0 +1,16 @@ +-- Lazy.nvim plugin manager setup + +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not vim.loop.fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) +end +vim.opt.rtp:prepend(lazypath) + +-- User dictionary for spell checking +local path = vim.fn.stdpath("config") .. "/spell/en.utf-8.add" +local words = {} + +for word in io.open(path, "r"):lines() do + table.insert(words, word) +end \ No newline at end of file diff --git a/home/neovim/neovim/lua/config/options.lua b/home/neovim/neovim/lua/config/options.lua new file mode 100644 index 0000000..ad92aef --- /dev/null +++ b/home/neovim/neovim/lua/config/options.lua @@ -0,0 +1,44 @@ +-- Options configuration +vim.g.mapleader = ";" +vim.g.maplocalleader = ";" + +-- Line numbers +vim.opt.number = true +vim.opt.relativenumber = true + +-- Mouse +vim.opt.mouse = "" + +-- Mode display +vim.opt.showmode = false + +-- Search +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.hlsearch = true + +-- Sign column +vim.opt.signcolumn = "yes" + +-- Splits +vim.opt.splitright = true +vim.opt.splitbelow = true + +-- Whitespace display +vim.opt.list = true +vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } + +-- Live substitution preview +vim.opt.inccommand = "split" + +-- Cursor line +vim.opt.cursorline = true + +-- General settings +vim.opt.shiftwidth = 4 +vim.opt.tabstop = 4 +vim.opt.expandtab = true +vim.opt.tw = 100 +vim.opt.colorcolumn = "+1" +vim.opt.termguicolors = true +vim.opt.pumheight = 5 diff --git a/home/neovim/neovim/lua/iron.lua b/home/neovim/neovim/lua/iron.lua new file mode 100644 index 0000000..73bad0c --- /dev/null +++ b/home/neovim/neovim/lua/iron.lua @@ -0,0 +1,45 @@ +local iron = require("iron.core") +local view = require("iron.view") + +iron.setup { + config = { + -- Whether a repl should be discarded or not + scratch_repl = true, + -- Your repl definitions come here + repl_definition = { + python = { + -- Can be a table or a function that + -- returns a table (see below) + command = "ipython --no-autoindent" + } + }, + -- How the repl window will be displayed + -- See below for more information + repl_open_cmd = require('iron.view').bottom(20), + }, + -- Iron doesn't set keymaps by default anymore. + -- You can set them here or manually add keymaps to the functions in iron.core + keymaps = { + visual_send = ";sc", + send_file = ";sf", + send_line = ";sl", + cr = ";s", + interrupt = ";s", + exit = ";sq", + clear = ";cl", + }, + -- If the highlight is on, you can change how it looks + -- For the available options, check nvim_set_hl + highlight = { + italic = true + }, + ignore_blank_lines = true, -- ignore blank lines when sending visual select lines +} + +-- iron also has a list of commands, see :h iron-commands for all available commands +vim.keymap.set('n', ';rs', 'IronRepl') +vim.keymap.set('n', ';rr', 'IronRestart') +vim.keymap.set('n', ';rf', 'IronFocus') +vim.keymap.set('n', ';rh', 'IronHide') + +repl_open_cmd = "horizontal bot 20 split" diff --git a/home/neovim/neovim/lua/plugins/autopairs.lua b/home/neovim/neovim/lua/plugins/autopairs.lua new file mode 100644 index 0000000..afc64f8 --- /dev/null +++ b/home/neovim/neovim/lua/plugins/autopairs.lua @@ -0,0 +1,59 @@ +-- Autopairs plugin configuration + +return { + "windwp/nvim-autopairs", + config = function() + local remap = vim.api.nvim_set_keymap + local npairs = require("nvim-autopairs") + + npairs.setup({ map_bs = false, map_cr = false }) + + _G.MUtils = {} + + MUtils.CR = function() + if vim.fn.pumvisible() ~= 0 then + if vim.fn.complete_info({ "selected" }).selected ~= -1 then + return npairs.esc("") + else + return npairs.esc("") .. npairs.autopairs_cr() + end + else + return npairs.autopairs_cr() + end + end + remap("i", "", "v:lua.MUtils.CR()", { expr = true, noremap = true }) + + MUtils.BS = function() + if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info({ "mode" }).mode == "eval" then + return npairs.esc("") .. npairs.autopairs_bs() + else + return npairs.autopairs_bs() + end + end + remap("i", "", "v:lua.MUtils.BS()", { expr = true, noremap = true }) + + -- put this to setup function and press to use fast_wrap + npairs.setup({ + fast_wrap = {}, + }) + + -- change default fast_wrap + npairs.setup({ + fast_wrap = { + map = "", + chars = { "{", "[", "(", '"', "'" }, + pattern = [=[[%'%"%>%]%)%}%,]]=], + end_key = "$", + before_key = "h", + after_key = "l", + cursor_pos_before = true, + keys = "qwertyuiopzxcvbnmasdfghjkl", + manual_position = true, + highlight = "Search", + highlight_grey = "Comment", + }, + }) + + npairs.remove_rule("`") + end, +} \ No newline at end of file diff --git a/home/neovim/neovim/lua/plugins/completion.lua b/home/neovim/neovim/lua/plugins/completion.lua new file mode 100644 index 0000000..660df97 --- /dev/null +++ b/home/neovim/neovim/lua/plugins/completion.lua @@ -0,0 +1,137 @@ +-- Completion and snippets configuration + +return { + { + "hrsh7th/nvim-cmp", + event = "InsertEnter", + dependencies = { + { + "L3MON4D3/LuaSnip", + build = (function() + if vim.fn.has("win32") == 1 or vim.fn.executable("make") == 0 then + return + end + return "make install_jsregexp" + end)(), + config = function() + require("luasnip.loaders.from_snipmate").lazy_load({ paths = "./snippets" }) + local ls = require("luasnip") + + vim.keymap.set({ "i", "s" }, "j", function() + if ls.expand_or_locally_jumpable() then + ls.expand_or_jump() + end + end, { silent = true }) + vim.keymap.set({ "i", "s" }, "k", function() + if ls.locally_jumpable(-1) then + ls.jump(-1) + end + end, { silent = true }) + + local snip = ls.snippet + local node = ls.snippet_node + local text = ls.text_node + local insert = ls.insert_node + local func = ls.function_node + local choice = ls.choice_node + local dynamicn = ls.dynamic_node + + ls.add_snippets(nil, { + python = { + snip({ + trig = "imp", + namr = "Imports", + dscr = "Comments for imports", + }, { + text({ "# Core modules", "" }), + insert(1), + text({ "", "# Non-core modules", "" }), + insert(2), + text({ "", "# SEI modules", "" }), + insert(3), + }), + }, + tex = { + snip({ + trig = "input", + namr = "Input Cell", + dscr = "Cell for SEIInputTable", + }, { + text({ "\\hypertarget{" }), + insert(1), + text({ "}{" }), + insert(2), + text({ "} & \\SEICell{", "\t" }), + insert(3), + text({ "", "}\\\\", "" }), + }), + }, + markdown = { + snip({ + trig = "img", + namr = "image", + dscr = "Markdown img", + }, { + text({ "![" }), + insert(1), + text("]("), + insert(2), + text(")"), + }), + snip({ + trig = "header", + namr = "header", + dscr = "Yaml header for markdown notes", + }, { + text({ "---", "" }), + text("title: "), + insert(1), + text({ "", "author: Alex Selimov", "" }), + text("tags: ["), + insert(2), + text({ "]", "", "" }), + text({ "---", "" }), + }), + }, + }) + end, + }, + "saadparwaiz1/cmp_luasnip", + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-path", + }, + config = function() + local cmp = require("cmp") + local luasnip = require("luasnip") + luasnip.config.setup({}) + cmp.setup({ + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + completion = { completeopt = "menu,menuone,noinsert" }, + + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.select_prev_item(), + [""] = cmp.mapping.confirm({ select = true }), + }), + sources = { + { name = "nvim_lsp" }, + { name = "luasnip" }, + { name = "path" }, + }, + }) + end, + snippet = { + expand = function(args) + local luasnip = require("luasnip") + if not luasnip then + return + end + luasnip.lsp_expand(args.body) + end, + }, + }, +} \ No newline at end of file diff --git a/home/neovim/neovim/lua/plugins/dev-tools.lua b/home/neovim/neovim/lua/plugins/dev-tools.lua new file mode 100644 index 0000000..94c606e --- /dev/null +++ b/home/neovim/neovim/lua/plugins/dev-tools.lua @@ -0,0 +1,74 @@ +-- Development tools and utilities + +return { + { + "codersauce/runst.nvim", + lazy = false, + opts = {}, + config = function() + require("runst").setup() + end, + }, + + { + "mrcjkb/rustaceanvim", + version = "^6", -- Recommended + lazy = false, -- This plugin is already lazy + }, + + { + "cdelledonne/vim-cmake", + cond = vim.fn.executable("cmake") == 1, + }, + + { + "f-person/git-blame.nvim", + opts = { + enabled = false, + message_template = "<> • ", + }, + }, + + { + "Exafunction/windsurf.vim", + event = "BufEnter", + cond = os.getenv("NVIM_USE_WINDSURF") == "true", + }, + + { + "danymat/neogen", + setup = { + snippet_engine = "luasnip", + }, + config = function() + require("neogen").setup({}) + local opts = { noremap = true, silent = true } + vim.api.nvim_set_keymap("n", "dg", ":lua require('neogen').generate()", opts) + end, + version = "*", + }, + { + "greggh/claude-code.nvim", + dependencies = { + "nvim-lua/plenary.nvim", -- Required for git operations + }, + config = function() + require("claude-code").setup({ + window = { + split_ratio = 0.3, -- Percentage of screen for the terminal window (height for horizontal, width for vertical splits) + position = "vertical", -- Position of the window: "botright", "topleft", "vertical", "float", etc. + }, + keymaps = { + toggle = { + normal = "cc", -- Normal mode keymap for toggling Claude Code, false to disable + terminal = "cc", -- Terminal mode keymap for toggling Claude Code, false to disable + variants = { + continue = "cC", -- Normal mode keymap for Claude Code with continue flag + verbose = "cV", -- Normal mode keymap for Claude Code with verbose flag + }, + }, + }, + }) + end, + }, +} diff --git a/home/neovim/neovim/lua/plugins/editor.lua b/home/neovim/neovim/lua/plugins/editor.lua new file mode 100644 index 0000000..b385e85 --- /dev/null +++ b/home/neovim/neovim/lua/plugins/editor.lua @@ -0,0 +1,23 @@ +-- Editor enhancement plugins + +return { + "christoomey/vim-tmux-navigator", + "kana/vim-textobj-user", + "mechatroner/rainbow_csv", + { + "GCBallesteros/vim-textobj-hydrogen", + dependencies = { + "kana/vim-textobj-user", + }, + }, + "godlygeek/tabular", + "tpope/vim-sleuth", + "catgoose/nvim-colorizer.lua", + { "ixru/nvim-markdown", ft = "markdown" }, + "KeitaNakamura/tex-conceal.vim", + "skywind3000/asyncrun.vim", + "airblade/vim-gitgutter", + "tpope/vim-abolish", + "dhruvasagar/vim-table-mode", +} + diff --git a/home/neovim/neovim/lua/plugins/formatting.lua b/home/neovim/neovim/lua/plugins/formatting.lua new file mode 100644 index 0000000..1faa2a2 --- /dev/null +++ b/home/neovim/neovim/lua/plugins/formatting.lua @@ -0,0 +1,40 @@ +-- Formatting plugins + +return { + { + "stevearc/conform.nvim", + opts = { + notify_on_error = false, + format_on_save = { + timeout_ms = 2500, + lsp_fallback = true, + }, + formatters = { + beautysh = { + prepend_args = { "--indent-size", "2" }, + }, + golines = { + prepend_args = { + "--max-len=100", + "--base-formatter=gofmt", + }, + }, + }, + formatters_by_ft = { + lua = { "stylua" }, + python = { "ruff_format" }, + cpp = { "clang-format" }, + c = { "clang-format" }, + sh = { "beautysh" }, + tex = { "latexindent" }, + java = { "google-java-format" }, + javascript = { "prettier" }, + typescript = { "deno_fmt" }, + typescriptreact = { "deno_fmt" }, + svelte = { "deno_fmt" }, + json = { "prettier" }, + go = { "golines" }, + }, + }, + }, +} diff --git a/home/neovim/neovim/lua/plugins/iron.lua b/home/neovim/neovim/lua/plugins/iron.lua new file mode 100644 index 0000000..7defb3d --- /dev/null +++ b/home/neovim/neovim/lua/plugins/iron.lua @@ -0,0 +1,51 @@ +-- Iron REPL plugin configuration + +return { + "Vigemus/iron.nvim", + ft = { "python" }, + config = function() + local iron = require("iron.core") + local view = require("iron.view") + + iron.setup({ + config = { + -- Whether a repl should be discarded or not + scratch_repl = true, + -- Your repl definitions come here + repl_definition = { + python = { + -- Can be a table or a function that + -- returns a table (see below) + command = "ipython --no-autoindent", + }, + }, + -- How the repl window will be displayed + -- See below for more information + repl_open_cmd = require("iron.view").bottom(20), + }, + -- Iron doesn't set keymaps by default anymore. + -- You can set them here or manually add keymaps to the functions in iron.core + keymaps = { + visual_send = "sc", + send_file = "sf", + send_line = "sl", + cr = "s", + interrupt = "s", + exit = "sq", + clear = "cl", + }, + -- If the highlight is on, you can change how it looks + -- For the available options, check nvim_set_hl + highlight = { + italic = true, + }, + ignore_blank_lines = false, -- ignore blank lines when sending visual select lines + }) + vim.keymap.set("n", ";rs", "IronRepl") + vim.keymap.set("n", ";rr", "IronRestart") + vim.keymap.set("n", ";rf", "IronFocus") + vim.keymap.set("n", ";rh", "IronHide") + + repl_open_cmd = "horizontal bot 20 split" + end, +} \ No newline at end of file diff --git a/home/neovim/neovim/lua/plugins/lsp.lua b/home/neovim/neovim/lua/plugins/lsp.lua new file mode 100644 index 0000000..6bcd67b --- /dev/null +++ b/home/neovim/neovim/lua/plugins/lsp.lua @@ -0,0 +1,262 @@ +-- LSP configuration + +return { + { + "mfussenegger/nvim-jdtls", + ft = "java", + config = function() + local jdtls = require("jdtls") + + -- Find project root + local root_dir = require("jdtls.setup").find_root({ ".git", "mvnw", "gradlew" }) + + -- Path to your exported Eclipse/IntelliJ style xml + local style_path = vim.fn.expand("~/.config/nvim/formatters/eclipse-java-google-style.xml") + + local java_home = os.getenv("NVIM_JDTLS_JAVA_HOME") + + local config = { + cmd = { + java_home .. "/bin/java", + "-Declipse.application=org.eclipse.jdt.ls.core.id1", + "-Dosgi.bundles.defaultStartLevel=4", + "-Declipse.product=org.eclipse.jdt.ls.core.product", + "-Dlog.protocol=true", + "-Dlog.level=ALL", + "-Xms1g", + "--add-modules=ALL-SYSTEM", + "--add-opens", + "java.base/java.util=ALL-UNNAMED", + "--add-opens", + "java.base/java.lang=ALL-UNNAMED", + "-jar", + vim.fn.glob( + vim.fn.stdpath("data") .. "/mason/packages/jdtls/plugins/org.eclipse.equinox.launcher_*.jar" + ), + "-configuration", + vim.fn.glob(vim.fn.stdpath("data") .. "/mason/packages/jdtls/config_mac"), + "-data", + vim.fn.expand("~/.cache/jdtls-workspace/") .. "/" .. root_dir:gsub(":", "_"), + }, + root_dir = root_dir, + settings = { + java = { + format = { + enabled = false, + }, + }, + }, + } + + jdtls.start_or_attach(config) + end, + }, + + { + "neovim/nvim-lspconfig", + opts = { + autoformat = false, + }, + dependencies = { + "williamboman/mason.nvim", + "williamboman/mason-lspconfig.nvim", + "WhoIsSethDaniel/mason-tool-installer.nvim", + { "j-hui/fidget.nvim", opts = {} }, + }, + config = function() + local util = require("lspconfig.util") + + vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("kickstart-lsp-attach", { clear = true }), + callback = function(event) + local map = function(keys, func, desc) + vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP: " .. desc }) + end + + map("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") + map("I", require("telescope.builtin").lsp_implementations, "[G]oto [I]mplementation") + map("D", require("telescope.builtin").lsp_type_definitions, "Type [D]efinition") + map("ds", require("telescope.builtin").lsp_document_symbols, "[D]ocument [S]ymbols") + map( + "ws", + require("telescope.builtin").lsp_dynamic_workspace_symbols, + "[W]orkspace [S]ymbols" + ) + map("rn", vim.lsp.buf.rename, "[R]e[n]ame") + map("ca", vim.lsp.buf.code_action, "[C]ode [A]ction") + map("K", vim.lsp.buf.hover, "Hover Documentation") + map("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") + + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client and client.server_capabilities.documentHighlightProvider then + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { + buffer = event.buf, + callback = vim.lsp.buf.document_highlight, + }) + + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + buffer = event.buf, + callback = vim.lsp.buf.clear_references, + }) + end + end, + }) + + local capabilities = vim.lsp.protocol.make_client_capabilities() + capabilities = vim.tbl_deep_extend("force", capabilities, require("cmp_nvim_lsp").default_capabilities()) + + local function is_executable(path) + return path and vim.fn.executable(path) == 1 + end + + local function get_python_path(root_dir) + local candidates = {} + local active_venv = os.getenv("VIRTUAL_ENV") + + if root_dir then + vim.list_extend(candidates, { + util.path.join(root_dir, ".venv", "bin", "python"), + util.path.join(root_dir, "venv", "bin", "python"), + }) + end + + if active_venv then + table.insert(candidates, util.path.join(active_venv, "bin", "python")) + end + + table.insert(candidates, vim.fn.exepath("python3")) + table.insert(candidates, vim.fn.exepath("python")) + + for _, path in ipairs(candidates) do + if is_executable(path) then + return path + end + end + end + + local servers = { + clangd = { + filetypes = { + "c", + "cpp", + "cuda", + }, + }, + yamlls = { settings = { yaml = { format = { enable = true } } } }, + pyright = { + root_dir = util.root_pattern( + "pyproject.toml", + "uv.lock", + "setup.py", + "setup.cfg", + "requirements.txt", + ".git" + ), + before_init = function(_, config) + local python_path = get_python_path(config.root_dir) + config.settings = vim.tbl_deep_extend("force", config.settings or {}, { + python = { + pythonPath = python_path, + analysis = { + autoSearchPaths = true, + useLibraryCodeForTypes = true, + }, + }, + }) + end, + }, + ruff = { + on_attach = function(client) + client.server_capabilities.documentFormattingProvider = false + end, + }, + jsonls = {}, + denols = {}, + svelte = {}, + arduino_language_server = {}, + zls = {}, + ltex = { + settings = { + ltex = { + enabled = { "latex", "tex", "bib", "markdown" }, + language = "auto", + diagnosticSeverity = "information", + sentenceCacheSize = 2000, + latex = { + commands = { + ["\\hypertarget"] = "dummy", + }, + }, + dictionary = (function() + local files = {} + for _, file in ipairs(vim.api.nvim_get_runtime_file("dict/*", true)) do + local lang = vim.fn.fnamemodify(file, ":t:r") + local fullpath = vim.fs.normalize(file, ":p") + files[lang] = { ":" .. fullpath } + end + + if files.default then + for lang, _ in pairs(files) do + if lang ~= "default" then + vim.list_extend(files[lang], files.default) + end + end + files.default = nil + end + return files + end)(), + }, + }, + }, + lua_ls = { + settings = { + Lua = { + runtime = { version = "LuaJIT" }, + workspace = { + checkThirdParty = false, + library = { + "${3rd}/luv/library", + unpack(vim.api.nvim_get_runtime_file("", true)), + }, + }, + }, + }, + }, + } + + require("mason").setup() + + local ensure_installed = vim.tbl_keys(servers or {}) + vim.list_extend(ensure_installed, { + "jdtls", + "stylua", + "ruff", + "clang-format", + "beautysh", + "latexindent", + "prettier", + }) + require("mason-tool-installer").setup({ ensure_installed = ensure_installed }) + + require("mason-lspconfig").setup({ + handlers = { + function(server_name) + local server = servers[server_name] or {} + require("lspconfig")[server_name].setup({ + cmd = server.cmd, + on_attach = server.on_attach, + before_init = server.before_init, + on_init = function(client) + client.offset_encoding = "utf-8" + end, + root_dir = server.root_dir, + settings = server.settings, + filetypes = server.filetypes, + capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {}), + }) + end, + }, + }) + end, + }, +} diff --git a/home/neovim/neovim/lua/plugins/telescope.lua b/home/neovim/neovim/lua/plugins/telescope.lua new file mode 100644 index 0000000..abe283d --- /dev/null +++ b/home/neovim/neovim/lua/plugins/telescope.lua @@ -0,0 +1,36 @@ +-- Telescope fuzzy finder configuration + +return { + "nvim-telescope/telescope.nvim", + event = "VeryLazy", + branch = "master", + dependencies = { + "nvim-lua/plenary.nvim", + { "nvim-tree/nvim-web-devicons" }, + { "nvim-telescope/telescope-live-grep-args.nvim" }, + { + "nvim-telescope/telescope-fzf-native.nvim", + build = "make", + cond = function() + return vim.fn.executable("make") == 1 + end, + }, + }, + config = function() + require("telescope").setup({ + defaults = vim.tbl_extend("force", require("telescope.themes").get_ivy(), { + path_display = { "smart" }, + }), + }) + + pcall(require("telescope").load_extension("live_grep_args")) + local builtin = require("telescope.builtin") + vim.keymap.set("n", "", require("telescope").extensions.live_grep_args.live_grep_args) + vim.keymap.set( + "x", + "", + "\"zy:lua require('telescope').extensions.live_grep_args.live_grep_args(require('telescope.themes').get_ivy({}))z" + ) + vim.keymap.set("n", "", builtin.find_files) + end, +} \ No newline at end of file diff --git a/home/neovim/neovim/lua/plugins/ui.lua b/home/neovim/neovim/lua/plugins/ui.lua new file mode 100644 index 0000000..416f4f5 --- /dev/null +++ b/home/neovim/neovim/lua/plugins/ui.lua @@ -0,0 +1,143 @@ +-- UI and appearance plugins + +return { + { + "zenbones-theme/zenbones.nvim", + lazy = false, + priority = 1000, + dependencies = "rktjmp/lush.nvim", + config = function() + if vim.g.light_mode then + vim.o.background = "light" + else + vim.o.background = "dark" + end + vim.cmd.colorscheme("zenwritten") + vim.api.nvim_set_hl(0, "Normal", { bg = "none" }) + vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" }) + end, + }, + + { "folke/todo-comments.nvim", dependencies = { "nvim-lua/plenary.nvim" }, opts = { signs = false } }, + + { + "echasnovski/mini.nvim", + keys = { + { + "m", + function() + require("mini.files").open(vim.api.nvim_buf_get_name(0), true) + end, + desc = "Open mini.files (Directory of Current File)", + }, + }, + config = function() + require("mini.files").setup() + local getWords = require("utils.statusline").getWords + require("mini.statusline").setup({ + content = { + active = function() + local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 }) + local git = MiniStatusline.section_git({ trunc_width = 75 }) + local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 75 }) + local filename = MiniStatusline.section_filename({ trunc_width = 140 }) + local fileinfo = MiniStatusline.section_fileinfo({ trunc_width = 120 }) + local location = MiniStatusline.section_location({ trunc_width = 75 }) + local search = MiniStatusline.section_searchcount({ trunc_width = 75 }) + local words = getWords() + return MiniStatusline.combine_groups({ + + { hl = mode_hl, strings = { mode } }, + { hl = "MiniStatuslineDevinfo", strings = { git, diagnostics } }, + "%<", + { hl = "MiniStatuslineFilename", strings = { filename } }, + "%=", + { hl = "MiniStatuslineFileinfo", strings = { fileinfo } }, + { hl = "MiniStatuslineFileinfo", strings = { words } }, + { hl = mode_hl, strings = { search, location } }, + }) + end, + }, + }) + end, + }, + + { + "nvim-treesitter/nvim-treesitter", + branch = "main", + main = "nvim-treesitter", + build = ":TSUpdate", + init = function() + -- Install parsers that aren't already present + local ensure_installed = { "bash", "c", "html", "lua", "markdown", "vim", "vimdoc" } + local already_installed = require("nvim-treesitter.config").get_installed() + local to_install = vim.iter(ensure_installed) + :filter(function(parser) + return not vim.tbl_contains(already_installed, parser) + end) + :totable() + if #to_install > 0 then + require("nvim-treesitter").install(to_install) + end + end, + }, + + { + "folke/snacks.nvim", + priority = 1000, + lazy = false, + opts = { + dashboard = { enabled = true }, + input = { enabled = true }, + terminal = { enabled = true }, + notify = { enabled = true }, + }, + keys = { + { + "T", + function() + Snacks.terminal() + end, + desc = "Toggle Terminal", + }, + }, + }, + + { + "folke/trouble.nvim", + opts = {}, + cmd = "Trouble", + keys = { + { + "xx", + "Trouble diagnostics toggle", + desc = "Diagnostics (Trouble)", + }, + { + "xX", + "Trouble diagnostics toggle filter.buf=0", + desc = "Buffer Diagnostics (Trouble)", + }, + { + "cs", + "Trouble symbols toggle focus=false", + desc = "Symbols (Trouble)", + }, + { + "cl", + "Trouble lsp toggle focus=false win.position=right", + desc = "LSP Definitions / references / ... (Trouble)", + }, + { + "xL", + "Trouble loclist toggle", + desc = "Location List (Trouble)", + }, + { + "xQ", + "Trouble qflist toggle", + desc = "Quickfix List (Trouble)", + }, + }, + }, +} diff --git a/home/neovim/neovim/lua/telescope_settings.lua b/home/neovim/neovim/lua/telescope_settings.lua new file mode 100644 index 0000000..84b3a5a --- /dev/null +++ b/home/neovim/neovim/lua/telescope_settings.lua @@ -0,0 +1,5 @@ +require('telescope').setup{ + defaults = { + path_display={"smart"}, + } +} diff --git a/home/neovim/neovim/lua/todo-config.lua b/home/neovim/neovim/lua/todo-config.lua new file mode 100644 index 0000000..c134fce --- /dev/null +++ b/home/neovim/neovim/lua/todo-config.lua @@ -0,0 +1,55 @@ +require("todo-comments").setup({ + signs = true, -- show icons in the signs column + sign_priority = 8, -- sign priority + -- keywords recognized as todo comments + keywords = { + FIX = { + icon = " ", -- icon used for the sign, and in search results + color = "error", -- can be a hex color, or a named color (see below) + alt = { "FIXME", "BUG", "FIXIT", "ISSUE" }, -- a set of other keywords that all map to this FIX keywords + -- signs = false, -- configure signs for some keywords individually + }, + TODO = { icon = " ", color = "info" }, + HACK = { icon = " ", color = "warning" }, + WARN = { icon = " ", color = "warning", alt = { "WARNING", "XXX" } }, + PERF = { icon = "󰾆 ", alt = { "OPTIM", "PERFORMANCE", "OPTIMIZE" } }, + NOTE = { icon = "󰎞 ", color = "hint", alt = { "INFO" } }, + }, + merge_keywords = true, -- when true, custom keywords will be merged with the defaults + -- highlighting of the line containing the todo comment + -- * before: highlights before the keyword (typically comment characters) + -- * keyword: highlights of the keyword + -- * after: highlights after the keyword (todo text) + highlight = { + before = "", -- "fg" or "bg" or empty + keyword = "wide", -- "fg", "bg", "wide" or empty. (wide is the same as bg, but will also highlight surrounding characters) + after = "fg", -- "fg" or "bg" or empty + pattern = [[.*<(KEYWORDS)\s*:]], -- pattern or table of patterns, used for highlightng (vim regex) + comments_only = true, -- uses treesitter to match keywords in comments only + max_line_len = 400, -- ignore lines longer than this + exclude = {}, -- list of file types to exclude highlighting + }, + -- list of named colors where we try to extract the guifg from the + -- list of hilight groups or use the hex color if hl not found as a fallback + colors = { + error = { "DiagnosticError", "ErrorMsg", "#DC2626" }, + warning = { "DiagnosticWarning", "WarningMsg", "#FBBF24" }, + info = { "DiagnosticInfo", "#2563EB" }, + hint = { "DiagnosticHint", "#10B981" }, + default = { "Identifier", "#7C3AED" }, + }, + search = { + command = "rg", + args = { + "--color=never", + "--no-heading", + "--with-filename", + "--line-number", + "--column", + }, + -- regex that will be used to match keywords. + -- don't replace the (KEYWORDS) placeholder + pattern = [[\b(KEYWORDS):]], -- ripgrep regex + -- pattern = [[\b(KEYWORDS)\b]], -- match without the extra colon. You'll likely get false positives + }, +}) diff --git a/home/neovim/neovim/lua/utils/statusline.lua b/home/neovim/neovim/lua/utils/statusline.lua new file mode 100644 index 0000000..1c29c1a --- /dev/null +++ b/home/neovim/neovim/lua/utils/statusline.lua @@ -0,0 +1,15 @@ +-- Statusline utilities + +local M = {} + +-- Function to get word count in status line +function M.getWords() + -- the third string here is the string for visual-block mode (^V) + if vim.fn.mode() == "v" or vim.fn.mode() == "V" or vim.fn.mode() == "" then + return vim.fn.wordcount().visual_words .. "" + else + return vim.fn.wordcount().words .. "" + end +end + +return M \ No newline at end of file diff --git a/home/neovim/neovim/lua/workspace.lua b/home/neovim/neovim/lua/workspace.lua new file mode 100644 index 0000000..0f851e5 --- /dev/null +++ b/home/neovim/neovim/lua/workspace.lua @@ -0,0 +1,25 @@ +local util = require('lspconfig.util') + +local join = util.path.join + +local M = {} + +local env = { + HOME = vim.loop.os_homedir(), + XDG_CACHE_HOME = os.getenv('XDG_CACHE_HOME'), +} + +---Returns the default workspace directory +---@return string +function M.get_default_workspace() + local cache_dir = env.XDG_CACHE_HOME and env.XDG_CACHE_HOME + or join(env.HOME, '.cache') + local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ':p:h:t') + + local path = + join(cache_dir, 'jdtls', 'workspaces', project_name) + + return path +end + +return M diff --git a/home/neovim/neovim/spell/en.utf-8.add b/home/neovim/neovim/spell/en.utf-8.add new file mode 100644 index 0000000..3667456 --- /dev/null +++ b/home/neovim/neovim/spell/en.utf-8.add @@ -0,0 +1,52 @@ +interphase +nanolaminate +microstructures +multilayers +multiscale +microrotation +microcontinuum +microstructure +heterostructured +proven +diffusionless +martensitic +embrittlement +deliverables +minima +energetics +Predictiveness +atomistic +foundational +diffusivity +equilibrated +compositionally +compositional +nanometers +undeformed +interdiffusion +nanolaminates +interdiffused +monatomic +atomistics +interfacial +interatomic +Fortran +runtimes +spacings +unrelaxed +a +nm +centroids +microrotations +centroid +evolutions +recomendations +rhombohedron +inhibitive +parallelized +assumming +exhibitted +manyfold +reusability +Architected +roadmaps diff --git a/home/neovim/neovim/spell/en.utf-8.add.spl b/home/neovim/neovim/spell/en.utf-8.add.spl new file mode 100644 index 0000000..b8bc973 Binary files /dev/null and b/home/neovim/neovim/spell/en.utf-8.add.spl differ diff --git a/home/root/home.nix b/home/root/home.nix new file mode 100644 index 0000000..69a6e50 --- /dev/null +++ b/home/root/home.nix @@ -0,0 +1,13 @@ +{config, pkgs, ... }: +{ + imports = [ + ../shell/shell.nix + ../neovim/neovim.nix + ]; + + home.username = "root"; + home.homeDirectory = "/root"; + home.stateVersion = "26.05"; + + programs.home-manager.enable = true; +} diff --git a/home/shell/.tmux.conf b/home/shell/.tmux.conf new file mode 100644 index 0000000..d700e4f --- /dev/null +++ b/home/shell/.tmux.conf @@ -0,0 +1,80 @@ +#Make nicer tmux motion keys that work with vim as well +set -g xterm-keys on +is_vim="ps -o state= -o comm= -t '#{pane_tty}' \ + | grep -iqE '^[^TXZ ]+ +(\\S+\/)?g?(view|n?vim?x?)(diff)?$'" + +bind-key -n C-h if-shell "$is_vim" "send-keys C-h" "select-pane -L" +bind-key -n C-j if-shell "$is_vim" "send-keys C-j" "select-pane -D" +bind-key -n C-k if-shell "$is_vim" "send-keys C-k" "select-pane -U" +bind-key -n C-l if-shell "$is_vim" "send-keys C-l" "select-pane -R" +bind-key -n C-\ if-shell "$is_vim" "send-keys C-\\" "select-pane -l" + +unbind C-b +set -g prefix C-p +bind C-p send-prefix + +#Sane split commands +bind v split-window -h -c "#{pane_current_path}" +bind s split-window -v -c "#{pane_current_path}" +unbind '"' +unbind % + +# New windows open in current directory +bind c new-window -c "#{pane_current_path}" + +# reload config file (change file location to your the tmux.conf you want to use) +bind r source-file ~/.tmux.conf + +# Vim key bindings +set-window-option -g mode-keys vi + +bind-key -T copy-mode-vi v send-keys -X begin-selection +bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -in -selection primary" +bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -in -selection primary" + +# don't do anything when a 'bell' rings +set -g visual-activity off +set -g visual-bell off +set -g visual-silence off +setw -g monitor-activity off +set -g bell-action none + +# clock mode +setw -g clock-mode-colour "#BBBBBB" + +# copy mode +setw -g mode-style 'fg=black bg=red bold' + +# panes +set -g pane-border-style 'fg=red' +set -g pane-active-border-style 'fg=yellow' + +# statusbar +set -g status-position bottom +set -g status-justify left +set -g status-style 'fg=black bold' + +set -g status-left '#( [ -n "$SSH_CONNECTION" ] && printf " #[fg=red,bold][SSH]" ) ' +set -g status-left-length 10 + +set -g status-right-style 'fg=white bold bg=black' +set -g status-right '%Y-%m-%d %H:%M ' +set -g status-right-length 50 + +setw -g window-status-current-style 'fg=red bold bg=black' +setw -g window-status-current-format ' #I #W #F ' + +setw -g window-status-style 'fg=white bg=black' +setw -g window-status-format ' #I #[fg=white]#W #F ' + +setw -g window-status-bell-style 'fg=yellow bg=red bold' + +# messages +set -g message-style 'fg=white bg=black' + +# Pass through shift+enter +set -g extended-keys on +set -g extended-keys-format csi-u + +# Dim inactive panes +source-file ~/.config/tmux/theme.conf diff --git a/home/shell/.zshrc b/home/shell/.zshrc new file mode 100644 index 0000000..e12fa01 --- /dev/null +++ b/home/shell/.zshrc @@ -0,0 +1,225 @@ +#============================================================================== +# Zsh Configuration +#============================================================================== +# History settings +HISTFILE=~/.histfile +HISTSIZE=100000 +SAVEHIST=100000 +setopt extendedglob notify +unsetopt autocd beep +setopt INC_APPEND_HISTORY # Write to history file immediately, not when shell exits +setopt APPEND_HISTORY # Append instead of overwriting the file +setopt HIST_IGNORE_DUPS # Don't save duplicate commands +setopt HIST_IGNORE_SPACE # Don't save commands starting with space + +#============================================================================== +# Environment Variables +#============================================================================== + +export OMPI_MCA_rmaps_base_oversubscribe=1 +export CLICOLOR=1 +export LSCOLORS=ExGxBxDxCxEgEdxbxgxcxd +export LS_COLORS='di=1;37:ln=35:so=32:pi=33:ex=1;32:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43' +export XKB_DEFAULT_OPTIONS="caps:escape" +export PASSWORD_STORE_CHARACTER_SET='a-zA-Z0-9+\-$!*_=' +export XDEB_PKGROOT=${HOME}/.config/xdeb +export EDITOR=nvim +export TERMINAL=ghostty +export GOOGLE_CLOUD_PROJECT=slurm-slinky-k8s +export SU2_RUN="~/.local/bin/" +export SU2_HOME="~/builds/SU2/" +export PYTHONPATH=$SU2_RUN:$PYTHONPATH + +if [[ -f /etc/profiles/per-user/$USER/etc/profile.d/hm-session-vars.sh ]]; then + source /etc/profiles/per-user/$USER/etc/profile.d/hm-session-vars.sh +fi + +# Custom path additions +if [ -f "$HOME/.profile" ]; then + source ~/.profile +fi + +if [ -f "$HOME/.local/share/os/habits.sh" ]; then + source "$HOME/.local/share/os/habits.sh" +fi + +#============================================================================== +# Aliases +#============================================================================== + +alias clip2png="xclip -selection clipboard -target image/png -out" +if which kubectl > /dev/null; then + alias k="kubectl" + source <(k completion zsh) +fi +cc() { + CLAUDE_SESSION="${1:-unnamed}" claude "${@:2}" +} + +ssh_no_tmux() { + NO_TMUX=1 nohup ghostty --command="ssh $*" >/dev/null 2>&1 & +} + +alias jjn="jj new -B @ --no-edit" +alias jjs="jj squash --interactive --from @ --into @-" +alias jjp="jj bookmark move master --to @-; jj git push" +alias pkg_search="nix search nixpkgs --extra-experimental-features 'nix-command flakes'" + +sandbox() { + local host_repos="$HOME/repos" + local sandbox_cwd="/workspace" + + if [[ "$PWD" == "$host_repos" ]]; then + sandbox_cwd="/workspace" + elif [[ "$PWD" == "$host_repos"/* ]]; then + sandbox_cwd="/workspace/${PWD#$host_repos/}" + fi + + if ! docker ps -a --format '{{.Names}}' | grep -q '^dev-sandbox$'; then + docker run -dit --name dev-sandbox \ + --env-file "$host_repos/dev_sandbox/.env" \ + -v "$host_repos:/workspace" \ + -v pi-state:/root/.pi \ + -v /var/run/docker.sock:/var/run/docker.sock \ + dev-sandbox:latest + else + docker start dev-sandbox 2>/dev/null + fi + + if (( $# > 0 )); then + docker exec -it -w "$sandbox_cwd" dev-sandbox /bin/zsh -l -c 'exec "$@"' sandbox "$@" + else + docker exec -it -w "$sandbox_cwd" dev-sandbox /bin/zsh -l + fi +} + + +#============================================================================== +# Functions +#============================================================================== + +load_env() { + set -a + . "./$1" + set +a +} + +#============================================================================== +# os functions +#============================================================================== +alias t="nvim ~/.local/share/os/tasks.md" +alias h="habits open" +alias books="nvim ~/.local/share/os/books.md" +alias mindset="nvim ~/.local/share/os/mindset.md" + +#============================================================================== +# Completions +#============================================================================== + +autoload -Uz compinit +compinit +zstyle ':compinstall' filename '/home/aselimov/.zshrc' +zstyle -e ':completion:*:hosts' hosts 'reply=( + ${=${${(f)"$(cat {/etc/ssh_,~/ar.ssh/known_}hosts(|2)(N) 2>/dev/null)"}%%[#| ]*}//,/ } + ${=${${${${(@M)${(f)"$(cat ~/.ssh/config 2>/dev/null)"}:#Host *}#Host }:#*\**}:#*\?*}} +)' + +#============================================================================== +# Plugins & Tools +#============================================================================== + +# nvm +# Lazy-load nvm - only initialize when first used +export NVM_DIR="$HOME/.nvm" + +# Function to load nvm (called only once) +load_nvm() { + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" +} + +# Create placeholder functions that load nvm once, then call the real command +nvm() { + unset -f nvm node npm + load_nvm + nvm "$@" +} + +node() { + unset -f nvm node npm + load_nvm + node "$@" +} + +npm() { + unset -f nvm node npm + load_nvm + npm "$@" +} + +# ghcup +[ -f "/home/aselimov/.ghcup/env" ] && . "/home/aselimov/.ghcup/env" # ghcup-env + +# pyenv +if command -v pyenv >/dev/null 2>&1; then + export PYENV_ROOT="$HOME/.pyenv" + [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" + eval "$(pyenv init - zsh)" +fi + +# jenv +if command -v jenv >/dev/null 2>&1; then + export PATH="$HOME/.jenv/bin:$PATH" + eval "$(jenv init -)" +fi + +# Simple notify function +notify() { + local cmd="$*" + eval "$cmd" + local rc=$? + osascript -e "display notification \"Done (exit=$rc)\" with title \"${cmd//\"/\\\"}\"" + return $rc +} + + +# zsh-autosuggestions +source "$HOME/.config/zsh/zsh-autosuggestions/zsh-autosuggestions.zsh" + +# zsh-syntax-highlighting +source "$HOME/.config/zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" + +# zsh-history-substring-search +source "$HOME/.config/zsh/zsh-history-substring-search/zsh-history-substring-search.zsh" + +#============================================================================== +# Keybindings +#============================================================================== + +bindkey -v +bindkey '^[[A' history-substring-search-up +bindkey '^[[B' history-substring-search-down + +#============================================================================== +# OS-Specific Configuration +#============================================================================== + +if [ "$(uname)" = "Darwin" ]; then + alias ls="gls --classify --group-directories-first --color" + export NVIM_JDTLS_JAVA_HOME="/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/" +else + alias ls="ls --classify --group-directories-first --color" +fi + +# starship +eval "$(starship init zsh)" + +if [[ -z "$TMUX" ]] && [[ -n "$PS1" ]] && [[ -z "$NO_TMUX" ]]; then + tmux attach -t dev || tmux new -s dev +fi + +# Get remaining habits +if [ -n "$HABITS" ]; then + echo "Habits remaining are:" + habits left +fi diff --git a/home/shell/shell.nix b/home/shell/shell.nix new file mode 100644 index 0000000..4d77bd3 --- /dev/null +++ b/home/shell/shell.nix @@ -0,0 +1,51 @@ +{config, pkgs, ...}: +{ + home.packages = with pkgs; [ + starship + ]; + xdg.configFile."starship.toml".source = ./starship.toml; + + programs.zsh = { + enable = true; + initContent='' + source ${./.zshrc} + ''; + shellAliases = { + sudo = "doas"; + }; + }; + programs.direnv = { + enable = true; + nix-direnv.enable = true; + + config = { + global = { + hide_env_diff = true; + }; + }; + }; + + xdg.configFile."zsh/zsh-syntax-highlighting".source = builtins.fetchGit { + url = "https://forge.alexselimov.com/aselimov/zsh-syntax-highlighting.git"; + rev = "2fc57d63067c18b1100ecdbf684fa5baf49459d1"; + }; + + xdg.configFile."zsh/zsh-history-substring-search".source = builtins.fetchGit { + url = "https://forge.alexselimov.com/aselimov/zsh-history-substring-search.git"; + rev = "14c8d2e0ffaee98f2df9850b19944f32546fdea5"; + }; + + xdg.configFile."zsh/zsh-autosuggestions".source = builtins.fetchGit { + url = "https://forge.alexselimov.com/aselimov/zsh-autosuggestions.git"; + rev = "85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5"; + }; + + programs.tmux.enable = true; + xdg.configFile."tmux/tmux.conf".source = ./.tmux.conf; + xdg.configFile."tmux/themes/zenwritten-light.conf".text = '' + set -g window-style 'bg=gray' + ''; + xdg.configFile."tmux/themes/zenwritten-dark.conf".text = '' + set -g window-style 'bg=brightblack' + ''; +} diff --git a/home/shell/starship.toml b/home/shell/starship.toml new file mode 100644 index 0000000..9a2259c --- /dev/null +++ b/home/shell/starship.toml @@ -0,0 +1,166 @@ +#8e8e8e normal +#BBBBBB bold +#66a5ad accent + +format = """ +$username\ +$hostname\ +$shlvl\ +$kubernetes\ +$directory\ +$hg_branch\ +$docker_context\ +$package\ +$cmake\ +$dart\ +$dotnet\ +$elixir\ +$elm\ +$erlang\ +$golang\ +$helm\ +$java\ +$julia\ +$kotlin\ +$nim\ +$nodejs\ +$ocaml\ +$perl\ +$php\ +$purescript\ +$python\ +$ruby\ +$rust\ +$swift\ +$terraform\ +$zig\ +$nix_shell\ +$conda\ +$memory_usage\ +$aws\ +$gcloud\ +$openstack\ +$env_var\ +$crystal\ +$custom\ +$cmd_duration\ +$line_break\ +$lua\ +$jobs\ +$battery\ +$time\ +$status\ +$character""" + +[username] +style_user = 'bold #66a5ad' + +[hostname] +style = 'bold #BBBBBB' +ssh_symbol = "" + +[singularity] +style = 'bold #BBBBBB' + +[kubernetes] +style = 'bold #BBBBBB' + +[vcsh] +style = 'bold white' + +[git_branch] +style = 'bold #BBBBBB' + +[git_commit] +style = 'bold #BBBBBB' + +[docker_context] +style = 'bold #BBBBBB' +[package] +style = 'bold #BBBBBB' +symbol = " " +[cmake] +style = 'bold #BBBBBB' +[dart] +style = 'bold #BBBBBB' +[dotnet] +style = 'bold #BBBBBB' +[elixir] +style = 'bold #BBBBBB' +[elm] +style = 'bold #BBBBBB' +[erlang] +style = 'bold #BBBBBB' +[golang] +style = 'bold #BBBBBB' +[helm] +style = 'bold #BBBBBB' +[java] +style = 'bold #BBBBBB' +[julia] +style = 'bold #BBBBBB' +[kotlin] +style = 'bold #BBBBBB' +[nim] +style = 'bold #BBBBBB' +[nodejs] +style = 'bold #BBBBBB' +[ocaml] +style = 'bold #BBBBBB' +[perl] +style = 'bold #BBBBBB' +[php] +style = 'bold #BBBBBB' +[purescript] +style = 'bold #BBBBBB' +[ruby] +style = 'bold #BBBBBB' +[swift] +style = 'bold #BBBBBB' +[terraform] +style = 'bold #BBBBBB' +[zig] +style = 'bold #BBBBBB' +[nix_shell] +style = 'bold #BBBBBB' +[conda] +style = 'bold #BBBBBB' +[memory_usage] +style = 'bold #BBBBBB' +[aws] +style = 'bold #BBBBBB' +[gcloud] +style = 'bold #BBBBBB' +disabled=true +[openstack] +style = 'bold #BBBBBB' +[crystal] +style = 'bold #BBBBBB' +[cmd_duration] +style = 'bold #BBBBBB' +[lua] +style = 'bold #BBBBBB' +symbol = "󰢱 " +[jobs] +style = 'bold #BBBBBB' +[time] +style = 'bold #BBBBBB' + + +[python] +symbol = "󱔎 " +style = 'bold #BBBBBB' + +[rust] +symbol = "󱘗 " +style = 'bold #BBBBBB' + +[directory] +truncate_to_repo = false +style = 'bold #BBBBBB' + +[character] +success_symbol = "[󰜴](bold green)" +error_symbol = "[󰬅](bold red)" +vicmd_symbol = "[N](bold green)" +