Compare commits
18
Commits
438f67e4cc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c43ff55d32 | ||
|
|
62e4feba61 | ||
|
|
d2e47dec2a | ||
|
|
d2de783f3b | ||
|
|
1c4f950e3f | ||
|
|
2e6bbc77fd | ||
|
|
60c8d863d3 | ||
|
|
30c87a36af | ||
|
|
5ddfe643c3 | ||
|
|
ce6b1aa6f0 | ||
|
|
8313889ac4 | ||
|
|
9b63be7856 | ||
|
|
625713cbb4 | ||
|
|
20f501c2b1 | ||
|
|
8fa53a582c | ||
|
|
ed196212ed | ||
|
|
7d9fc403b0 | ||
|
|
dc575dc2fd |
+12
-2
@@ -1,11 +1,21 @@
|
|||||||
|
# emacs
|
||||||
|
config/emacs/.ignore
|
||||||
|
config/emacs/var/
|
||||||
|
config/emacs/elfeed/
|
||||||
|
config/emacs/eshell/
|
||||||
|
config/emacs/auto-save-list/
|
||||||
|
# fish
|
||||||
config/fish/conf.d
|
config/fish/conf.d
|
||||||
config/fish/functions
|
config/fish/functions
|
||||||
config/fish/fish_variables
|
config/fish/fish_variables
|
||||||
config/fish/generated_completions/
|
config/fish/generated_completions/
|
||||||
|
# vim/nvim
|
||||||
config/vim/autoload/
|
config/vim/autoload/
|
||||||
config/vim/pack/
|
config/vim/pack/
|
||||||
config/vim/.netrwhist
|
config/vim/.netrwhist
|
||||||
config/nvim/nvim-pack-lock.json
|
config/nvim/nvim-pack-lock.json
|
||||||
config/awesome/bling
|
# other
|
||||||
scripts/bin/Obsidian
|
|
||||||
scripts/bin/ols
|
scripts/bin/ols
|
||||||
|
scripts/bin/deno
|
||||||
|
scripts/bin/yt-dlp
|
||||||
|
scripts/bin/tiled
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
;;; early-init.el --- Pre-init: GC ceiling and frame chrome -*- lexical-binding: t; -*-
|
||||||
|
;;; Commentary:
|
||||||
|
;; Runs before package.el initialises and first frame is drawn, the only place these take effect:
|
||||||
|
;; 1. Raising the GC ceiling, so the whole startup (package load + init.el)
|
||||||
|
;; runs without garbage-collection pauses.
|
||||||
|
;; 2. Removing the menu/tool/scroll bars via `default-frame-alist', so they
|
||||||
|
;; are never drawn — toggling the minor modes in init.el instead draws
|
||||||
|
;; them and then removes them, a visible flicker on launch.
|
||||||
|
;;
|
||||||
|
;; Nothing here may depend on a package: none are loaded yet.
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(startup-redirect-eln-cache (expand-file-name "var/eln-cache/" user-emacs-directory))
|
||||||
|
(setq package-user-dir (expand-file-name "var/elpa/" user-emacs-directory))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Garbage Collection
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Hold GC off for the whole startup; init.el lowers it back on
|
||||||
|
;; `emacs-startup-hook' (see the Commentary above).
|
||||||
|
|
||||||
|
(setq gc-cons-threshold most-positive-fixnum)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Frame Chrome (no flicker)
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Disable the bars before the first frame exists.
|
||||||
|
|
||||||
|
(push '(menu-bar-lines . 0) default-frame-alist)
|
||||||
|
(push '(tool-bar-lines . 0) default-frame-alist)
|
||||||
|
(push '(vertical-scroll-bars) default-frame-alist)
|
||||||
|
|
||||||
|
;; Don't resize the frame when the UI/fonts change during startup.
|
||||||
|
(setq frame-inhibit-implied-resize t)
|
||||||
|
|
||||||
|
;;; early-init.el ends here
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
;;; init.el --- Minimal Emacs: built-ins + evil + consult -*- lexical-binding: t; -*-
|
||||||
|
;; Learning: F1 k KEY, F1 f FUNCTION, F1 v VARIABLE, F1 m (modes), F1 b (bindings).
|
||||||
|
;; C-h works too, except in normal/motion state where it moves to the window on the left.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
;;;; 1. Emac setup, gc, files, packages
|
||||||
|
(add-hook 'emacs-startup-hook
|
||||||
|
(lambda () (setq gc-cons-threshold (* 16 1024 1024))))
|
||||||
|
|
||||||
|
(dolist (bin (list (expand-file-name "~/.local/bin")
|
||||||
|
(expand-file-name "~/.go/bin")))
|
||||||
|
(add-to-list 'exec-path bin)
|
||||||
|
(setenv "PATH" (concat bin path-separator (getenv "PATH"))))
|
||||||
|
|
||||||
|
;; Add the themes directory to the load path
|
||||||
|
(add-to-list 'custom-theme-load-path (expand-file-name "themes" user-emacs-directory))
|
||||||
|
|
||||||
|
;; all the emacs runtime files live in var/.
|
||||||
|
;; early-init.el redirects eln-cache and elpa.
|
||||||
|
(defvar my/var (locate-user-emacs-file "var/"))
|
||||||
|
(make-directory (concat my/var "transient/") t)
|
||||||
|
(setq savehist-file (concat my/var "history")
|
||||||
|
save-place-file (concat my/var "places.eld")
|
||||||
|
recentf-save-file (concat my/var "recentf.eld")
|
||||||
|
project-list-file (concat my/var "projects.eld")
|
||||||
|
transient-history-file (concat my/var "transient/history.el")
|
||||||
|
transient-levels-file (concat my/var "transient/levels.el")
|
||||||
|
transient-values-file (concat my/var "transient/values.el"))
|
||||||
|
|
||||||
|
;; Custom output goes to its own file, not here.
|
||||||
|
(setq custom-file (expand-file-name "var/custom.el" user-emacs-directory))
|
||||||
|
(load custom-file 'noerror 'nomessage)
|
||||||
|
|
||||||
|
;; No session manager save: stops the empty session.* files.
|
||||||
|
(add-hook 'emacs-save-session-functions #'always)
|
||||||
|
|
||||||
|
;; Package GNU, NonGNU are built in melpa additional lowest priority.
|
||||||
|
(require 'package)
|
||||||
|
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
|
||||||
|
(setq package-archive-priorities '(("gnu" . 3) ("nongnu" . 2) ("melpa" . 1)))
|
||||||
|
(package-initialize)
|
||||||
|
|
||||||
|
(require 'use-package)
|
||||||
|
(setq use-package-always-ensure t)
|
||||||
|
|
||||||
|
;;;; 2. Ui settings, theme setup and fonts
|
||||||
|
(add-to-list 'default-frame-alist '(fullscreen . maximized))
|
||||||
|
(menu-bar-mode -1)
|
||||||
|
(tool-bar-mode -1)
|
||||||
|
(scroll-bar-mode -1)
|
||||||
|
(blink-cursor-mode -1)
|
||||||
|
|
||||||
|
(setq inhibit-startup-screen t
|
||||||
|
ring-bell-function #'ignore
|
||||||
|
use-short-answers t
|
||||||
|
scroll-conservatively 101
|
||||||
|
scroll-margin 20)
|
||||||
|
|
||||||
|
(setq-default indent-tabs-mode nil tab-width 4)
|
||||||
|
|
||||||
|
(global-hl-line-mode 1)
|
||||||
|
(global-display-line-numbers-mode 1)
|
||||||
|
(pixel-scroll-precision-mode 1)
|
||||||
|
(column-number-mode 1)
|
||||||
|
(electric-pair-mode 1)
|
||||||
|
(which-key-mode 1)
|
||||||
|
|
||||||
|
;; Load the compline theme
|
||||||
|
(load-theme 'minimal t)
|
||||||
|
|
||||||
|
;; set mode line at the top of each window
|
||||||
|
(setq-default header-line-format mode-line-format mode-line-format nil)
|
||||||
|
|
||||||
|
(set-face-attribute 'default nil :family "JetBrainsMono Nerd Font" :height 120)
|
||||||
|
(setq-default line-spacing '(4 . 4))
|
||||||
|
|
||||||
|
;; Command launcher.
|
||||||
|
(keymap-global-set "C-S-p" #'execute-extended-command)
|
||||||
|
|
||||||
|
;; Escape behaves like C-g
|
||||||
|
(keymap-global-set "<escape>" #'keyboard-quit)
|
||||||
|
(keymap-set minibuffer-local-map "<escape>" #'abort-minibuffers)
|
||||||
|
|
||||||
|
;;;; 3. Files
|
||||||
|
(setq make-backup-files nil
|
||||||
|
auto-save-default nil
|
||||||
|
auto-save-list-file-prefix nil
|
||||||
|
create-lockfiles nil
|
||||||
|
confirm-kill-processes nil
|
||||||
|
vc-follow-symlinks t)
|
||||||
|
|
||||||
|
(save-place-mode 1)
|
||||||
|
(savehist-mode 1)
|
||||||
|
(recentf-mode 1)
|
||||||
|
(global-auto-revert-mode 1)
|
||||||
|
|
||||||
|
;;;; 4. Completion
|
||||||
|
;; C-n/C-p navigates up and down, section 5 stops evil from overrriding
|
||||||
|
(use-package vertico
|
||||||
|
:init
|
||||||
|
(vertico-mode 1)
|
||||||
|
:custom
|
||||||
|
(vertico-count 15))
|
||||||
|
|
||||||
|
(setq completion-styles '(basic partial-completion flex)
|
||||||
|
completion-ignore-case t
|
||||||
|
read-buffer-completion-ignore-case t
|
||||||
|
read-file-name-completion-ignore-case t
|
||||||
|
completions-format 'one-column
|
||||||
|
isearch-lazy-count t
|
||||||
|
xref-search-program 'ripgrep)
|
||||||
|
|
||||||
|
(use-package vertico-posframe
|
||||||
|
:after vertico
|
||||||
|
:custom
|
||||||
|
(vertico-posframe-poshandler #'posframe-poshandler-frame-center)
|
||||||
|
:config
|
||||||
|
(vertico-posframe-mode 1))
|
||||||
|
|
||||||
|
;;;; 5. Evil
|
||||||
|
(defvar evil-mode-buffers nil)
|
||||||
|
|
||||||
|
(defun my/insert-tab ()
|
||||||
|
"Insert a literal tab character."
|
||||||
|
(interactive)
|
||||||
|
(insert "\t"))
|
||||||
|
|
||||||
|
(use-package evil
|
||||||
|
:init
|
||||||
|
(setq evil-want-C-u-scroll t
|
||||||
|
evil-undo-system 'undo-redo
|
||||||
|
evil-want-keybinding nil)
|
||||||
|
:config
|
||||||
|
(evil-mode 1)
|
||||||
|
|
||||||
|
(evil-define-key 'insert 'global
|
||||||
|
(kbd "TAB") #'my/insert-tab
|
||||||
|
(kbd "C-SPC") #'completion-at-point)
|
||||||
|
|
||||||
|
;; C-p and C-f are assigned to Consult below, C-m to ibuffer.
|
||||||
|
(evil-define-key '(normal motion) 'global
|
||||||
|
(kbd "C-e") #'dired-jump))
|
||||||
|
|
||||||
|
(use-package evil-collection
|
||||||
|
:after evil
|
||||||
|
:custom
|
||||||
|
;; Don't add its global [b ]b [e ]e ... bindings.
|
||||||
|
(evil-collection-want-unimpaired-p nil)
|
||||||
|
:config
|
||||||
|
(evil-collection-init '(info ibuffer)))
|
||||||
|
|
||||||
|
;; Minibuffer. Vertico
|
||||||
|
(with-eval-after-load 'vertico
|
||||||
|
(evil-define-key '(insert normal) vertico-map
|
||||||
|
(kbd "C-n") #'vertico-next
|
||||||
|
(kbd "C-p") #'vertico-previous
|
||||||
|
(kbd "TAB") #'vertico-insert
|
||||||
|
(kbd "<tab>") #'vertico-insert))
|
||||||
|
|
||||||
|
(evil-define-key '(insert normal) minibuffer-local-map
|
||||||
|
(kbd "<escape>") #'abort-minibuffers)
|
||||||
|
|
||||||
|
;; Result buffers: hjkl motions and RET to jump to a result.
|
||||||
|
(dolist (m '(occur-mode grep-mode xref--xref-buffer-mode))
|
||||||
|
(evil-set-initial-state m 'motion))
|
||||||
|
|
||||||
|
(with-eval-after-load 'compile
|
||||||
|
(evil-define-key 'motion compilation-mode-map
|
||||||
|
(kbd "RET") #'compile-goto-error))
|
||||||
|
|
||||||
|
(with-eval-after-load 'grep
|
||||||
|
(evil-define-key 'motion grep-mode-map
|
||||||
|
(kbd "RET") #'compile-goto-error))
|
||||||
|
|
||||||
|
(with-eval-after-load 'replace
|
||||||
|
(evil-define-key 'motion occur-mode-map
|
||||||
|
(kbd "RET") #'occur-mode-goto-occurrence))
|
||||||
|
|
||||||
|
(with-eval-after-load 'xref
|
||||||
|
(evil-define-key 'motion xref--xref-buffer-mode-map
|
||||||
|
(kbd "RET") #'xref-goto-xref))
|
||||||
|
|
||||||
|
;;;; 6. Consult
|
||||||
|
;; Requires the external `fd` and `rg` executables. Both honour .ignore files,
|
||||||
|
;; so keep excludes (node_modules, elpa, ...) in ~/.ignore or per-project .ignore.
|
||||||
|
;; Searches start at the project root when there is one, else the current directory.
|
||||||
|
(use-package consult
|
||||||
|
:config
|
||||||
|
;; Don't re-run the preview on every keystroke while typing a search.
|
||||||
|
(consult-customize consult-ripgrep
|
||||||
|
:preview-key '(:debounce 0.4 any)))
|
||||||
|
|
||||||
|
;; Bind immediately, without waiting for consult to load.
|
||||||
|
;; C-m opens the full ibuffer list (evil-collection provides its navigation).
|
||||||
|
(evil-define-key '(normal motion) 'global
|
||||||
|
(kbd "C-p") #'consult-fd
|
||||||
|
(kbd "C-f") #'consult-ripgrep
|
||||||
|
(kbd "C-m") #'ibuffer)
|
||||||
|
|
||||||
|
;;;; 7. Dired
|
||||||
|
(setq dired-dwim-target t
|
||||||
|
dired-kill-when-opening-new-dired-buffer t
|
||||||
|
dired-listing-switches "-agho --group-directories-first"
|
||||||
|
dired-recursive-copies 'always
|
||||||
|
delete-by-moving-to-trash t)
|
||||||
|
|
||||||
|
(with-eval-after-load 'dired
|
||||||
|
(require 'dired-x)
|
||||||
|
(setq dired-omit-files "\\`\\.")
|
||||||
|
(add-hook 'dired-mode-hook #'dired-omit-mode)
|
||||||
|
(evil-set-initial-state 'dired-mode 'motion)
|
||||||
|
|
||||||
|
(evil-define-key 'motion dired-mode-map
|
||||||
|
"h" #'dired-up-directory
|
||||||
|
"l" #'dired-find-file
|
||||||
|
"." #'dired-omit-mode
|
||||||
|
(kbd "RET") #'dired-find-file))
|
||||||
|
|
||||||
|
;;;; Core config ends here.
|
||||||
|
;;;; -----------------------------------------------------------------
|
||||||
|
;;;; 8. Modules - additional functionality outside of the core init.el
|
||||||
|
|
||||||
|
;; Setup for orgmode
|
||||||
|
(load (locate-user-emacs-file "modules/org.el") nil 'nomessage)
|
||||||
|
|
||||||
|
;; Magit and the :git command live in modules/git.el.
|
||||||
|
(load (locate-user-emacs-file "modules/git.el") nil 'nomessage)
|
||||||
|
|
||||||
|
;; Setup for personal build commands and system.
|
||||||
|
(load (locate-user-emacs-file "modules/build.el") nil 'nomessage)
|
||||||
|
|
||||||
|
;; Setup for dev languages, modes, lsp and lsp keybinds.
|
||||||
|
(load (locate-user-emacs-file "modules/dev.el") nil 'nomessage)
|
||||||
|
|
||||||
|
;;; init.el ends here
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
;;; build.el --- Project build, set up for Evil -*- lexical-binding: t; -*-
|
||||||
|
;;; Commentary:
|
||||||
|
;; Loaded from init.el after Evil.
|
||||||
|
;;
|
||||||
|
;; :build Run ./build.sh from the nearest ancestor dir containing it.
|
||||||
|
;; :build ARGS Run ./build.sh ARGS, e.g. :build release -v
|
||||||
|
;;
|
||||||
|
;; If no build.sh is found (or it isn't executable), report it and do nothing.
|
||||||
|
;;
|
||||||
|
;; The compilation buffer opens at the bottom (45% height, full width) and
|
||||||
|
;; takes focus when the build starts. ANSI colours are rendered.
|
||||||
|
;; Kill a running build with M-x kill-compilation.
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(setq compilation-read-command nil ; run without prompting
|
||||||
|
compilation-ask-about-save nil
|
||||||
|
compilation-scroll-output t)
|
||||||
|
|
||||||
|
(add-hook 'compilation-filter-hook #'ansi-color-compilation-filter)
|
||||||
|
|
||||||
|
;; Compilation buffer at the bottom, full frame width.
|
||||||
|
(add-to-list 'display-buffer-alist
|
||||||
|
'((derived-mode . compilation-mode)
|
||||||
|
(display-buffer-reuse-window display-buffer-at-bottom)
|
||||||
|
(window-height . 0.45)))
|
||||||
|
|
||||||
|
;; Focus the compilation window when a build starts.
|
||||||
|
(add-hook 'compilation-start-hook
|
||||||
|
(lambda (proc)
|
||||||
|
(when-let* ((win (get-buffer-window (process-buffer proc))))
|
||||||
|
(select-window win))))
|
||||||
|
|
||||||
|
;; :build runs ./build.sh; :build ARGS appends ARGS.
|
||||||
|
(evil-define-command my/ex-build (args)
|
||||||
|
"Run `./build.sh ARGS' from the nearest directory containing build.sh."
|
||||||
|
(interactive "<a>")
|
||||||
|
(let ((root (locate-dominating-file default-directory "build.sh")))
|
||||||
|
(unless root
|
||||||
|
(user-error "No build.sh found"))
|
||||||
|
(let ((default-directory root))
|
||||||
|
(unless (file-executable-p "build.sh")
|
||||||
|
(user-error "build.sh is not executable"))
|
||||||
|
(compile (string-trim (concat "./build.sh " args)))))) ; nil args -> ""
|
||||||
|
|
||||||
|
(evil-ex-define-cmd "build" #'my/ex-build)
|
||||||
|
|
||||||
|
;;; build.el ends here
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
;;; development.el --- Languages, Eglot and code navigation -*- lexical-binding: t; -*-
|
||||||
|
;;; Commentary:
|
||||||
|
;; Loaded from init.el. Requires Evil.
|
||||||
|
;;
|
||||||
|
;; Languages:
|
||||||
|
;; Markdown markdown-mode.
|
||||||
|
;; PHP php-mode, PSR-2 style, 4 spaces.
|
||||||
|
;; Odin odin-mode from git (needs Emacs 30+ for :vc), Eglot + OLS.
|
||||||
|
;; Go go-mode, Eglot + gopls; organize imports and format on save.
|
||||||
|
;;
|
||||||
|
;; Normal/motion state:
|
||||||
|
;; gd definitions gD references K eldoc
|
||||||
|
;; C-t jump back ESC closes any open eldoc window.
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;;;; Markdown
|
||||||
|
(use-package markdown-mode)
|
||||||
|
|
||||||
|
;;;; PHP
|
||||||
|
(use-package php-mode
|
||||||
|
:mode "\\.php\\'"
|
||||||
|
:hook
|
||||||
|
(php-mode . (lambda ()
|
||||||
|
(setq-local indent-tabs-mode nil)
|
||||||
|
(setq-local tab-width 4)
|
||||||
|
(setq-local c-basic-offset 4)))
|
||||||
|
:custom
|
||||||
|
(php-mode-coding-style 'psr2))
|
||||||
|
|
||||||
|
;;;; Odin
|
||||||
|
(use-package odin-mode
|
||||||
|
:vc (:url "https://github.com/mattt-b/odin-mode"
|
||||||
|
:rev :newest)
|
||||||
|
:mode "\\.odin\\'"
|
||||||
|
:hook (odin-mode . eglot-ensure))
|
||||||
|
|
||||||
|
;;;; Go
|
||||||
|
;; Emacs started from the desktop doesn't inherit fish env.
|
||||||
|
(dolist (d '("/usr/local/go/bin" "/home/jason/.go/bin"))
|
||||||
|
(add-to-list 'exec-path d)
|
||||||
|
(setenv "PATH" (concat d ":" (getenv "PATH"))))
|
||||||
|
(setenv "GOPATH" "/home/jason/.go")
|
||||||
|
(setenv "GOCACHE" "/home/jason/.go/cache")
|
||||||
|
|
||||||
|
(defun my/go-before-save ()
|
||||||
|
"Organize imports and format the buffer through Eglot."
|
||||||
|
(when (eglot-managed-p)
|
||||||
|
(eglot-code-actions nil nil "source.organizeImports" t)
|
||||||
|
(eglot-format-buffer)))
|
||||||
|
|
||||||
|
(use-package go-mode
|
||||||
|
:mode "\\.go\\'"
|
||||||
|
:hook ((go-mode . eglot-ensure)
|
||||||
|
(go-mode . (lambda ()
|
||||||
|
(setq-local tab-width 4)
|
||||||
|
(add-hook 'before-save-hook #'my/go-before-save nil t)))))
|
||||||
|
|
||||||
|
;;;; Eglot
|
||||||
|
(use-package eglot
|
||||||
|
:ensure nil
|
||||||
|
:config
|
||||||
|
(setq eglot-autoshutdown t)
|
||||||
|
(add-to-list 'eglot-ignored-server-capabilities :signatureHelpProvider)
|
||||||
|
|
||||||
|
;; Explicit OLS configuration.
|
||||||
|
(add-to-list
|
||||||
|
'eglot-server-programs
|
||||||
|
'(odin-mode
|
||||||
|
. ("/home/jason/.local/bin/ols"
|
||||||
|
:initializationOptions
|
||||||
|
(:odin_command "/home/jason/.odin/odin"
|
||||||
|
:enable_document_symbols t
|
||||||
|
:enable_format t
|
||||||
|
:collections
|
||||||
|
[(:name "core"
|
||||||
|
:path "/home/jason/.odin/core")
|
||||||
|
(:name "vendor"
|
||||||
|
:path "/home/jason/.odin/vendor")])))))
|
||||||
|
|
||||||
|
;; OLS built-in definitions.
|
||||||
|
(setenv "OLS_BUILTIN_FOLDER" "/home/jason/ThirdParty/ols/builtin")
|
||||||
|
|
||||||
|
;;;; Code navigation
|
||||||
|
;; Vim-style code navigation.
|
||||||
|
(evil-define-key '(normal motion) 'global
|
||||||
|
"gd" #'xref-find-definitions
|
||||||
|
"gD" #'xref-find-references
|
||||||
|
"K" #'eldoc
|
||||||
|
(kbd "C-t") #'xref-go-back)
|
||||||
|
|
||||||
|
;; ESC closes any open eldoc window.
|
||||||
|
(defun my/eldoc-close (&rest _)
|
||||||
|
"Quit every window showing an *eldoc* buffer."
|
||||||
|
(dolist (w (window-list))
|
||||||
|
(when (string-prefix-p "*eldoc" (buffer-name (window-buffer w)))
|
||||||
|
(quit-window nil w))))
|
||||||
|
(advice-add 'evil-force-normal-state :after #'my/eldoc-close)
|
||||||
|
|
||||||
|
;;; development.el ends here
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
;;; git.el --- Magit, set up for Evil -*- lexical-binding: t; -*-
|
||||||
|
;;; Commentary:
|
||||||
|
;; Loaded from init.el, which must set `evil-want-keybinding' to nil before
|
||||||
|
;; Evil loads (Evil Collection needs it).
|
||||||
|
;;
|
||||||
|
;; :git Magit status for the current repo, full frame.
|
||||||
|
;; q puts your previous window layout back.
|
||||||
|
;; :git ARGS Run `git ARGS' from the repo root, e.g. :git log --oneline
|
||||||
|
;;
|
||||||
|
;; In Magit (Evil Collection layout):
|
||||||
|
;; j/k move, TAB folds, s stage, u unstage, x discard, c c commit,
|
||||||
|
;; p push, F pull, l log, d diff, b branch, z stash, gr refresh, q quit,
|
||||||
|
;; ? lists every command.
|
||||||
|
;; Commit message: opens in insert state; ZZ or C-c C-c commits,
|
||||||
|
;; ZQ or C-c C-k cancels.
|
||||||
|
;; Ctrl+hjkl, C-f and C-b keep their global meaning in Magit buffers.
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(use-package magit
|
||||||
|
:defer t
|
||||||
|
:custom
|
||||||
|
;; Status takes the whole frame; q restores the previous window layout.
|
||||||
|
(magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1)
|
||||||
|
(magit-bury-buffer-function #'magit-restore-window-configuration))
|
||||||
|
|
||||||
|
;; Vim-style keys for Magit, its section folding, and the commit message buffer.
|
||||||
|
;; (magit magit-submodule) is the form Evil Collection's own default list uses.
|
||||||
|
(with-eval-after-load 'evil-collection
|
||||||
|
;; Evil Collection puts section jumps on C-j/C-k and page scrolling on C-f/C-b.
|
||||||
|
;; Unbind them so your window and Consult keys show through. Sibling sections
|
||||||
|
;; are still on ] and [, and scrolling on C-d/C-u.
|
||||||
|
(add-hook 'evil-collection-setup-hook
|
||||||
|
(lambda (mode &rest _)
|
||||||
|
(when (eq mode 'magit)
|
||||||
|
(evil-define-key 'normal magit-mode-map
|
||||||
|
(kbd "C-j") nil
|
||||||
|
(kbd "C-k") nil
|
||||||
|
(kbd "C-f") nil
|
||||||
|
(kbd "C-b") nil))))
|
||||||
|
|
||||||
|
(evil-collection-init '((magit magit-submodule) magit-section with-editor)))
|
||||||
|
|
||||||
|
;; Commit messages start in insert state. Added after git-commit loads so its
|
||||||
|
;; default hook functions are kept.
|
||||||
|
(with-eval-after-load 'git-commit
|
||||||
|
(add-hook 'git-commit-setup-hook #'evil-insert-state))
|
||||||
|
|
||||||
|
;; :git opens Magit; :git ARGS runs a git command.
|
||||||
|
(evil-define-command my/git (args)
|
||||||
|
"Open Magit status, or run `git ARGS' from the repository root."
|
||||||
|
(interactive "<a>")
|
||||||
|
(if (and args (string-match-p "[^[:space:]]" args))
|
||||||
|
(magit-git-command-topdir (concat "git " args))
|
||||||
|
(magit-status)))
|
||||||
|
|
||||||
|
(evil-ex-define-cmd "git" #'my/git)
|
||||||
|
|
||||||
|
;;; git.el ends here
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
;;; org.el --- Org appearance -*- lexical-binding: t; -*-
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Styled stars, bullets, tags, tables and blocks.
|
||||||
|
(use-package org-modern
|
||||||
|
:hook (org-mode . org-modern-mode))
|
||||||
|
|
||||||
|
(setq org-directory "~/Projects/notebook")
|
||||||
|
(setq org-startup-indented t ; visual indent per level, no real spaces
|
||||||
|
org-hide-emphasis-markers t ; *bold* shows bold, markers hidden
|
||||||
|
org-pretty-entities t ; \rarr, \alpha etc. as symbols
|
||||||
|
org-ellipsis " ▾" ; folded-heading marker
|
||||||
|
org-startup-folded 'show2levels ; open with headings only
|
||||||
|
org-fontify-whole-heading-line t
|
||||||
|
org-fontify-done-headline t
|
||||||
|
org-fontify-quote-and-verse-blocks t
|
||||||
|
org-src-fontify-natively t ; highlight src blocks with their own mode
|
||||||
|
org-src-tab-acts-natively t
|
||||||
|
org-edit-src-content-indentation 0
|
||||||
|
org-return-follows-link t)
|
||||||
|
|
||||||
|
;; org-modern's recommended settings.
|
||||||
|
(setq org-auto-align-tags nil
|
||||||
|
org-tags-column 0
|
||||||
|
org-catch-invisible-edits 'show-and-error
|
||||||
|
org-special-ctrl-a/e t
|
||||||
|
org-insert-heading-respect-content t)
|
||||||
|
|
||||||
|
(add-hook 'org-mode-hook #'visual-line-mode) ; wrap at window edge
|
||||||
|
(add-hook 'org-mode-hook (lambda () (display-line-numbers-mode -1))) ; prose reads better without
|
||||||
|
|
||||||
|
;; doom-themes' own Org fontification fixes (blocks, headings).
|
||||||
|
(doom-themes-org-config)
|
||||||
|
|
||||||
|
;; Heading sizes; 'user survives theme reloads, same as in init.el.
|
||||||
|
(doom-themes-set-faces 'user
|
||||||
|
'(org-document-title :height 1.3 :weight 'bold)
|
||||||
|
'(org-level-1 :height 1.2 :weight 'bold)
|
||||||
|
'(org-level-2 :height 1.15 :weight 'bold)
|
||||||
|
'(org-level-3 :height 1.1 :weight 'bold)
|
||||||
|
'(org-level-4 :height 1.0 :weight 'bold))
|
||||||
|
|
||||||
|
(defun my/notes-index ()
|
||||||
|
"Open the notes index."
|
||||||
|
(interactive)
|
||||||
|
(find-file (expand-file-name "index.org" org-directory)))
|
||||||
|
|
||||||
|
(keymap-global-set "C-c n" #'my/notes-index)
|
||||||
|
|
||||||
|
;; Evil's TAB (= C-i, jump-forward) shadows Org's. Rebind for Org buffers only.
|
||||||
|
(with-eval-after-load 'org
|
||||||
|
(evil-define-key 'normal org-mode-map
|
||||||
|
(kbd "TAB") #'org-cycle ; fold/unfold the heading at point
|
||||||
|
(kbd "<tab>") #'org-cycle ; GUI emits <tab>, so bind both
|
||||||
|
(kbd "RET") #'org-open-at-point
|
||||||
|
(kbd "<backtab>") #'org-shifttab)) ; S-TAB: cycle all headings
|
||||||
|
|
||||||
|
;;; org.el ends here
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
;;; minimal-theme.el --- Minimal high-functionality Ujelly port -*- lexical-binding: t; -*-
|
||||||
|
;;
|
||||||
|
;; Built on the compline-theme face structure, updated with the color palette
|
||||||
|
;; from Ujelly (color-theme-ujelly by marktran).
|
||||||
|
;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(deftheme minimal
|
||||||
|
"Created 2026-10-26.")
|
||||||
|
|
||||||
|
(custom-theme-set-faces
|
||||||
|
'minimal
|
||||||
|
|
||||||
|
;;;; Core
|
||||||
|
'(default ((t (:inherit nil :extend nil :stipple nil :background "#151515" :foreground "#e8e8d3" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight regular :height 143 :width normal))))
|
||||||
|
'(cursor ((t (:background "#8fbfdc"))))
|
||||||
|
'(fixed-pitch ((t (:height 140))))
|
||||||
|
'(variable-pitch ((t (:height 140))))
|
||||||
|
'(escape-glyph ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(homoglyph ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(minibuffer-prompt ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(highlight ((t (:foreground "#e8e8d3" :background "#303030" :weight bold))))
|
||||||
|
'(hl-line ((t (:extend t :background "#1b1b1b"))))
|
||||||
|
'(region ((t (:extend t :background "#404040"))))
|
||||||
|
'(shadow ((t (:foreground "#7f7f7f"))))
|
||||||
|
'(secondary-selection ((t (:extend t :background "#404040"))))
|
||||||
|
'(trailing-whitespace ((t (:background "#cf6a4c"))))
|
||||||
|
'(vertical-border ((t (:foreground "#262626"))))
|
||||||
|
'(error ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(warning ((t (:foreground "#fad07a"))))
|
||||||
|
'(success ((t (:foreground "#99ad6a"))))
|
||||||
|
|
||||||
|
;;;; Line numbers
|
||||||
|
'(line-number ((t (:foreground "#404040"))))
|
||||||
|
'(line-number-current-line ((t (:foreground "#e8e8d3"))))
|
||||||
|
|
||||||
|
;;;; Font lock
|
||||||
|
'(font-lock-bracket-face ((t (:inherit (font-lock-punctuation-face)))))
|
||||||
|
'(font-lock-builtin-face ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(font-lock-comment-delimiter-face ((default (:inherit (font-lock-comment-face)))))
|
||||||
|
'(font-lock-comment-face ((t (:foreground "#767676"))))
|
||||||
|
'(font-lock-constant-face ((t (:foreground "#c6b5ed"))))
|
||||||
|
'(font-lock-delimiter-face ((t (:inherit (font-lock-punctuation-face)))))
|
||||||
|
'(font-lock-doc-face ((t (:foreground "#767676" :inherit (font-lock-comment-face)))))
|
||||||
|
'(font-lock-doc-markup-face ((t (:inherit (font-lock-constant-face)))))
|
||||||
|
'(font-lock-escape-face ((t (:inherit (font-lock-regexp-grouping-backslash)))))
|
||||||
|
'(font-lock-function-call-face ((t (:slant italic :foreground "#8fbfdc" :inherit (font-lock-function-name-face)))))
|
||||||
|
'(font-lock-function-name-face ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(font-lock-keyword-face ((t (:foreground "#fad07a"))))
|
||||||
|
'(font-lock-negation-char-face ((t (:foreground "#cf6a4c" :inherit (bold)))))
|
||||||
|
'(font-lock-number-face ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(font-lock-misc-punctuation-face ((t (:inherit (font-lock-punctuation-face)))))
|
||||||
|
'(font-lock-operator-face ((t (:foreground "#a0a8b0"))))
|
||||||
|
'(font-lock-preprocessor-face ((t (:foreground "#fad07a" :inherit (bold)))))
|
||||||
|
'(font-lock-property-name-face ((t (:weight bold :foreground "#8fbfdc"))))
|
||||||
|
'(font-lock-property-use-face ((t (:weight regular :inherit (font-lock-property-name-face)))))
|
||||||
|
'(font-lock-punctuation-face ((t (:foreground "#a0a8b0"))))
|
||||||
|
'(font-lock-regexp-grouping-backslash ((t (:foreground "#fad07a" :inherit (bold)))))
|
||||||
|
'(font-lock-regexp-grouping-construct ((t (:foreground "#fad07a" :inherit (bold)))))
|
||||||
|
'(font-lock-string-face ((t (:foreground "#99ad6a"))))
|
||||||
|
'(font-lock-type-face ((t (:foreground "#ffb17a"))))
|
||||||
|
'(font-lock-variable-name-face ((t (:foreground "#e8e8d3"))))
|
||||||
|
'(font-lock-variable-use-face ((t (:foreground "#e8e8d3" :inherit (font-lock-variable-name-face)))))
|
||||||
|
'(font-lock-warning-face ((t (:inherit (warning)))))
|
||||||
|
|
||||||
|
;;;; Links, buttons, tooltips
|
||||||
|
'(button ((t (:inherit (link)))))
|
||||||
|
'(link ((t (:weight bold :underline (:color foreground-color :style line :position nil) :foreground "#8fbfdc"))))
|
||||||
|
'(link-visited ((t (:inherit link :foreground "#c6b5ed"))))
|
||||||
|
'(fringe ((t (:foreground "#404040" :inherit (default)))))
|
||||||
|
'(tooltip ((t (:foreground "#e8e8d3" :background "#1b1b1b"))))
|
||||||
|
|
||||||
|
;;;; Mode line
|
||||||
|
'(header-line ((t (:inherit (mode-line)))))
|
||||||
|
'(mode-line ((t (:background "#1c1c1c" :foreground unspecified))))
|
||||||
|
'(mode-line-buffer-id ((t (:weight bold))))
|
||||||
|
'(mode-line-emphasis ((t (:foreground "#fad07a"))))
|
||||||
|
'(mode-line-highlight ((t (:inherit (highlight)))))
|
||||||
|
'(mode-line-inactive ((t (:foreground "#767676" :background "#121212"))))
|
||||||
|
|
||||||
|
;;;; Tab bar
|
||||||
|
'(tab-bar ((t (:inherit default :background "#151515" :foreground "#767676"))))
|
||||||
|
'(tab-bar-tab ((t (:inherit tab-bar :background "#262626" :foreground "#e8e8d3" :weight bold :box nil))))
|
||||||
|
'(tab-bar-tab-inactive ((t (:inherit tab-bar :background "#151515" :foreground "#999999" :weight normal :box nil))))
|
||||||
|
|
||||||
|
;;;; Search & Completions
|
||||||
|
'(isearch ((t (:weight bold :inherit (lazy-highlight)))))
|
||||||
|
'(isearch-fail ((t (:weight bold :foreground "#151515" :background "#cf6a4c"))))
|
||||||
|
'(lazy-highlight ((t (:weight bold :foreground "#e8e8d3" :background "#303030"))))
|
||||||
|
'(match ((t (:weight bold :foreground "#99ad6a" :background "#151515"))))
|
||||||
|
'(next-error ((t (:inherit (region)))))
|
||||||
|
'(query-replace ((t (:inherit (isearch)))))
|
||||||
|
|
||||||
|
;;;; VC gutter: added = green, deleted = red, modified = sand/yellow
|
||||||
|
'(diff-hl-insert ((t (:foreground "#99ad6a" :background "#99ad6a"))))
|
||||||
|
'(diff-hl-delete ((t (:foreground "#cf6a4c" :background "#cf6a4c"))))
|
||||||
|
'(diff-hl-change ((t (:foreground "#fad07a" :background "#fad07a"))))
|
||||||
|
'(git-gutter:added ((t (:foreground "#99ad6a" :background "#99ad6a"))))
|
||||||
|
'(git-gutter:deleted ((t (:foreground "#cf6a4c" :background "#cf6a4c"))))
|
||||||
|
'(git-gutter:modified ((t (:foreground "#fad07a" :background "#fad07a"))))
|
||||||
|
'(git-gutter-fr:added ((t (:foreground "#99ad6a"))))
|
||||||
|
'(git-gutter-fr:deleted ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(git-gutter-fr:modified ((t (:foreground "#fad07a"))))
|
||||||
|
|
||||||
|
;;;; gnus: group buffer
|
||||||
|
'(gnus-group-news-1 ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(gnus-group-news-1-empty ((t (:foreground "#e8e8d3" :weight normal))))
|
||||||
|
'(gnus-group-news-2 ((t (:foreground "#8fbfdc" :weight bold))))
|
||||||
|
'(gnus-group-news-2-empty ((t (:foreground "#8fbfdc" :weight normal))))
|
||||||
|
'(gnus-group-news-3 ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(gnus-group-news-3-empty ((t (:foreground "#fad07a" :weight normal))))
|
||||||
|
'(gnus-group-news-low ((t (:foreground "#767676" :weight bold))))
|
||||||
|
'(gnus-group-news-low-empty ((t (:foreground "#404040" :weight normal))))
|
||||||
|
'(gnus-group-mail-1 ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(gnus-group-mail-1-empty ((t (:foreground "#99ad6a" :weight normal))))
|
||||||
|
'(gnus-group-mail-2 ((t (:foreground "#c6b5ed" :weight bold))))
|
||||||
|
'(gnus-group-mail-2-empty ((t (:foreground "#c6b5ed" :weight normal))))
|
||||||
|
'(gnus-group-mail-3 ((t (:foreground "#ffb17a" :weight bold))))
|
||||||
|
'(gnus-group-mail-3-empty ((t (:foreground "#ffb17a" :weight normal))))
|
||||||
|
'(gnus-group-mail-low ((t (:foreground "#767676" :weight bold))))
|
||||||
|
'(gnus-group-mail-low-empty ((t (:foreground "#404040" :weight normal))))
|
||||||
|
|
||||||
|
;;;; gnus: summary buffer
|
||||||
|
'(gnus-summary-normal-unread ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(gnus-summary-normal-read ((t (:foreground "#767676" :weight normal))))
|
||||||
|
'(gnus-summary-normal-ticked ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(gnus-summary-normal-ancient ((t (:foreground "#404040" :weight normal))))
|
||||||
|
'(gnus-summary-normal-undownloaded ((t (:foreground "#8fbfdc" :slant italic))))
|
||||||
|
'(gnus-summary-high-unread ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(gnus-summary-high-read ((t (:foreground "#99ad6a" :weight normal))))
|
||||||
|
'(gnus-summary-high-ticked ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(gnus-summary-high-ancient ((t (:foreground "#767676" :weight normal))))
|
||||||
|
'(gnus-summary-low-unread ((t (:foreground "#8fbfdc" :slant italic :weight bold))))
|
||||||
|
'(gnus-summary-low-read ((t (:foreground "#404040" :slant italic :weight normal))))
|
||||||
|
'(gnus-summary-low-ticked ((t (:foreground "#cf6a4c" :slant italic))))
|
||||||
|
'(gnus-summary-low-ancient ((t (:foreground "#404040" :slant italic))))
|
||||||
|
'(gnus-summary-selected ((t (:background "#404040" :foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(gnus-summary-cancelled ((t (:foreground "#cf6a4c" :strike-through t))))
|
||||||
|
|
||||||
|
;;;; gnus: article headers, citations, misc
|
||||||
|
'(gnus-header-name ((t (:foreground "#8fbfdc" :weight bold))))
|
||||||
|
'(gnus-header-content ((t (:foreground "#fad07a" :slant italic))))
|
||||||
|
'(gnus-header-from ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(gnus-header-subject ((t (:foreground "#ffb17a"))))
|
||||||
|
'(gnus-header-newsgroups ((t (:foreground "#fad07a" :slant italic))))
|
||||||
|
'(gnus-cite-1 ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(gnus-cite-2 ((t (:foreground "#99ad6a"))))
|
||||||
|
'(gnus-cite-3 ((t (:foreground "#fad07a"))))
|
||||||
|
'(gnus-cite-4 ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(gnus-cite-5 ((t (:foreground "#c6b5ed"))))
|
||||||
|
'(gnus-cite-6 ((t (:foreground "#ffb17a"))))
|
||||||
|
'(gnus-cite-7 ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(gnus-cite-8 ((t (:foreground "#99ad6a"))))
|
||||||
|
'(gnus-cite-9 ((t (:foreground "#fad07a"))))
|
||||||
|
'(gnus-cite-10 ((t (:foreground "#767676"))))
|
||||||
|
'(gnus-cite-11 ((t (:foreground "#404040"))))
|
||||||
|
'(gnus-signature ((t (:foreground "#767676" :slant italic))))
|
||||||
|
'(gnus-button ((t (:inherit link))))
|
||||||
|
'(gnus-splash ((t (:foreground "#767676"))))
|
||||||
|
'(gnus-emphasis-bold ((t (:weight bold))))
|
||||||
|
'(gnus-emphasis-italic ((t (:slant italic))))
|
||||||
|
'(gnus-emphasis-underline ((t (:underline t))))
|
||||||
|
'(gnus-emphasis-bold-italic ((t (:weight bold :slant italic))))
|
||||||
|
'(gnus-server-opened ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(gnus-server-closed ((t (:foreground "#767676" :slant italic))))
|
||||||
|
'(gnus-server-denied ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(gnus-server-offline ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(gnus-server-agent ((t (:foreground "#8fbfdc" :weight bold))))
|
||||||
|
|
||||||
|
;;;; message (gnus composition buffers)
|
||||||
|
'(message-header-name ((t (:foreground "#8fbfdc" :weight bold))))
|
||||||
|
'(message-header-to ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(message-header-cc ((t (:foreground "#ffb17a"))))
|
||||||
|
'(message-header-subject ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(message-header-newsgroups ((t (:foreground "#fad07a" :slant italic))))
|
||||||
|
'(message-header-other ((t (:foreground "#fad07a"))))
|
||||||
|
'(message-header-xheader ((t (:foreground "#767676"))))
|
||||||
|
'(message-separator ((t (:foreground "#404040"))))
|
||||||
|
'(message-mml ((t (:foreground "#99ad6a"))))
|
||||||
|
'(message-cited-text-1 ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(message-cited-text-2 ((t (:foreground "#99ad6a"))))
|
||||||
|
'(message-cited-text-3 ((t (:foreground "#fad07a"))))
|
||||||
|
'(message-cited-text-4 ((t (:foreground "#cf6a4c"))))
|
||||||
|
|
||||||
|
;;;; magit: sections
|
||||||
|
'(magit-section-heading ((t (:foreground "#fad07a" :weight bold :extend t))))
|
||||||
|
'(magit-section-secondary-heading ((t (:foreground "#c6b5ed" :weight bold :extend t))))
|
||||||
|
'(magit-section-heading-selection ((t (:foreground "#99ad6a" :weight bold :extend t))))
|
||||||
|
'(magit-section-highlight ((t (:background "#1b1b1b" :extend t))))
|
||||||
|
'(magit-section-child-count ((t (:foreground "#767676"))))
|
||||||
|
|
||||||
|
;;;; magit: refs, hashes, log
|
||||||
|
'(magit-branch-local ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(magit-branch-remote ((t (:foreground "#99ad6a"))))
|
||||||
|
'(magit-branch-current ((t (:foreground "#8fbfdc" :weight bold :box (:line-width -1 :color "#767676")))))
|
||||||
|
'(magit-branch-remote-head ((t (:foreground "#99ad6a" :weight bold :box (:line-width -1 :color "#767676")))))
|
||||||
|
'(magit-branch-upstream ((t (:slant italic))))
|
||||||
|
'(magit-tag ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-hash ((t (:foreground "#767676"))))
|
||||||
|
'(magit-dimmed ((t (:foreground "#404040"))))
|
||||||
|
'(magit-filename ((t (:foreground "#e8e8d3"))))
|
||||||
|
'(magit-refname ((t (:foreground "#767676"))))
|
||||||
|
'(magit-refname-stash ((t (:foreground "#767676"))))
|
||||||
|
'(magit-refname-wip ((t (:foreground "#767676"))))
|
||||||
|
'(magit-log-author ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-log-date ((t (:foreground "#767676"))))
|
||||||
|
'(magit-log-graph ((t (:foreground "#404040"))))
|
||||||
|
'(magit-keyword ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-keyword-squash ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-cherry-equivalent ((t (:foreground "#e8e8d3"))))
|
||||||
|
'(magit-cherry-unmatched ((t (:foreground "#8fbfdc"))))
|
||||||
|
|
||||||
|
;;;; magit: diffs
|
||||||
|
'(magit-diff-file-heading ((t (:foreground "#e8e8d3" :weight bold :extend t))))
|
||||||
|
'(magit-diff-file-heading-highlight ((t (:inherit magit-diff-file-heading :background "#1b1b1b"))))
|
||||||
|
'(magit-diff-file-heading-selection ((t (:inherit magit-diff-file-heading :foreground "#fad07a" :background "#404040"))))
|
||||||
|
'(magit-diff-hunk-heading ((t (:foreground "#c6b5ed" :background "#222222" :extend t))))
|
||||||
|
'(magit-diff-hunk-heading-highlight ((t (:foreground "#e8e8d3" :background "#404040" :extend t))))
|
||||||
|
'(magit-diff-hunk-heading-selection ((t (:foreground "#fad07a" :background "#404040" :extend t))))
|
||||||
|
'(magit-diff-lines-heading ((t (:foreground "#151515" :background "#fad07a" :extend t))))
|
||||||
|
'(magit-diff-context ((t (:foreground "#767676" :extend t))))
|
||||||
|
'(magit-diff-context-highlight ((t (:foreground "#c6b5ed" :background "#1b1b1b" :extend t))))
|
||||||
|
'(magit-diff-added ((t (:foreground "#99ad6a" :background "#1a261a" :extend t))))
|
||||||
|
'(magit-diff-added-highlight ((t (:foreground "#99ad6a" :background "#223322" :extend t))))
|
||||||
|
'(magit-diff-removed ((t (:foreground "#cf6a4c" :background "#261a1a" :extend t))))
|
||||||
|
'(magit-diff-removed-highlight ((t (:foreground "#cf6a4c" :background "#332222" :extend t))))
|
||||||
|
'(magit-diffstat-added ((t (:foreground "#99ad6a"))))
|
||||||
|
'(magit-diffstat-removed ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(magit-diff-whitespace-warning ((t (:background "#cf6a4c"))))
|
||||||
|
|
||||||
|
;;;; magit: process, signatures, sequences, blame, header line
|
||||||
|
'(magit-process-ok ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(magit-process-ng ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(magit-mode-line-process ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-mode-line-process-error ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(magit-signature-good ((t (:foreground "#99ad6a"))))
|
||||||
|
'(magit-signature-bad ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(magit-signature-untrusted ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(magit-signature-expired ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-signature-expired-key ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-signature-revoked ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(magit-signature-error ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(magit-sequence-head ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(magit-sequence-stop ((t (:foreground "#99ad6a"))))
|
||||||
|
'(magit-sequence-part ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-sequence-done ((t (:foreground "#767676"))))
|
||||||
|
'(magit-sequence-onto ((t (:foreground "#767676"))))
|
||||||
|
'(magit-bisect-good ((t (:foreground "#99ad6a"))))
|
||||||
|
'(magit-bisect-skip ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-bisect-bad ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(magit-blame-heading ((t (:foreground "#c6b5ed" :background "#222222" :extend t))))
|
||||||
|
'(magit-header-line ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(magit-header-line-key ((t (:foreground "#fad07a"))))
|
||||||
|
'(magit-header-line-log-select ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
|
||||||
|
;;;; transient (magit popups)
|
||||||
|
'(transient-heading ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(transient-key ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(transient-key-exit ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(transient-key-return ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(transient-key-stay ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(transient-argument ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(transient-value ((t (:foreground "#99ad6a"))))
|
||||||
|
'(transient-inactive-argument ((t (:foreground "#767676"))))
|
||||||
|
'(transient-inactive-value ((t (:foreground "#767676"))))
|
||||||
|
'(transient-unreachable ((t (:foreground "#404040"))))
|
||||||
|
'(transient-unreachable-key ((t (:foreground "#404040"))))
|
||||||
|
'(transient-disabled-suffix ((t (:foreground "#151515" :background "#cf6a4c" :weight bold))))
|
||||||
|
'(transient-enabled-suffix ((t (:foreground "#151515" :background "#99ad6a" :weight bold))))
|
||||||
|
'(transient-delimiter ((t (:foreground "#767676"))))
|
||||||
|
'(transient-separator ((t (:background "#1c1c1c"))))
|
||||||
|
'(transient-active-infix ((t (:foreground "#e8e8d3" :background "#404040"))))
|
||||||
|
'(transient-mismatched-key ((t (:underline t))))
|
||||||
|
'(transient-nonstandard-key ((t (:underline t))))
|
||||||
|
|
||||||
|
;;;; git-commit (magit commit message buffer)
|
||||||
|
'(git-commit-summary ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(git-commit-overlong-summary ((t (:foreground "#cf6a4c" :weight bold))))
|
||||||
|
'(git-commit-nonempty-second-line ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(git-commit-keyword ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(git-commit-comment-heading ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(git-commit-comment-branch-local ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(git-commit-comment-branch-remote ((t (:foreground "#99ad6a"))))
|
||||||
|
'(git-commit-comment-detached ((t (:foreground "#fad07a"))))
|
||||||
|
'(git-commit-comment-file ((t (:foreground "#fad07a"))))
|
||||||
|
'(git-commit-comment-action ((t (:foreground "#99ad6a"))))
|
||||||
|
|
||||||
|
;;;; erc: buffer text
|
||||||
|
'(erc-default-face ((t (:foreground "#e8e8d3"))))
|
||||||
|
'(erc-input-face ((t (:foreground "#99ad6a"))))
|
||||||
|
'(erc-my-nick-face ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(erc-my-nick-prefix-face ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(erc-nick-default-face ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(erc-nick-prefix-face ((t (:foreground "#fad07a"))))
|
||||||
|
'(erc-notice-face ((t (:foreground "#767676" :weight normal))))
|
||||||
|
'(erc-information ((t (:foreground "#c6b5ed"))))
|
||||||
|
'(erc-timestamp-face ((t (:foreground "#404040" :weight normal))))
|
||||||
|
'(erc-action-face ((t (:foreground "#ffb17a" :weight bold))))
|
||||||
|
'(erc-prompt-face ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(erc-command-indicator-face ((t (:foreground "#c6b5ed" :weight bold))))
|
||||||
|
'(erc-error-face ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(erc-button ((t (:inherit link :foreground "#e8e8d3"))))
|
||||||
|
'(erc-button-nick-default-face ((t (:foreground "#e8e8d3" :weight bold))))
|
||||||
|
'(erc-bold-face ((t (:weight bold))))
|
||||||
|
'(erc-italic-face ((t (:slant italic))))
|
||||||
|
'(erc-underline-face ((t (:underline t))))
|
||||||
|
'(erc-inverse-face ((t (:foreground "#151515" :background "#e8e8d3"))))
|
||||||
|
'(erc-keep-place-indicator-line ((t (:underline (:color "#404040" :style line)))))
|
||||||
|
'(erc-keep-place-indicator-arrow ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(erc-header-line ((t (:foreground "#c6b5ed" :background "#1c1c1c"))))
|
||||||
|
'(erc-header-line-disconnected ((t (:foreground "#cf6a4c" :background "#1c1c1c"))))
|
||||||
|
|
||||||
|
;;;; erc: highlighting rules
|
||||||
|
'(erc-current-nick-face ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(erc-keyword-face ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(erc-nick-msg-face ((t (:foreground "#fad07a" :weight bold))))
|
||||||
|
'(erc-direct-msg-face ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(erc-pal-face ((t (:foreground "#99ad6a" :weight bold))))
|
||||||
|
'(erc-fool-face ((t (:foreground "#404040"))))
|
||||||
|
'(erc-dangerous-host-face ((t (:foreground "#cf6a4c"))))
|
||||||
|
|
||||||
|
;;;; css-mode / scss-mode
|
||||||
|
'(css-proprietary-property ((t (:foreground "#fad07a"))))
|
||||||
|
'(css-property ((t (:foreground "#e8e8d3"))))
|
||||||
|
'(css-selector ((t (:foreground "#cf6a4c"))))
|
||||||
|
|
||||||
|
;;;; markdown-mode
|
||||||
|
'(markdown-markup-face ((t (:foreground "#404040"))))
|
||||||
|
'(markdown-header-face ((t (:inherit bold :foreground "#cf6a4c"))))
|
||||||
|
'(markdown-code-face ((t (:background "#1c1c1c"))))
|
||||||
|
|
||||||
|
;;;; outline
|
||||||
|
'(outline-1 ((t (:foreground "#e8e8d3" :weight ultra-bold))))
|
||||||
|
'(outline-2 ((t (:foreground "#8fbfdc"))))
|
||||||
|
'(outline-3 ((t (:foreground "#99ad6a"))))
|
||||||
|
'(outline-4 ((t (:foreground "#c6b5ed"))))
|
||||||
|
'(outline-5 ((t (:foreground "#ffb17a"))))
|
||||||
|
'(outline-6 ((t (:foreground "#fad07a"))))
|
||||||
|
'(outline-7 ((t (:foreground "#cf6a4c"))))
|
||||||
|
'(outline-8 ((t (:foreground "#e8e8d3"))))
|
||||||
|
|
||||||
|
;;;; org
|
||||||
|
'(org-block ((t (:background "#1b1b1b"))))
|
||||||
|
'(org-block-begin-line ((t (:foreground "#404040" :slant italic :background "#121212"))))
|
||||||
|
'(org-ellipsis ((t (:underline nil :background "#151515" :foreground "#cf6a4c"))))
|
||||||
|
'(org-quote ((t (:background "#1c1c1c"))))
|
||||||
|
'(org-hide ((t (:foreground "#151515"))))
|
||||||
|
|
||||||
|
;;;; solaire-mode
|
||||||
|
'(solaire-mode-line-face ((t (:inherit mode-line :background "#1c1c1c"))))
|
||||||
|
'(solaire-mode-line-inactive-face ((t (:inherit mode-line-inactive :background "#1c1c1c")))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(when load-file-name
|
||||||
|
(add-to-list 'custom-theme-load-path
|
||||||
|
(file-name-as-directory (file-name-directory load-file-name))))
|
||||||
|
|
||||||
|
(provide-theme 'minimal)
|
||||||
|
|
||||||
|
;;; minimal-theme.el ends here
|
||||||
@@ -21,7 +21,6 @@ set -gx COLORTERM "truecolor"
|
|||||||
set -gx DEBUG 1
|
set -gx DEBUG 1
|
||||||
set -gx GOPATH "$HOME/.go"
|
set -gx GOPATH "$HOME/.go"
|
||||||
set -gx GOCACHE "$HOME/.go/cache"
|
set -gx GOCACHE "$HOME/.go/cache"
|
||||||
set -gx GOROOT /usr/local/go
|
|
||||||
set -gx OLS_BUILTIN_FOLDER "/home/jason/ThirdParty/ols/builtin"
|
set -gx OLS_BUILTIN_FOLDER "/home/jason/ThirdParty/ols/builtin"
|
||||||
|
|
||||||
# Direnv
|
# Direnv
|
||||||
@@ -82,7 +81,10 @@ alias bat 'bat --theme="ansi" --paging=never'
|
|||||||
alias :q 'exit'
|
alias :q 'exit'
|
||||||
alias files 'thunar .'
|
alias files 'thunar .'
|
||||||
alias fetch 'pfetch'
|
alias fetch 'pfetch'
|
||||||
alias vi 'vis'
|
# Map 'php' directly to FrankenPHP's bundled PHP CLI runtime
|
||||||
|
alias php="frankenphp php-cli"
|
||||||
|
# Optional: A shorthand to spin up your local dev server instantly using your Caddyfile
|
||||||
|
alias phpserve="frankenphp php-server --config Caddyfile"
|
||||||
|
|
||||||
# Custom shortcuts
|
# Custom shortcuts
|
||||||
alias reload 'source ~/.config/fish/config.fish'
|
alias reload 'source ~/.config/fish/config.fish'
|
||||||
|
|||||||
@@ -1,256 +0,0 @@
|
|||||||
// ============================================================================
|
|
||||||
// GENERAL & SYSTEM SETTINGS
|
|
||||||
// Wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Introduction
|
|
||||||
// ============================================================================
|
|
||||||
config-notification {
|
|
||||||
disable-failed
|
|
||||||
}
|
|
||||||
|
|
||||||
hotkey-overlay {
|
|
||||||
skip-at-startup
|
|
||||||
}
|
|
||||||
|
|
||||||
prefer-no-csd
|
|
||||||
|
|
||||||
screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
|
|
||||||
|
|
||||||
debug {
|
|
||||||
honor-xdg-activation-with-invalid-serial
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ENVIRONMENT VARIABLES
|
|
||||||
// ============================================================================
|
|
||||||
environment {
|
|
||||||
XDG_CURRENT_DESKTOP "niri"
|
|
||||||
QT_QPA_PLATFORM "wayland;xcb"
|
|
||||||
ELECTRON_OZONE_PLATFORM_HINT "auto"
|
|
||||||
QT_QPA_PLATFORMTHEME "gtk3"
|
|
||||||
QT_QPA_PLATFORMTHEME_QT6 "gtk3"
|
|
||||||
TERMINAL "alacritty"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// AUTOSTART / SPAWN AT STARTUP
|
|
||||||
// ============================================================================
|
|
||||||
spawn-at-startup "dms" "run"
|
|
||||||
|
|
||||||
// Export the session env to D-Bus so xdg-desktop-portal works
|
|
||||||
spawn-at-startup "dbus-update-activation-environment" "--all"
|
|
||||||
|
|
||||||
// Audio stack
|
|
||||||
spawn-at-startup "pipewire"
|
|
||||||
|
|
||||||
// PolicyKit authentication agent (verify path: xbps-query -f mate-polkit | grep -i agent)
|
|
||||||
spawn-at-startup "sh" "-c" "/usr/libexec/polkit-mate-authentication-agent-1 &"
|
|
||||||
|
|
||||||
// Clipboard history backing store for Mod+V
|
|
||||||
spawn-at-startup "sh" "-c" "wl-paste --watch cliphist store"
|
|
||||||
|
|
||||||
// Automount removable media
|
|
||||||
spawn-at-startup "udiskie" "--no-tray"
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// INPUT & GESTURES
|
|
||||||
// Wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Input
|
|
||||||
// ============================================================================
|
|
||||||
input {
|
|
||||||
keyboard {
|
|
||||||
xkb {
|
|
||||||
// If this section is empty, niri will fetch xkb settings
|
|
||||||
// from org.freedesktop.locale1. You can control these using
|
|
||||||
// localectl set-x11-keymap.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable numlock on startup, omitting this setting disables it.
|
|
||||||
numlock
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focus windows and outputs automatically when moving the mouse into them.
|
|
||||||
focus-follows-mouse max-scroll-amount="95%"
|
|
||||||
}
|
|
||||||
|
|
||||||
gestures {
|
|
||||||
hot-corners {
|
|
||||||
off
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// LAYOUT & VISUAL APPEARANCE
|
|
||||||
// Wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Layout
|
|
||||||
// ============================================================================
|
|
||||||
layout {
|
|
||||||
background-color "transparent"
|
|
||||||
|
|
||||||
// When to center a column when changing focus: "never", "always", or "on-overflow"
|
|
||||||
center-focused-column "never"
|
|
||||||
|
|
||||||
// Custom widths toggled by "switch-preset-column-width" (Mod+R)
|
|
||||||
preset-column-widths {
|
|
||||||
proportion 0.5
|
|
||||||
proportion 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
default-column-width { proportion 0.5; }
|
|
||||||
|
|
||||||
border {
|
|
||||||
off
|
|
||||||
width 4
|
|
||||||
active-color "#707070" // Neutral gray
|
|
||||||
inactive-color "#d0d0d0" // Light gray
|
|
||||||
urgent-color "#cc4444" // Softer red
|
|
||||||
}
|
|
||||||
|
|
||||||
shadow {
|
|
||||||
softness 30
|
|
||||||
spread 5
|
|
||||||
offset x=0 y=5
|
|
||||||
color "#0007"
|
|
||||||
}
|
|
||||||
|
|
||||||
struts {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
overview {
|
|
||||||
workspace-shadow {
|
|
||||||
off
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ANIMATIONS
|
|
||||||
// ============================================================================
|
|
||||||
animations {
|
|
||||||
workspace-switch {
|
|
||||||
spring damping-ratio=0.80 stiffness=523 epsilon=0.0001
|
|
||||||
}
|
|
||||||
window-open {
|
|
||||||
duration-ms 150
|
|
||||||
curve "ease-out-expo"
|
|
||||||
}
|
|
||||||
window-close {
|
|
||||||
duration-ms 150
|
|
||||||
curve "ease-out-quad"
|
|
||||||
}
|
|
||||||
horizontal-view-movement {
|
|
||||||
spring damping-ratio=0.85 stiffness=423 epsilon=0.0001
|
|
||||||
}
|
|
||||||
window-movement {
|
|
||||||
spring damping-ratio=0.75 stiffness=323 epsilon=0.0001
|
|
||||||
}
|
|
||||||
window-resize {
|
|
||||||
spring damping-ratio=0.85 stiffness=423 epsilon=0.0001
|
|
||||||
}
|
|
||||||
config-notification-open-close {
|
|
||||||
spring damping-ratio=0.65 stiffness=923 epsilon=0.001
|
|
||||||
}
|
|
||||||
screenshot-ui-open {
|
|
||||||
duration-ms 200
|
|
||||||
curve "ease-out-quad"
|
|
||||||
}
|
|
||||||
overview-open-close {
|
|
||||||
spring damping-ratio=0.85 stiffness=800 epsilon=0.0001
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// WINDOW & LAYER RULES
|
|
||||||
// Wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Window-Rules
|
|
||||||
// ============================================================================
|
|
||||||
layer-rule {
|
|
||||||
match namespace="^quickshell$"
|
|
||||||
place-within-backdrop true
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id=r#"^org\.gnome\."#
|
|
||||||
draw-border-with-background false
|
|
||||||
geometry-corner-radius 12
|
|
||||||
clip-to-geometry true
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id=r#"^gnome-control-center$"#
|
|
||||||
match app-id=r#"^pavucontrol$"#
|
|
||||||
match app-id=r#"^nm-connection-editor$"#
|
|
||||||
default-column-width { proportion 0.5; }
|
|
||||||
open-floating false
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id=r#"^org\.gnome\.Calculator$"#
|
|
||||||
match app-id=r#"^gnome-calculator$"#
|
|
||||||
match app-id=r#"^galculator$"#
|
|
||||||
match app-id=r#"^blueman-manager$"#
|
|
||||||
match app-id=r#"^org\.gnome\.Nautilus$"#
|
|
||||||
match app-id=r#"^xdg-desktop-portal$"#
|
|
||||||
open-floating true
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id="Alacritty"
|
|
||||||
match app-id="kitty"
|
|
||||||
draw-border-with-background false
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id=r#"firefox$"# title="^Picture-in-Picture$"
|
|
||||||
match app-id="zoom"
|
|
||||||
open-floating true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force the Steam client, Friends List, and settings windows to float
|
|
||||||
window-rule {
|
|
||||||
match app-id="steam"
|
|
||||||
open-floating true
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id="steam"
|
|
||||||
match title="Friends List"
|
|
||||||
open-floating true
|
|
||||||
default-floating-position x=10 y=10 relative-to="bottom-right"
|
|
||||||
}
|
|
||||||
|
|
||||||
window-rule {
|
|
||||||
match app-id=r#"^steam$"# title=r#"^notificationtoasts_\d+_desktop$"#
|
|
||||||
default-floating-position x=10 y=10 relative-to="top-right"
|
|
||||||
open-focused false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Automatically fullscreen games launched via Proton
|
|
||||||
window-rule {
|
|
||||||
// Proton games typically use "steam_app_<id>" as their app-id.
|
|
||||||
// The r#"..."# syntax tells niri to evaluate this as a regular expression.
|
|
||||||
match app-id=r#"^steam_app_\d+$"#
|
|
||||||
open-fullscreen true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// NAVIGATION & KEYBINDINGS
|
|
||||||
// ============================================================================
|
|
||||||
// Override to disable super+tab
|
|
||||||
recent-windows {
|
|
||||||
binds {
|
|
||||||
Alt+Tab { next-window scope="output"; }
|
|
||||||
Alt+Shift+Tab { previous-window scope="output"; }
|
|
||||||
Alt+grave { next-window filter="app-id"; }
|
|
||||||
Alt+Shift+grave { previous-window filter="app-id"; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// INCLUDES (DMS MANAGEMENT)
|
|
||||||
// ============================================================================
|
|
||||||
// @NOTE: only dms file we could edit
|
|
||||||
include optional=true "dms/binds.kdl"
|
|
||||||
|
|
||||||
// @NOTE: Non-editable files below all managed by dms
|
|
||||||
include optional=true "dms/colors.kdl"
|
|
||||||
include optional=true "dms/layout.kdl"
|
|
||||||
include optional=true "dms/alttab.kdl"
|
|
||||||
include optional=true "dms/outputs.kdl"
|
|
||||||
include optional=true "dms/cursor.kdl"
|
|
||||||
include optional=true "dms/input.kdl"
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
binds {
|
|
||||||
// ========================================================================
|
|
||||||
// SYSTEM & DMS APPLICATION LAUNCHERS
|
|
||||||
// ========================================================================
|
|
||||||
// Screenshots
|
|
||||||
Alt+Print hotkey-overlay-title="Screenshot: Window" { spawn "dms" "screenshot" "window"; }
|
|
||||||
Alt+XF86Launch1 hotkey-overlay-title="Screenshot: Window" { spawn "dms" "screenshot" "window"; }
|
|
||||||
Ctrl+Print hotkey-overlay-title="Screenshot: Full Screen" { spawn "dms" "screenshot" "full"; }
|
|
||||||
Ctrl+XF86Launch1 hotkey-overlay-title="Screenshot: Full Screen" { spawn "dms" "screenshot" "full"; }
|
|
||||||
Mod+P hotkey-overlay-title="Screenshot: Region" { spawn "dms" "screenshot"; }
|
|
||||||
|
|
||||||
// Launchers & Overlays
|
|
||||||
Mod+D hotkey-overlay-title="Application Launcher" { spawn "dms" "ipc" "call" "spotlight" "toggle"; }
|
|
||||||
Mod+space hotkey-overlay-title="Spotlight Bar: Toggle" { spawn "dms" "ipc" "call" "spotlight-bar" "toggle"; }
|
|
||||||
Mod+Y hotkey-overlay-title="Browse Wallpapers" { spawn "dms" "ipc" "call" "dash" "toggle" "wallpaper"; }
|
|
||||||
Super+Backspace hotkey-overlay-title="Power Menu: Toggle" { spawn "dms" "ipc" "call" "powermenu" "toggle"; }
|
|
||||||
Mod+Alt+L hotkey-overlay-title="Lock Screen" { spawn "dms" "ipc" "call" "lock" "lock"; }
|
|
||||||
|
|
||||||
// Utilities & Tools
|
|
||||||
Ctrl+Alt+Delete hotkey-overlay-title="Task Manager" { spawn "dms" "ipc" "call" "processlist" "focusOrToggle"; }
|
|
||||||
Mod+M hotkey-overlay-title="Task Manager" { spawn "dms" "ipc" "call" "processlist" "focusOrToggle"; }
|
|
||||||
Mod+N hotkey-overlay-title="Notification Center" { spawn "dms" "ipc" "call" "notifications" "toggle"; }
|
|
||||||
Mod+S hotkey-overlay-title="Notepad" { spawn "dms" "ipc" "call" "notepad" "toggle"; }
|
|
||||||
Mod+V hotkey-overlay-title="Clipboard Manager" { spawn "dms" "ipc" "call" "clipboard" "toggle"; }
|
|
||||||
Mod+Comma hotkey-overlay-title="Settings" { spawn "dms" "ipc" "call" "settings" "focusOrToggle"; }
|
|
||||||
|
|
||||||
// Configuration Helpers
|
|
||||||
Ctrl+Shift+R hotkey-overlay-title="Rename Workspace" { spawn "dms" "ipc" "call" "workspace-rename" "open"; }
|
|
||||||
Mod+Shift+W hotkey-overlay-title="Create window rule" { spawn "dms" "ipc" "call" "window-rules" "toggle"; }
|
|
||||||
|
|
||||||
// Audio Control (MPRIS)
|
|
||||||
Ctrl+XF86AudioLowerVolume allow-when-locked=true { spawn "dms" "ipc" "call" "mpris" "decrement" "3"; }
|
|
||||||
Ctrl+XF86AudioRaiseVolume allow-when-locked=true { spawn "dms" "ipc" "call" "mpris" "increment" "3"; }
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// WINDOW & COLUMN FOCUS
|
|
||||||
// ========================================================================
|
|
||||||
// Focus Columns (Horizontal)
|
|
||||||
Mod+H { focus-column-left; }
|
|
||||||
Mod+Left { focus-column-left; }
|
|
||||||
Mod+L { focus-column-right; }
|
|
||||||
Mod+Right { focus-column-right; }
|
|
||||||
Mod+Home { focus-column-first; }
|
|
||||||
Mod+End { focus-column-last; }
|
|
||||||
|
|
||||||
// Focus Windows within Column (Vertical)
|
|
||||||
Mod+J { focus-window-down; }
|
|
||||||
Mod+Down { focus-window-down; }
|
|
||||||
Mod+K { focus-window-up; }
|
|
||||||
Mod+Up { focus-window-up; }
|
|
||||||
|
|
||||||
// Mouse Wheel Focus Navigation
|
|
||||||
Mod+WheelScrollLeft { focus-column-left; }
|
|
||||||
Mod+WheelScrollRight { focus-column-right; }
|
|
||||||
Mod+Shift+WheelScrollUp { focus-column-left; }
|
|
||||||
Mod+Shift+WheelScrollDown { focus-column-right; }
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// WINDOW & COLUMN MANIPULATION
|
|
||||||
// ========================================================================
|
|
||||||
// Close Window
|
|
||||||
Mod+Q repeat=false { close-window; }
|
|
||||||
|
|
||||||
// Move Columns (Horizontal)
|
|
||||||
Mod+Shift+H { move-column-left; }
|
|
||||||
Mod+Shift+Left { move-column-left; }
|
|
||||||
Mod+Shift+L { move-column-right; }
|
|
||||||
Mod+Shift+Right { move-column-right; }
|
|
||||||
Mod+Ctrl+Home { move-column-to-first; }
|
|
||||||
Mod+Ctrl+End { move-column-to-last; }
|
|
||||||
Mod+Ctrl+WheelScrollLeft { move-column-left; }
|
|
||||||
Mod+Ctrl+WheelScrollRight { move-column-right; }
|
|
||||||
Mod+Ctrl+Shift+WheelScrollUp { move-column-left; }
|
|
||||||
Mod+Ctrl+Shift+WheelScrollDown { move-column-right; }
|
|
||||||
|
|
||||||
// Move Windows within Column (Vertical)
|
|
||||||
Mod+Shift+J { move-window-down; }
|
|
||||||
Mod+Shift+Down { move-window-down; }
|
|
||||||
Mod+Shift+K { move-window-up; }
|
|
||||||
Mod+Shift+Up { move-window-up; }
|
|
||||||
|
|
||||||
// Sizing & Layout Constraints
|
|
||||||
Mod+Equal { set-column-width "+10%"; }
|
|
||||||
Mod+Minus { set-column-width "-10%"; }
|
|
||||||
Mod+Shift+Equal { set-window-height "+10%"; }
|
|
||||||
Mod+Shift+Minus { set-window-height "-10%"; }
|
|
||||||
Mod+R { switch-preset-column-width; }
|
|
||||||
Mod+Shift+R { switch-preset-window-height; }
|
|
||||||
Mod+Ctrl+R { reset-window-height; }
|
|
||||||
Mod+Ctrl+F { expand-column-to-available-width; }
|
|
||||||
Mod+F { maximize-column; }
|
|
||||||
Mod+Shift+F { fullscreen-window; }
|
|
||||||
|
|
||||||
// Positioning, Floating & Tiling States
|
|
||||||
Mod+C { center-column; }
|
|
||||||
Mod+Ctrl+C { center-visible-columns; }
|
|
||||||
Mod+W { toggle-column-tabbed-display; }
|
|
||||||
Mod+Shift+T { toggle-window-floating; }
|
|
||||||
Mod+Shift+V { switch-focus-between-floating-and-tiling; }
|
|
||||||
Mod+BracketLeft { consume-or-expel-window-left; }
|
|
||||||
Mod+BracketRight { consume-or-expel-window-right; }
|
|
||||||
Mod+Period { expel-window-from-column; }
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// WORKSPACE MANAGEMENT
|
|
||||||
// ========================================================================
|
|
||||||
// Switch Workspace Focus
|
|
||||||
Mod+Page_Up { focus-workspace-up; }
|
|
||||||
Mod+I { focus-workspace-up; }
|
|
||||||
Mod+Page_Down { focus-workspace-down; }
|
|
||||||
Mod+U { focus-workspace-down; }
|
|
||||||
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
|
|
||||||
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
|
|
||||||
|
|
||||||
// Switch Workspace by Index
|
|
||||||
Mod+1 { focus-workspace 1; }
|
|
||||||
Mod+2 { focus-workspace 2; }
|
|
||||||
Mod+3 { focus-workspace 3; }
|
|
||||||
Mod+4 { focus-workspace 4; }
|
|
||||||
|
|
||||||
// Move Focused Column to Workspace
|
|
||||||
Mod+Ctrl+Up { move-column-to-workspace-up; }
|
|
||||||
Mod+Ctrl+I { move-column-to-workspace-up; }
|
|
||||||
Mod+Ctrl+Down { move-column-to-workspace-down; }
|
|
||||||
Mod+Ctrl+U { move-column-to-workspace-down; }
|
|
||||||
Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; }
|
|
||||||
Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }
|
|
||||||
|
|
||||||
// Move Focused Column to Workspace Index
|
|
||||||
Mod+Shift+1 { move-column-to-workspace 1; }
|
|
||||||
Mod+Shift+2 { move-column-to-workspace 2; }
|
|
||||||
Mod+Shift+3 { move-column-to-workspace 3; }
|
|
||||||
Mod+Shift+4 { move-column-to-workspace 4; }
|
|
||||||
|
|
||||||
// Move Entire Workspace Position
|
|
||||||
Mod+Shift+Page_Up { move-workspace-up; }
|
|
||||||
Mod+Shift+I { move-workspace-up; }
|
|
||||||
Mod+Shift+Page_Down { move-workspace-down; }
|
|
||||||
Mod+Shift+U { move-workspace-down; }
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// COMPOSITOR & SESSION CONTROLS
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
Mod+T hotkey-overlay-title="Open Terminal" { spawn "alacritty"; }
|
|
||||||
Mod+O repeat=false { toggle-overview; }
|
|
||||||
Mod+Tab repeat=false { toggle-overview; }
|
|
||||||
Mod+Slash { show-hotkey-overlay; }
|
|
||||||
Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
|
|
||||||
Mod+Shift+P { power-off-monitors; }
|
|
||||||
Mod+Shift+E { quit; }
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
-- Runs ./build.sh from vis's cwd (project root), logs the output for the
|
|
||||||
-- error picker (pickers.errors), and returns to vis on Enter/Esc.
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
-- last build's output; pickers.errors() reads it
|
|
||||||
M.log = '/tmp/vis-build.log'
|
|
||||||
|
|
||||||
-- single-quote a string for the shell
|
|
||||||
local function q(s) return "'" .. s:gsub("'", "'\\''") .. "'" end
|
|
||||||
|
|
||||||
-- write a raw escape sequence straight to the terminal
|
|
||||||
local function tty(s)
|
|
||||||
local t = io.open('/dev/tty', 'w')
|
|
||||||
if t then t:write(s) t:close() end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function exists(path)
|
|
||||||
local f = io.open(path, 'r')
|
|
||||||
if f then f:close() end
|
|
||||||
return f ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- args: flags passed through to build.sh, e.g. { 'run' }
|
|
||||||
function M.run(args)
|
|
||||||
if not exists('build.sh') then
|
|
||||||
vis:info('No build.sh in current directory')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- save so the build sees your latest changes
|
|
||||||
local file = vis.win and vis.win.file
|
|
||||||
if file and file.modified and file.path then vis:command('w') end
|
|
||||||
|
|
||||||
local parts = {}
|
|
||||||
for _, a in ipairs(args or {}) do parts[#parts + 1] = q(a) end
|
|
||||||
local argstr = table.concat(parts, ' ')
|
|
||||||
|
|
||||||
local script = table.concat({
|
|
||||||
'saved=$(stty -g); stty sane',
|
|
||||||
-- script runs the build on a pty (colors stay on) and logs it to M.log
|
|
||||||
'script -qefc ' .. q('bash ./build.sh ' .. argstr) .. ' ' .. q(M.log),
|
|
||||||
'st=$?',
|
|
||||||
[[printf '\n[exit %s] enter/esc: back to vis ' "$st"]],
|
|
||||||
[[while IFS= read -rsn1 k; do [ -z "$k" ] || [ "$k" = $'\e' ] && break; done]],
|
|
||||||
'stty "$saved"',
|
|
||||||
}, '\n')
|
|
||||||
|
|
||||||
-- leave the alt screen and clear it, so each run starts fresh and the
|
|
||||||
-- output lands in normal scrollback; run; come back to vis
|
|
||||||
tty('\27[?1049l\27[H\27[2J')
|
|
||||||
os.execute('bash -c ' .. q(script) .. ' </dev/tty >/dev/tty 2>&1')
|
|
||||||
tty('\27[?1049h')
|
|
||||||
vis:redraw()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- events
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- re-index tags in the background after saving an .odin file
|
|
||||||
-- (build.sh -t re-scans src and merges it with the cached stdlib tags)
|
|
||||||
vis.events.subscribe(vis.events.FILE_SAVE_POST, function(file, path) -- luacheck: no unused args
|
|
||||||
if path and path:match('%.odin$') and exists('build.sh') then
|
|
||||||
os.execute('bash ./build.sh -t </dev/null >/dev/null 2>&1 &')
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
-- Copyright 2026 Artur Ugnivenko. See LICENSE.
|
|
||||||
-- Odin LPeg lexer.
|
|
||||||
|
|
||||||
-- References:
|
|
||||||
-- https://odin-lang.org/spec/grammar/
|
|
||||||
-- https://pkg.odin-lang.org/base/builtin/
|
|
||||||
|
|
||||||
local lexer = lexer
|
|
||||||
local P, S, R = lpeg.P, lpeg.S, lpeg.R
|
|
||||||
|
|
||||||
local lex = lexer.new(...)
|
|
||||||
|
|
||||||
local ws = S(' \t')^0
|
|
||||||
local word_end = -(lexer.alnum + '_')
|
|
||||||
|
|
||||||
-- Keywords.
|
|
||||||
lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD)))
|
|
||||||
|
|
||||||
-- Definitions: `name :: proc` and `Name :: struct / enum / union / distinct ...`.
|
|
||||||
local proc_def = lex:tag(lexer.FUNCTION, lexer.word) *
|
|
||||||
#(ws * '::' * ws * ('#' * lexer.word * ws)^0 * 'proc' * word_end)
|
|
||||||
local type_def = lex:tag(lexer.TYPE, lexer.word) *
|
|
||||||
#(ws * '::' * ws *
|
|
||||||
(P('struct') + 'enum' + 'union' + 'bit_set' + 'bit_field' + 'distinct') * word_end)
|
|
||||||
lex:add_rule('definition', proc_def + type_def)
|
|
||||||
|
|
||||||
-- Types.
|
|
||||||
lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE)))
|
|
||||||
|
|
||||||
-- Polymorphic parameters: $T, $N.
|
|
||||||
lex:add_rule('poly', lex:tag(lexer.TYPE, '$' * lexer.word))
|
|
||||||
|
|
||||||
-- Functions.
|
|
||||||
local builtin_func = -lpeg.B('.') *
|
|
||||||
lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN))
|
|
||||||
local func = lex:tag(lexer.FUNCTION, lexer.word)
|
|
||||||
lex:add_rule('function', (builtin_func + func) * #P('('))
|
|
||||||
|
|
||||||
-- Constants.
|
|
||||||
lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN)))
|
|
||||||
|
|
||||||
-- Variables.
|
|
||||||
lex:add_rule('variable',
|
|
||||||
lex:tag(lexer.VARIABLE_BUILTIN, lex:word_match(lexer.VARIABLE_BUILTIN)))
|
|
||||||
|
|
||||||
-- Identifiers.
|
|
||||||
lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word))
|
|
||||||
|
|
||||||
-- Strings. Quoted strings end at the line; raw strings span lines, no escapes.
|
|
||||||
local sq_str = lexer.range("'", true)
|
|
||||||
local dq_str = lexer.range('"', true)
|
|
||||||
local raw_str = lexer.range('`', false, false)
|
|
||||||
lex:add_rule('string', lex:tag(lexer.STRING, sq_str + dq_str + raw_str))
|
|
||||||
|
|
||||||
-- Comments.
|
|
||||||
local comment = lexer.to_eol(P('//') + '#!')
|
|
||||||
local block_comment = lexer.range('/*', '*/', false, false, true)
|
|
||||||
local file_tag = lexer.to_eol('#+')
|
|
||||||
lex:add_rule('comment', lex:tag(lexer.COMMENT, comment + block_comment + file_tag))
|
|
||||||
|
|
||||||
-- Directives.
|
|
||||||
lex:add_rule('directive', lex:tag(lexer.PREPROCESSOR, '#' * S(' \t')^0 * lexer.word))
|
|
||||||
|
|
||||||
-- Attributes.
|
|
||||||
lex:add_rule('attribute', lex:tag(lexer.PREPROCESSOR, '@' * lexer.word^-1))
|
|
||||||
|
|
||||||
-- Numbers: 1_000_000, 1.5e-3, 0xff, 0b1010, 0o17, 0z1a (dozenal), 0h3f80_0000 (hex float), 2i.
|
|
||||||
local function digits(d) return d * (P('_')^-1 * d)^0 end
|
|
||||||
local dec = digits(lexer.digit)
|
|
||||||
local float = (dec * '.' * dec^-1 * -P('.') + '.' * dec) * (S('eE') * S('+-')^-1 * dec)^-1 +
|
|
||||||
dec * S('eE') * S('+-')^-1 * dec
|
|
||||||
local int = '0' * (
|
|
||||||
S('xh') * P('_')^-1 * digits(lexer.xdigit) +
|
|
||||||
'b' * P('_')^-1 * digits(S('01')) +
|
|
||||||
'o' * P('_')^-1 * digits(R('07')) +
|
|
||||||
'z' * P('_')^-1 * digits(R('09') + S('abAB'))) + dec
|
|
||||||
lex:add_rule('number', lex:tag(lexer.NUMBER, (float + int) * S('ijk')^-1))
|
|
||||||
|
|
||||||
-- Operators.
|
|
||||||
lex:add_rule('operator', lex:tag(lexer.OPERATOR, '..' + S('+-/*%<>!=^&|?~:;,.()[]{}')))
|
|
||||||
|
|
||||||
-- Fold points.
|
|
||||||
lex:add_fold_point(lexer.OPERATOR, '(', ')')
|
|
||||||
lex:add_fold_point(lexer.OPERATOR, '[', ']')
|
|
||||||
lex:add_fold_point(lexer.OPERATOR, '{', '}')
|
|
||||||
lex:add_fold_point(lexer.COMMENT, '/*', '*/')
|
|
||||||
|
|
||||||
-- Word lists.
|
|
||||||
lex:set_word_list(lexer.KEYWORD, {
|
|
||||||
'asm', 'auto_cast', 'bit_field', 'bit_set', 'break', 'case', 'cast', 'continue', 'defer',
|
|
||||||
'distinct', 'do', 'dynamic', 'else', 'enum', 'fallthrough', 'for', 'foreign', 'if', 'import',
|
|
||||||
'in', 'map', 'matrix', 'not_in', 'or_break', 'or_continue', 'or_else', 'or_return', 'package',
|
|
||||||
'proc', 'return', 'struct', 'switch', 'transmute', 'union', 'using', 'when', 'where'
|
|
||||||
})
|
|
||||||
|
|
||||||
lex:set_word_list(lexer.TYPE, {
|
|
||||||
'any', 'b8', 'b16', 'b32', 'b64', 'bool', 'byte', 'complex32', 'complex64', 'complex128',
|
|
||||||
'cstring', 'cstring16', 'f16', 'f16le', 'f16be', 'f32', 'f32le', 'f32be', 'f64', 'f64le', 'f64be',
|
|
||||||
'i8', 'i16', 'i16le', 'i16be', 'i32', 'i32le', 'i32be', 'i64', 'i64le', 'i64be', 'i128',
|
|
||||||
'i128le', 'i128be', 'int', 'quaternion64', 'quaternion128', 'quaternion256', 'rawptr', 'rune',
|
|
||||||
'string', 'string16', 'typeid', 'u8', 'u16', 'u16le', 'u16be', 'u32', 'u32le', 'u32be', 'u64',
|
|
||||||
'u64le', 'u64be', 'u128', 'u128le', 'u128be', 'uint', 'uintptr'
|
|
||||||
})
|
|
||||||
|
|
||||||
lex:set_word_list(lexer.FUNCTION_BUILTIN, {
|
|
||||||
-- compiler built-ins
|
|
||||||
'abs', 'align_of', 'cap', 'clamp', 'complex', 'compress_values', 'conj', 'expand_values', 'imag',
|
|
||||||
'jmag', 'kmag', 'len', 'max', 'min', 'offset_of', 'offset_of_by_string', 'offset_of_member',
|
|
||||||
'offset_of_selector', 'quaternion', 'raw_data', 'real', 'size_of', 'soa_unzip', 'soa_zip',
|
|
||||||
'swizzle', 'type_info_of', 'type_of', 'typeid_of',
|
|
||||||
-- base:runtime procs exported as @(builtin)
|
|
||||||
'append', 'assert', 'card', 'clear', 'copy', 'delete', 'delete_key', 'ensure', 'free',
|
|
||||||
'free_all', 'inject_at', 'make', 'new', 'new_clone', 'ordered_remove', 'panic', 'pop',
|
|
||||||
'pop_front', 'reserve', 'resize', 'shrink', 'unimplemented', 'unordered_remove', 'unreachable'
|
|
||||||
})
|
|
||||||
|
|
||||||
lex:set_word_list(lexer.CONSTANT_BUILTIN, {
|
|
||||||
'false', 'true', 'nil', 'ODIN_ARCH', 'ODIN_BUILD_MODE', 'ODIN_COMPILE_TIMESTAMP', 'ODIN_DEBUG',
|
|
||||||
'ODIN_DEFAULT_TO_NIL_ALLOCATOR', 'ODIN_DEFAULT_TO_PANIC_ALLOCATOR', 'ODIN_DISABLE_ASSERT',
|
|
||||||
'ODIN_ENDIAN', 'ODIN_ERROR_POS_STYLE', 'ODIN_NO_BOUNDS_CHECK', 'ODIN_NO_CRT',
|
|
||||||
'ODIN_NO_ENTRY_POINT', 'ODIN_NO_RTTI', 'ODIN_NO_TYPE_ASSERT', 'ODIN_OPTIMIZATION_MODE',
|
|
||||||
'ODIN_OS', 'ODIN_PLATFORM_SUBTARGET', 'ODIN_ROOT', 'ODIN_TEST', 'ODIN_VENDOR', 'ODIN_VERSION',
|
|
||||||
'ODIN_WINDOWS_SUBSYSTEM'
|
|
||||||
})
|
|
||||||
|
|
||||||
lex:set_word_list(lexer.VARIABLE_BUILTIN, {
|
|
||||||
'context', 'runtime'
|
|
||||||
})
|
|
||||||
|
|
||||||
return lex
|
|
||||||
@@ -1,285 +0,0 @@
|
|||||||
-- pickers: fuzzy file finder, live ripgrep, build errors, yazi file manager, gitu.
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
-- height of the drop-down fzf panel at the top ('100%' = full screen)
|
|
||||||
M.height = '100%'
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- shared constants
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
local BAT = 'bat --theme=custom_zen --color=always --style=numbers'
|
|
||||||
local PREVIEW_FILE = BAT .. ' --line-range=:500 {}' -- {} = path
|
|
||||||
local PREVIEW_AT = BAT .. ' --highlight-line {2} {1}' -- {1}=path {2}=line
|
|
||||||
|
|
||||||
local KEYS_NAV = 'ctrl-n:down,ctrl-p:up'
|
|
||||||
local KEYS_PREVIEW = 'ctrl-/:toggle-preview,shift-up:preview-up,shift-down:preview-down'
|
|
||||||
|
|
||||||
-- an Odin error line (-error-pos-style:unix): path.odin:line:col: message
|
|
||||||
local ERROR_PATTERN = '^(.-%.odin):(%d+):(%d+):'
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- helpers
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- single-quote a string for the shell
|
|
||||||
local function q(s)
|
|
||||||
return "'" .. s:gsub("'", "'\\''") .. "'"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- write a raw escape sequence straight to the terminal
|
|
||||||
local function tty_write(seq)
|
|
||||||
local tty = io.open('/dev/tty', 'w')
|
|
||||||
if tty then
|
|
||||||
tty:write(seq)
|
|
||||||
tty:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- hand the terminal back to vis: re-enter the alt screen and repaint
|
|
||||||
local function restore_screen()
|
|
||||||
tty_write('\27[?1049h')
|
|
||||||
vis:redraw()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- fzf command line: common flags + a list of extra options
|
|
||||||
local function fzf(prompt, opts)
|
|
||||||
return 'fzf --height=' .. M.height .. ' --layout=reverse --border'
|
|
||||||
.. ' --prompt ' .. q(prompt) .. ' ' .. table.concat(opts, ' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
-- "--flag 'value'"
|
|
||||||
local function opt(flag, value)
|
|
||||||
return flag .. ' ' .. q(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- run an fzf pipeline; returns its output lines and exit code
|
|
||||||
local function run_fzf(cmd)
|
|
||||||
-- --height mode draws from the cursor down, so start at the top-left
|
|
||||||
tty_write('\27[H')
|
|
||||||
|
|
||||||
local handle = io.popen(cmd)
|
|
||||||
if not handle then
|
|
||||||
vis:info('fzf: failed to start')
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local lines = {}
|
|
||||||
for line in handle:lines() do table.insert(lines, line) end
|
|
||||||
local _, _, code = handle:close()
|
|
||||||
|
|
||||||
restore_screen()
|
|
||||||
return lines, code
|
|
||||||
end
|
|
||||||
|
|
||||||
-- open a path in the current window, unless it's already the current file.
|
|
||||||
-- returns false if the buffer has unsaved changes and nothing was opened
|
|
||||||
local function open_path(path)
|
|
||||||
local win = vis.win
|
|
||||||
local current = win and win.file and win.file.path
|
|
||||||
if current and (current == path or current:sub(-#path - 1) == '/' .. path) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if win and win.file and win.file.modified then
|
|
||||||
vis:info('Buffer has unsaved changes — :w first (or use :e! manually)')
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
vis:command(string.format("e '%s'", path))
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- files: fuzzy-find a file, or create one from the query
|
|
||||||
-- enter open in the current window
|
|
||||||
-- ctrl-v open in a vertical split
|
|
||||||
-- alt-enter create a file named after the query
|
|
||||||
-- ctrl-n/p move down/up
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
function M.files()
|
|
||||||
local cmd = 'fd --type f --hidden --exclude .git | ' .. fzf('files> ', {
|
|
||||||
'--print-query --expect=alt-enter,ctrl-v', -- output: query, key, choice
|
|
||||||
opt('--header', 'enter: open · alt-enter: new file · ctrl-v: vsplit'),
|
|
||||||
opt('--preview', PREVIEW_FILE),
|
|
||||||
opt('--preview-window', 'down:75%:border-top'),
|
|
||||||
opt('--bind', KEYS_NAV),
|
|
||||||
opt('--bind', KEYS_PREVIEW),
|
|
||||||
})
|
|
||||||
|
|
||||||
local out, code = run_fzf(cmd)
|
|
||||||
if not out or code == 130 then return end -- failed, or Esc / Ctrl-C
|
|
||||||
|
|
||||||
local query, key, choice = out[1], out[2], out[3]
|
|
||||||
local is_new = key == 'alt-enter' or not choice or choice == ''
|
|
||||||
local path = is_new and query or choice
|
|
||||||
if not path or path == '' then return end
|
|
||||||
|
|
||||||
if key == 'ctrl-v' then
|
|
||||||
vis:command(string.format("vsplit '%s'", path))
|
|
||||||
elseif not open_path(path) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_new then
|
|
||||||
vis:info('New file: ' .. path .. ' (written to disk on :w)')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- grep: live ripgrep search across the project, jump to the match
|
|
||||||
-- M.grep() start empty, results appear as you type
|
|
||||||
-- M.grep_selection() visual mode: start with the selected text
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
local function grep_with(query)
|
|
||||||
-- don't run rg on an empty query (it would match every line)
|
|
||||||
local reload = '[ -n {q} ] && rg --column --line-number --no-heading'
|
|
||||||
.. ' --color=always --smart-case --hidden --glob "!.git" -- {q} || true'
|
|
||||||
|
|
||||||
local opts = {
|
|
||||||
'--ansi --disabled', -- let rg do the matching, not fzf
|
|
||||||
'--delimiter :', -- fields: path:line:col:text
|
|
||||||
opt('--bind', 'change:reload:' .. reload),
|
|
||||||
opt('--preview', PREVIEW_AT),
|
|
||||||
opt('--preview-window', 'down:90%:border-top:+{2}/2'),
|
|
||||||
opt('--bind', KEYS_PREVIEW),
|
|
||||||
}
|
|
||||||
if query then
|
|
||||||
table.insert(opts, opt('--query', query))
|
|
||||||
table.insert(opts, opt('--bind', 'start:reload:' .. reload))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- empty stdin: results only appear once there is a query
|
|
||||||
local out = run_fzf(': | ' .. fzf('rg> ', opts))
|
|
||||||
local choice = out and out[1]
|
|
||||||
if not choice or choice == '' then return end
|
|
||||||
|
|
||||||
choice = choice:gsub('\27%[[%d;]*m', '') -- strip colour codes
|
|
||||||
local path, line, col = choice:match('^(.-):(%d+):(%d+):')
|
|
||||||
if not path or not open_path(path) then return end
|
|
||||||
|
|
||||||
vis.win.selection:to(tonumber(line), tonumber(col))
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.grep()
|
|
||||||
grep_with(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.grep_selection()
|
|
||||||
local win = vis.win
|
|
||||||
local text
|
|
||||||
if win and win.file and win.selection.range then
|
|
||||||
text = win.file:content(win.selection.range)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- leave visual mode before fzf takes over the screen
|
|
||||||
vis.mode = vis.modes.NORMAL
|
|
||||||
|
|
||||||
-- first line of the selection only; nothing usable -> plain grep
|
|
||||||
text = text and text:match('^[^\n]*')
|
|
||||||
if not text or text:match('^%s*$') then
|
|
||||||
grep_with(nil)
|
|
||||||
else
|
|
||||||
grep_with(text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- errors: browse the errors from the last build (the log build.lua writes)
|
|
||||||
-- enter jump to the error
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
function M.errors()
|
|
||||||
local f = io.open(require('build').log, 'r')
|
|
||||||
if not f then
|
|
||||||
vis:info('No build log yet — run a build first')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- keep only the path.odin:line:col: lines; the log comes from a pty, so
|
|
||||||
-- strip colour escapes and carriage returns first
|
|
||||||
local errors = {}
|
|
||||||
for line in f:lines() do
|
|
||||||
local clean = line:gsub('\27%[[%d;?]*%a', ''):gsub('\r', '')
|
|
||||||
if clean:match(ERROR_PATTERN) then table.insert(errors, clean) end
|
|
||||||
end
|
|
||||||
f:close()
|
|
||||||
|
|
||||||
if #errors == 0 then
|
|
||||||
vis:info('No errors in the last build')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local tmp = os.tmpname()
|
|
||||||
f = io.open(tmp, 'w')
|
|
||||||
if not f then
|
|
||||||
vis:info('errors: cannot write temp file')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
f:write(table.concat(errors, '\n'), '\n')
|
|
||||||
f:close()
|
|
||||||
|
|
||||||
local cmd = fzf('errors> ', {
|
|
||||||
'--no-sort', -- keep build order: the first error is the one to fix first
|
|
||||||
'--delimiter :',
|
|
||||||
opt('--preview', PREVIEW_AT),
|
|
||||||
opt('--preview-window', 'down:75%:border-top:+{2}/2'),
|
|
||||||
opt('--bind', KEYS_NAV),
|
|
||||||
opt('--bind', KEYS_PREVIEW),
|
|
||||||
}) .. ' < ' .. q(tmp)
|
|
||||||
|
|
||||||
local out = run_fzf(cmd)
|
|
||||||
os.remove(tmp)
|
|
||||||
|
|
||||||
local choice = out and out[1]
|
|
||||||
if not choice or choice == '' then return end
|
|
||||||
|
|
||||||
local path, line, col = choice:match(ERROR_PATTERN)
|
|
||||||
if not path or not open_path(path) then return end
|
|
||||||
|
|
||||||
vis.win.selection:to(tonumber(line), tonumber(col))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- fm: browse/create/rename/delete in yazi, then open the file you pick
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
function M.fm()
|
|
||||||
local tmp = os.tmpname()
|
|
||||||
|
|
||||||
os.execute(string.format("yazi --chooser-file='%s' </dev/tty >/dev/tty 2>&1", tmp))
|
|
||||||
restore_screen()
|
|
||||||
|
|
||||||
local f = io.open(tmp, 'r')
|
|
||||||
local path = f and f:read('*l')
|
|
||||||
if f then f:close() end
|
|
||||||
os.remove(tmp)
|
|
||||||
|
|
||||||
if path and path ~= '' then open_path(path) end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- git: run gitu, then hand the screen back to vis
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
function M.git()
|
|
||||||
tty_write('\27[?1049l')
|
|
||||||
os.execute('gitu </dev/tty >/dev/tty 2>&1')
|
|
||||||
restore_screen()
|
|
||||||
|
|
||||||
-- gitu may have changed files on disk (checkout, discard, stash, ...):
|
|
||||||
-- reload the current buffer if there's nothing unsaved to lose
|
|
||||||
local win = vis.win
|
|
||||||
if win and win.file and win.file.path and not win.file.modified then
|
|
||||||
vis:command('e!')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- events
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- create missing parent directories on save, so a new file like
|
|
||||||
-- src/util/new.odin can be written even if src/util/ doesn't exist yet
|
|
||||||
vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file, path) -- luacheck: no unused args
|
|
||||||
local dir = path and path:match('^(.*)/[^/]+$')
|
|
||||||
if dir and dir ~= '' then
|
|
||||||
os.execute('mkdir -p ' .. q(dir))
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end)
|
|
||||||
|
|
||||||
return M
|
|
||||||
Submodule config/vis/plugins/vis-ctags deleted from 40a537beaf
@@ -1,59 +0,0 @@
|
|||||||
-- vis-minimal-jellybeans-soft
|
|
||||||
-- Dark neutral background, warm off-white, and muted, low-brightness accents
|
|
||||||
|
|
||||||
local bg_dark = '#131313' -- Dark off-black background instead of harsh pure black
|
|
||||||
local black1 = '#303030'
|
|
||||||
local black2 = '#585858'
|
|
||||||
|
|
||||||
local offwhite0 = '#b9b9b9' -- Softened off-white base (reduces glare)
|
|
||||||
local offwhite1 = '#b0b0b0'
|
|
||||||
local offwhite2 = '#888888'
|
|
||||||
|
|
||||||
local clear0 = '#00000000'
|
|
||||||
|
|
||||||
-- Darkened, lower-contrast Jellybeans accents
|
|
||||||
local jelly_yellow_muted = '#d9b36a' -- Subdued warm yellow (Methods / Functions)
|
|
||||||
local jelly_blue_muted = '#75a0bc' -- Muted ice blue (Types / Classes)
|
|
||||||
|
|
||||||
local lexers = vis.lexers
|
|
||||||
|
|
||||||
-- Default Softened Base
|
|
||||||
lexers.STYLE_DEFAULT = 'back:'..clear0..',fore:'..offwhite0
|
|
||||||
lexers.STYLE_NOTHING = 'back:'..bg_dark
|
|
||||||
lexers.STYLE_COMMENT = 'fore:'..black2
|
|
||||||
lexers.STYLE_ERROR = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_WHITESPACE = ''
|
|
||||||
lexers.STYLE_EMBEDDED = 'back:'..black1
|
|
||||||
|
|
||||||
-- The ONLY Colored Highlights (Deepened / Softened)
|
|
||||||
lexers.STYLE_FUNCTION = 'fore:'..jelly_yellow_muted
|
|
||||||
lexers.STYLE_TYPE = 'fore:'..jelly_blue_muted
|
|
||||||
lexers.STYLE_CLASS = 'fore:'..jelly_blue_muted
|
|
||||||
|
|
||||||
-- Neutral / Off-White Text
|
|
||||||
lexers.STYLE_VARIABLE = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_IDENTIFIER = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_KEYWORD = 'fore:'..offwhite2
|
|
||||||
lexers.STYLE_CONSTANT = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_DEFINITION = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_LABEL = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_NUMBER = 'fore:'..offwhite1
|
|
||||||
lexers.STYLE_OPERATOR = 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_REGEX = 'fore:'..offwhite1
|
|
||||||
lexers.STYLE_STRING = 'fore:'..offwhite1
|
|
||||||
lexers.STYLE_PREPROCESSOR= 'fore:'..offwhite0
|
|
||||||
lexers.STYLE_TAG = 'fore:'..offwhite0
|
|
||||||
|
|
||||||
-- Editor Interface UI
|
|
||||||
lexers.STYLE_LINENUMBER = 'fore:'..black2
|
|
||||||
lexers.STYLE_LINENUMBER_CURSOR = 'fore:'..offwhite1
|
|
||||||
lexers.STYLE_CURSOR = 'back:'..offwhite2
|
|
||||||
lexers.STYLE_CURSOR_PRIMARY = lexers.STYLE_CURSOR..',fore:'..bg_dark
|
|
||||||
lexers.STYLE_CURSOR_LINE = 'underlined'
|
|
||||||
lexers.STYLE_COLOR_COLUMN = 'back:'..black1
|
|
||||||
lexers.STYLE_SELECTION = 'back:'..black1
|
|
||||||
lexers.STYLE_STATUS = 'reverse'
|
|
||||||
lexers.STYLE_STATUS_FOCUSED = 'back:'..black1..',fore:'..offwhite1
|
|
||||||
lexers.STYLE_SEPARATOR = lexers.STYLE_DEFAULT
|
|
||||||
lexers.STYLE_INFO = 'fore:default,back:default'
|
|
||||||
lexers.STYLE_EOF = ''
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
local lexers = vis.lexers
|
|
||||||
|
|
||||||
lexers.STYLE_DEFAULT = 'fore:#d7d7d7,back:#131313'
|
|
||||||
lexers.STYLE_NOTHING = ''
|
|
||||||
lexers.STYLE_CLASS = 'fore:#c4bd97'
|
|
||||||
lexers.STYLE_COMMENT = 'fore:#7d6d5d'
|
|
||||||
lexers.STYLE_CONSTANT = 'fore:#cdadad,bold'
|
|
||||||
lexers.STYLE_DEFINITION = 'fore:#f2d1af,bold'
|
|
||||||
lexers.STYLE_ERROR = 'fore:#8bc8aa,back:#303030,bold'
|
|
||||||
lexers.STYLE_FUNCTION = 'fore:#7a96b0'
|
|
||||||
lexers.STYLE_KEYWORD = 'fore:#787879,bold'
|
|
||||||
lexers.STYLE_LABEL = 'fore:#7a96b0'
|
|
||||||
lexers.STYLE_NUMBER = 'fore:#87d7d7'
|
|
||||||
lexers.STYLE_OPERATOR = 'fore:#d5ce90'
|
|
||||||
lexers.STYLE_REGEX = 'fore:#d0c195'
|
|
||||||
lexers.STYLE_STRING = 'fore:#6c836c'
|
|
||||||
lexers.STYLE_PREPROCESSOR = 'fore:#f2d1af,bold'
|
|
||||||
lexers.STYLE_TAG = 'fore:#cdadad,bold'
|
|
||||||
lexers.STYLE_TYPE = 'fore:#7a96b0,bold'
|
|
||||||
lexers.STYLE_VARIABLE = 'fore:#c9ba9c'
|
|
||||||
lexers.STYLE_WHITESPACE = ''
|
|
||||||
lexers.STYLE_EMBEDDED = 'fore:#c09494'
|
|
||||||
lexers.STYLE_IDENTIFIER = ''
|
|
||||||
|
|
||||||
lexers.STYLE_LINENUMBER = 'fore:#585858'
|
|
||||||
lexers.STYLE_LINENUMBER_CURSOR = 'fore:#666666'
|
|
||||||
lexers.STYLE_CURSOR = 'back:#585858,keep_attribute'
|
|
||||||
lexers.STYLE_CURSOR_PRIMARY = 'fore:#1c1c1c,back:#87afaf,bold,keep_attribute'
|
|
||||||
lexers.STYLE_CURSOR_LINE = 'back:#444444,keep_attribute'
|
|
||||||
lexers.STYLE_COLOR_COLUMN = 'back:#444444'
|
|
||||||
lexers.STYLE_SELECTION = 'back:#4a604a'
|
|
||||||
lexers.STYLE_STATUS = 'back:#262626,fore:#6c836c'
|
|
||||||
lexers.STYLE_STATUS_FOCUSED = 'back:#303030,fore:#cacaca,bold'
|
|
||||||
lexers.STYLE_SEPARATOR = ''
|
|
||||||
lexers.STYLE_INFO = ''
|
|
||||||
lexers.STYLE_EOF = 'fore:#585858'
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
require('vis')
|
|
||||||
require('plugins/vis-ctags')
|
|
||||||
|
|
||||||
local build = require('build')
|
|
||||||
local pickers = require('pickers')
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Global options, key mappings and commands
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
vis.events.subscribe(vis.events.INIT, function()
|
|
||||||
vis:command('set escdelay 1')
|
|
||||||
vis:command('set autoindent off')
|
|
||||||
vis:command('set ignorecase on')
|
|
||||||
vis:command('set theme custom_zen')
|
|
||||||
|
|
||||||
-- jump list
|
|
||||||
vis:map(vis.modes.NORMAL, "<M-j>", "g>")
|
|
||||||
vis:map(vis.modes.NORMAL, "<M-k>", "g<")
|
|
||||||
|
|
||||||
-- pickers
|
|
||||||
vis:map(vis.modes.NORMAL, '<C-p>', pickers.files, 'Fuzzy find / create a file')
|
|
||||||
vis:map(vis.modes.NORMAL, '<C-f>', pickers.grep, 'Live grep the project with ripgrep')
|
|
||||||
vis:map(vis.modes.VISUAL, '<C-f>', pickers.grep_selection, 'Live grep for the selected text')
|
|
||||||
vis:map(vis.modes.NORMAL, '<C-e>', pickers.fm, 'terminal file manager')
|
|
||||||
vis:map(vis.modes.NORMAL, '<M-e>', pickers.errors, 'Browse errors from the last build')
|
|
||||||
|
|
||||||
-- picker commands
|
|
||||||
vis:command_register('files', function() pickers.files() return true end, 'Fuzzy find / create a file')
|
|
||||||
vis:command_register('grep', function() pickers.grep() return true end, 'Live grep the project with ripgrep')
|
|
||||||
vis:command_register('fm', function() pickers.fm() return true end, 'Pick a file with a terminal file manager')
|
|
||||||
vis:command_register('git', function() pickers.git() return true end, 'Open gitu')
|
|
||||||
vis:command_register('errors', function() pickers.errors() return true end, 'Browse errors from the last build')
|
|
||||||
|
|
||||||
-- build.sh setup
|
|
||||||
vis:map(vis.modes.NORMAL, '<C-b>', function() build.run({}) end, 'Run ./build.sh')
|
|
||||||
vis:command_register('build', function(argv)
|
|
||||||
local args = {}
|
|
||||||
for i = 1, #argv do table.insert(args, argv[i]) end
|
|
||||||
build.run(args)
|
|
||||||
return true
|
|
||||||
end, 'Run ./build.sh with optional flags, e.g :build run')
|
|
||||||
|
|
||||||
-- system clipboard
|
|
||||||
local function clip_copy()
|
|
||||||
vis:feedkeys(':>wl-copy 2>/dev/null<Enter>')
|
|
||||||
vis:feedkeys('<Escape>') -- drop the selection / leave visual mode
|
|
||||||
end
|
|
||||||
|
|
||||||
local function clip_paste()
|
|
||||||
vis:feedkeys(':<wl-paste --no-newline<Enter>')
|
|
||||||
vis:feedkeys('<Escape>') -- clear any selection left on the pasted text
|
|
||||||
end
|
|
||||||
|
|
||||||
vis:map(vis.modes.VISUAL, '<C-c>', clip_copy, 'Copy selection to system clipboard')
|
|
||||||
vis:map(vis.modes.VISUAL, '<C-v>', clip_paste, 'Paste system clipboard at cursor')
|
|
||||||
vis:map(vis.modes.NORMAL, '<C-v>', clip_paste, 'Paste system clipboard at cursor')
|
|
||||||
|
|
||||||
-- ctag navigation
|
|
||||||
vis:map(vis.modes.NORMAL, 'gd', '<C-]>', 'Go to definition (ctags picker)')
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Per-window options
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
vis.events.subscribe(vis.events.WIN_OPEN, function(win)
|
|
||||||
vis:command('set tabwidth 4')
|
|
||||||
vis:command('set expandtab on')
|
|
||||||
vis:command('set number on')
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Syntax highlighting: ~/.config/vis/lexers/odin.lua
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
if vis.ftdetect then
|
|
||||||
-- vis 0.9 and earlier
|
|
||||||
if vis.ftdetect.filetypes then
|
|
||||||
vis.ftdetect.filetypes.odin = { ext = { '%.odin$' } }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- On save: strip trailing spaces/tabs and extra blank lines at the end of
|
|
||||||
-- the file. Skips files where trailing whitespace means something.
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
local keep_whitespace = { md = true, markdown = true, diff = true, patch = true }
|
|
||||||
|
|
||||||
vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file, path)
|
|
||||||
local ext = path and path:match('%.(%w+)$')
|
|
||||||
if ext and keep_whitespace[ext:lower()] then return true end
|
|
||||||
|
|
||||||
-- trailing spaces/tabs (not \r, so CRLF files stay CRLF);
|
|
||||||
-- read every line first, then rewrite only the ones that changed
|
|
||||||
local trimmed, n = {}, 0
|
|
||||||
for line in file:lines_iterator() do
|
|
||||||
n = n + 1
|
|
||||||
local s = line:find('[ \t]+$')
|
|
||||||
if s then trimmed[n] = line:sub(1, s - 1) end
|
|
||||||
end
|
|
||||||
for i, line in pairs(trimmed) do file.lines[i] = line end
|
|
||||||
|
|
||||||
-- blank lines at the end: keep exactly one final newline
|
|
||||||
local size = file.size
|
|
||||||
local tail = file:content(math.max(0, size - 256), math.min(size, 256))
|
|
||||||
local extra = tail:match('\n(\n+)$')
|
|
||||||
if extra then file:delete(size - #extra, #extra) end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end)
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
[app]
|
|
||||||
overall = { bg = "#131313" }
|
|
||||||
|
|
||||||
[icon]
|
|
||||||
dirs = []
|
|
||||||
prepend_conds = [ { if = "dir", text = ">", fg = "#7a96b0" } ]
|
|
||||||
|
|
||||||
|
|
||||||
[mgr]
|
|
||||||
cwd = { fg = "#7a96b0", bold = true }
|
|
||||||
find_keyword = { fg = "#f2d1af", bold = true }
|
|
||||||
find_position = { fg = "#87d7d7" }
|
|
||||||
symlink_target = { fg = "#87afaf", italic = true }
|
|
||||||
|
|
||||||
marker_copied = { fg = "#6c836c", bg = "#6c836c" }
|
|
||||||
marker_cut = { fg = "#cdadad", bg = "#cdadad" }
|
|
||||||
marker_marked = { fg = "#f2d1af", bg = "#f2d1af" }
|
|
||||||
marker_selected = { fg = "#7a96b0", bg = "#7a96b0" }
|
|
||||||
|
|
||||||
count_copied = { fg = "#131313", bg = "#6c836c" }
|
|
||||||
count_cut = { fg = "#131313", bg = "#cdadad" }
|
|
||||||
count_selected = { fg = "#131313", bg = "#7a96b0" }
|
|
||||||
|
|
||||||
border_style = { fg = "#585858" }
|
|
||||||
|
|
||||||
# code preview uses the same theme file as bat
|
|
||||||
syntect_theme = "/home/jason/.config/bat/themes/custom_zen.tmTheme"
|
|
||||||
|
|
||||||
[indicator]
|
|
||||||
parent = { bg = "#303030" }
|
|
||||||
current = { bg = "#444444" }
|
|
||||||
preview = { bg = "#303030" }
|
|
||||||
|
|
||||||
[tabs]
|
|
||||||
active = { fg = "#131313", bg = "#7a96b0", bold = true }
|
|
||||||
inactive = { fg = "#d7d7d7", bg = "#303030" }
|
|
||||||
|
|
||||||
[mode]
|
|
||||||
normal_main = { fg = "#131313", bg = "#7a96b0", bold = true }
|
|
||||||
normal_alt = { fg = "#7a96b0", bg = "#303030" }
|
|
||||||
select_main = { fg = "#131313", bg = "#6c836c", bold = true }
|
|
||||||
select_alt = { fg = "#6c836c", bg = "#303030" }
|
|
||||||
unset_main = { fg = "#131313", bg = "#cdadad", bold = true }
|
|
||||||
unset_alt = { fg = "#cdadad", bg = "#303030" }
|
|
||||||
|
|
||||||
[status]
|
|
||||||
overall = { fg = "#d7d7d7", bg = "#262626" }
|
|
||||||
perm_sep = { fg = "#585858" }
|
|
||||||
perm_type = { fg = "#7a96b0" }
|
|
||||||
perm_read = { fg = "#a0a0a0" }
|
|
||||||
perm_write = { fg = "#cdadad" }
|
|
||||||
perm_exec = { fg = "#6c836c" }
|
|
||||||
progress_label = { fg = "#d7d7d7", bold = true }
|
|
||||||
progress_normal = { fg = "#7a96b0", bg = "#303030" }
|
|
||||||
progress_error = { fg = "#cdadad", bg = "#303030" }
|
|
||||||
|
|
||||||
[which]
|
|
||||||
border = { fg = "#585858" }
|
|
||||||
mask = { bg = "#262626" }
|
|
||||||
cand = { fg = "#87d7d7" }
|
|
||||||
rest = { fg = "#585858" }
|
|
||||||
desc = { fg = "#a0a0a0" }
|
|
||||||
separator_style = { fg = "#585858" }
|
|
||||||
|
|
||||||
[confirm]
|
|
||||||
border = { fg = "#7a96b0" }
|
|
||||||
title = { fg = "#7a96b0" }
|
|
||||||
btn_yes = { fg = "#131313", bg = "#7a96b0" }
|
|
||||||
btn_no = { fg = "#d7d7d7", bg = "#303030" }
|
|
||||||
|
|
||||||
[spot]
|
|
||||||
border = { fg = "#7a96b0" }
|
|
||||||
title = { fg = "#7a96b0" }
|
|
||||||
tbl_col = { fg = "#7a96b0" }
|
|
||||||
tbl_cell = { fg = "#d7d7d7", bg = "#444444" }
|
|
||||||
|
|
||||||
[notify]
|
|
||||||
title_info = { fg = "#6c836c" }
|
|
||||||
title_warn = { fg = "#f2d1af" }
|
|
||||||
title_error = { fg = "#cdadad" }
|
|
||||||
|
|
||||||
[pick]
|
|
||||||
border = { fg = "#7a96b0" }
|
|
||||||
active = { fg = "#cdadad", bold = true }
|
|
||||||
|
|
||||||
[input]
|
|
||||||
border = { fg = "#7a96b0" }
|
|
||||||
selected = { bg = "#4a604a" }
|
|
||||||
|
|
||||||
[cmp]
|
|
||||||
border = { fg = "#7a96b0" }
|
|
||||||
active = { bg = "#444444" }
|
|
||||||
|
|
||||||
[tasks]
|
|
||||||
border = { fg = "#7a96b0" }
|
|
||||||
hovered = { fg = "#cdadad", underline = true }
|
|
||||||
|
|
||||||
[help]
|
|
||||||
border = { fg = "#585858" }
|
|
||||||
chord = { fg = "#87d7d7" }
|
|
||||||
action = { fg = "#6c836c" }
|
|
||||||
hovered = { bg = "#444444" }
|
|
||||||
|
|
||||||
[filetype]
|
|
||||||
rules = [
|
|
||||||
# images
|
|
||||||
{ mime = "image/*", fg = "#87d7d7" },
|
|
||||||
# audio / video
|
|
||||||
{ mime = "{audio,video}/*", fg = "#f2d1af" },
|
|
||||||
# archives
|
|
||||||
{ mime = "application/{zip,gzip,x-tar,x-bzip*,x-xz,x-7z-compressed,x-rar}", fg = "#cdadad" },
|
|
||||||
# documents
|
|
||||||
{ mime = "application/{pdf,doc,rtf}", fg = "#a0a0a0" },
|
|
||||||
# special files
|
|
||||||
{ url = "*", is = "orphan", fg = "#131313", bg = "#cdadad" },
|
|
||||||
{ url = "*", is = "exec", fg = "#6c836c" },
|
|
||||||
# directories
|
|
||||||
{ url = "*/", fg = "#7a96b0" },
|
|
||||||
]
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"folders":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"path": "."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,516 +0,0 @@
|
|||||||
{
|
|
||||||
"auto_complete":
|
|
||||||
{
|
|
||||||
"selected_items":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"buffers":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"file": "config/fish/config.fish",
|
|
||||||
"file_size": 4388,
|
|
||||||
"file_write_time": 134353912965388191,
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"buffer_size": 4386,
|
|
||||||
"encoding": "UTF-8",
|
|
||||||
"line_ending": "Unix"
|
|
||||||
},
|
|
||||||
"undo_stack":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
12,
|
|
||||||
1,
|
|
||||||
"nv_vi_o",
|
|
||||||
{
|
|
||||||
"count": 1,
|
|
||||||
"mode": "mode_internal_normal",
|
|
||||||
"register": "\""
|
|
||||||
},
|
|
||||||
"AQAAAOgCAAAAAAAA6QIAAAAAAAAAAAAA",
|
|
||||||
"CgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAA0wIAAAAAAADTAgAAAAAAAAAAAAAAAPC/"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
14,
|
|
||||||
1,
|
|
||||||
"nv_vi_paste",
|
|
||||||
{
|
|
||||||
"before_cursor": false,
|
|
||||||
"count": 1,
|
|
||||||
"mode": "mode_internal_normal",
|
|
||||||
"register": "\""
|
|
||||||
},
|
|
||||||
"AQAAAOoCAAAAAAAAIAMAAAAAAAAAAAAA",
|
|
||||||
"CgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAA6QIAAAAAAADpAgAAAAAAAAAAAAAAAPC/"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
17,
|
|
||||||
1,
|
|
||||||
"nv_vi_d",
|
|
||||||
{
|
|
||||||
"count": 1,
|
|
||||||
"mode": "mode_visual_line",
|
|
||||||
"register": "\""
|
|
||||||
},
|
|
||||||
"AQAAAOkCAAAAAAAA6QIAAAAAAAABAAAACg",
|
|
||||||
"CgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAA6QIAAAAAAADqAgAAAAAAAAAAAAAAAPC/"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
18,
|
|
||||||
1,
|
|
||||||
"nv_vi_o",
|
|
||||||
{
|
|
||||||
"count": 1,
|
|
||||||
"mode": "mode_internal_normal",
|
|
||||||
"register": "\""
|
|
||||||
},
|
|
||||||
"AQAAAB8DAAAAAAAAIAMAAAAAAAAAAAAA",
|
|
||||||
"CgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAA6QIAAAAAAADpAgAAAAAAAAAAAAAAAPC/"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
30,
|
|
||||||
1,
|
|
||||||
"sequence",
|
|
||||||
{
|
|
||||||
"commands":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"nv_vi_c",
|
|
||||||
{
|
|
||||||
"count": 1,
|
|
||||||
"mode": "mode_visual",
|
|
||||||
"register": "\""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"insert",
|
|
||||||
{
|
|
||||||
"characters": "home/jason/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"insert",
|
|
||||||
{
|
|
||||||
"characters": "ThirdPart"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"insert",
|
|
||||||
{
|
|
||||||
"characters": "y/ols"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"GgAAAAYDAAAAAAAABgMAAAAAAAAQAAAAcGF0aC90by9vbHMvcmVwbwYDAAAAAAAABwMAAAAAAAAAAAAABwMAAAAAAAAIAwAAAAAAAAAAAAAIAwAAAAAAAAkDAAAAAAAAAAAAAAkDAAAAAAAACgMAAAAAAAAAAAAACgMAAAAAAAALAwAAAAAAAAAAAAALAwAAAAAAAAwDAAAAAAAAAAAAAAwDAAAAAAAADQMAAAAAAAAAAAAADQMAAAAAAAAOAwAAAAAAAAAAAAAOAwAAAAAAAA8DAAAAAAAAAAAAAA8DAAAAAAAAEAMAAAAAAAAAAAAAEAMAAAAAAAARAwAAAAAAAAAAAAARAwAAAAAAABIDAAAAAAAAAAAAABIDAAAAAAAAEwMAAAAAAAAAAAAAEwMAAAAAAAAUAwAAAAAAAAAAAAAUAwAAAAAAABUDAAAAAAAAAAAAABUDAAAAAAAAFgMAAAAAAAAAAAAAFgMAAAAAAAAXAwAAAAAAAAAAAAAXAwAAAAAAABgDAAAAAAAAAAAAABgDAAAAAAAAGQMAAAAAAAAAAAAAGQMAAAAAAAAaAwAAAAAAAAAAAAAaAwAAAAAAABsDAAAAAAAAAAAAABsDAAAAAAAAHAMAAAAAAAAAAAAAHAMAAAAAAAAdAwAAAAAAAAAAAAAdAwAAAAAAAB4DAAAAAAAAAAAAAB4DAAAAAAAAHwMAAAAAAAAAAAAA",
|
|
||||||
"CgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAABAAAABgMAAAAAAAAWAwAAAAAAAAAAAAAAAPC/"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
17,
|
|
||||||
1,
|
|
||||||
"nv_vi_d",
|
|
||||||
{
|
|
||||||
"count": 1,
|
|
||||||
"mode": "mode_visual",
|
|
||||||
"register": "\""
|
|
||||||
},
|
|
||||||
"AQAAAGYFAAAAAAAAZgUAAAAAAAAEAAAAZmluZA",
|
|
||||||
"AQAAAAAAAAABAAAAZgUAAAAAAABqBQAAAAAAAAAAAAAAAPC/"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "config/vim/vimrc",
|
|
||||||
"file_size": 2854,
|
|
||||||
"file_write_time": 134345438284510269,
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"buffer_size": 2854,
|
|
||||||
"line_ending": "Unix"
|
|
||||||
},
|
|
||||||
"undo_stack":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"build_system": "",
|
|
||||||
"build_system_choices":
|
|
||||||
[
|
|
||||||
],
|
|
||||||
"build_varint": "",
|
|
||||||
"command_palette":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"last_filter": "",
|
|
||||||
"selected_items":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"lsp res",
|
|
||||||
"LSP: Restart Server"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"lsp",
|
|
||||||
"Preferences: LSP Server Configurations"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"setting",
|
|
||||||
"Preferences: Settings"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"set",
|
|
||||||
"Selection: Expand to Block"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"lsp se",
|
|
||||||
"Preferences: LSP Server Configurations"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"lsp server",
|
|
||||||
"Preferences: LSP Server Configurations"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"inst",
|
|
||||||
"Package Control: Install Package"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"key",
|
|
||||||
"Preferences: Key Bindings"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"remo",
|
|
||||||
"Package Control: Remove Package"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"color",
|
|
||||||
"UI: Select Color Scheme"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"insta",
|
|
||||||
"Package Control: Install Package"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"remove",
|
|
||||||
"Package Control: Remove Package"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"theme",
|
|
||||||
"UI: Customize Theme"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"instal",
|
|
||||||
"Package Control: Install Package"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"color scheme",
|
|
||||||
"UI: Select Color Scheme"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"cust",
|
|
||||||
"UI: Customize Color Scheme"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"settings",
|
|
||||||
"Preferences: Settings"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"pack",
|
|
||||||
"Package Control: Install Package"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"list pac",
|
|
||||||
"Package Control: List Packages"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"package inst",
|
|
||||||
"Package Control: Install Package"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"width": 0.0
|
|
||||||
},
|
|
||||||
"console":
|
|
||||||
{
|
|
||||||
"height": 124.0,
|
|
||||||
"history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"distraction_free":
|
|
||||||
{
|
|
||||||
"menu_visible": true,
|
|
||||||
"show_minimap": false,
|
|
||||||
"show_open_files": false,
|
|
||||||
"show_tabs": false,
|
|
||||||
"side_bar_visible": false,
|
|
||||||
"status_bar_visible": false
|
|
||||||
},
|
|
||||||
"expanded_folders":
|
|
||||||
[
|
|
||||||
"/home/jason/Projects/dotfiles",
|
|
||||||
"/home/jason/Projects/dotfiles/config"
|
|
||||||
],
|
|
||||||
"file_history":
|
|
||||||
[
|
|
||||||
"/home/jason/Projects/Games/pong_raylib/src/audio_manager.odin",
|
|
||||||
"/home/jason/Projects/Games/pong_raylib/src/main.odin",
|
|
||||||
"/home/jason/Projects/Games/pong_raylib/src/entity_player.odin",
|
|
||||||
"/home/jason/.config/sublime-text/Packages/User/LanguageServers.sublime-settings",
|
|
||||||
"/home/jason/.config/sublime-text/Packages/LSP/LanguageServers.sublime-settings",
|
|
||||||
"/home/jason/.config/sublime-text/Packages/User/Mariana.sublime-color-scheme",
|
|
||||||
"/home/jason/.config/sublime-text/Packages/Color Scheme - Default/Mariana.sublime-color-scheme"
|
|
||||||
],
|
|
||||||
"find":
|
|
||||||
{
|
|
||||||
"height": 42.0
|
|
||||||
},
|
|
||||||
"find_in_files":
|
|
||||||
{
|
|
||||||
"height": 158.0,
|
|
||||||
"where_history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"find_state":
|
|
||||||
{
|
|
||||||
"case_sensitive": false,
|
|
||||||
"find_history":
|
|
||||||
[
|
|
||||||
],
|
|
||||||
"highlight": true,
|
|
||||||
"in_selection": false,
|
|
||||||
"preserve_case": false,
|
|
||||||
"regex": false,
|
|
||||||
"replace_history":
|
|
||||||
[
|
|
||||||
],
|
|
||||||
"reverse": false,
|
|
||||||
"scrollbar_highlights": true,
|
|
||||||
"show_context": true,
|
|
||||||
"use_buffer2": true,
|
|
||||||
"use_gitignore": true,
|
|
||||||
"whole_word": false,
|
|
||||||
"wrap": true
|
|
||||||
},
|
|
||||||
"groups":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"sheets":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"buffer": 0,
|
|
||||||
"file": "config/fish/config.fish",
|
|
||||||
"selected": true,
|
|
||||||
"semi_transient": false,
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"buffer_size": 4386,
|
|
||||||
"regions":
|
|
||||||
{
|
|
||||||
},
|
|
||||||
"selection":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
1382,
|
|
||||||
1382
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"_nv_visual_sel_mode": "mode_visual",
|
|
||||||
"lsp_uri": "file:///home/jason/Projects/dotfiles/config/fish/config.fish",
|
|
||||||
"syntax": "Packages/Text/Plain text.tmLanguage",
|
|
||||||
"tab_size": 4,
|
|
||||||
"translate_tabs_to_spaces": true
|
|
||||||
},
|
|
||||||
"translation.x": 0.0,
|
|
||||||
"translation.y": 792.0,
|
|
||||||
"zoom_level": 1.0
|
|
||||||
},
|
|
||||||
"stack_index": 0,
|
|
||||||
"stack_multiselect": false,
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"buffer": 1,
|
|
||||||
"file": "config/vim/vimrc",
|
|
||||||
"semi_transient": false,
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"buffer_size": 2854,
|
|
||||||
"regions":
|
|
||||||
{
|
|
||||||
},
|
|
||||||
"selection":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"highlight_line": false,
|
|
||||||
"lsp_uri": "file:///home/jason/Projects/dotfiles/config/vim/vimrc",
|
|
||||||
"syntax": "Packages/Text/Plain text.tmLanguage",
|
|
||||||
"tab_size": 2,
|
|
||||||
"translate_tabs_to_spaces": true
|
|
||||||
},
|
|
||||||
"translation.x": 0.0,
|
|
||||||
"translation.y": 0.0,
|
|
||||||
"zoom_level": 1.0
|
|
||||||
},
|
|
||||||
"stack_index": 1,
|
|
||||||
"stack_multiselect": false,
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"incremental_find":
|
|
||||||
{
|
|
||||||
"height": 42.0
|
|
||||||
},
|
|
||||||
"input":
|
|
||||||
{
|
|
||||||
"height": 59.0
|
|
||||||
},
|
|
||||||
"layout":
|
|
||||||
{
|
|
||||||
"cells":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"cols":
|
|
||||||
[
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"rows":
|
|
||||||
[
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"menu_visible": true,
|
|
||||||
"output.LSP Log Panel":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"output.diagnostics":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"output.exec":
|
|
||||||
{
|
|
||||||
"height": 1123.0,
|
|
||||||
"history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"output.find_results":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"output.mdpopups":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"history":
|
|
||||||
[
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pinned_build_system": "",
|
|
||||||
"project": "dotfiles.sublime-project",
|
|
||||||
"replace":
|
|
||||||
{
|
|
||||||
"height": 80.0
|
|
||||||
},
|
|
||||||
"save_all_on_build": true,
|
|
||||||
"select_file":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"last_filter": "",
|
|
||||||
"selected_items":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"fish",
|
|
||||||
"config/fish/config.fish"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"main",
|
|
||||||
"src/main.odin"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"ene",
|
|
||||||
"src/entity_player.odin"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"width": 0.0
|
|
||||||
},
|
|
||||||
"select_project":
|
|
||||||
{
|
|
||||||
"height": 500.0,
|
|
||||||
"last_filter": "peb",
|
|
||||||
"selected_items":
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"peb",
|
|
||||||
"~/Projects/pebble/pebble.sublime-project"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"min",
|
|
||||||
"~/Projects/min_editor/min_editor.sublime-project"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"",
|
|
||||||
"~/Projects/dotfiles/dotfiles.sublime-project"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"pong",
|
|
||||||
"~/Projects/pong_raylib/pong_odin.sublime-project"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"dot",
|
|
||||||
"~/Projects/dotfiles/dotfiles.sublime-project"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"width": 380.0
|
|
||||||
},
|
|
||||||
"select_symbol":
|
|
||||||
{
|
|
||||||
"height": 0.0,
|
|
||||||
"last_filter": "",
|
|
||||||
"selected_items":
|
|
||||||
[
|
|
||||||
],
|
|
||||||
"width": 0.0
|
|
||||||
},
|
|
||||||
"selected_group": 0,
|
|
||||||
"settings":
|
|
||||||
{
|
|
||||||
"_vintageous_reset_during_init": true,
|
|
||||||
"lsp_show_inlay_hints": false
|
|
||||||
},
|
|
||||||
"show_minimap": true,
|
|
||||||
"show_open_files": false,
|
|
||||||
"show_tabs": false,
|
|
||||||
"side_bar_visible": true,
|
|
||||||
"side_bar_width": 328.0,
|
|
||||||
"status_bar_visible": true,
|
|
||||||
"template_settings":
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+6
-8
@@ -84,12 +84,9 @@ if [ "$DO_LINKS" = true ]; then
|
|||||||
SKIPPED=0
|
SKIPPED=0
|
||||||
|
|
||||||
# Modern shell & editor setup
|
# Modern shell & editor setup
|
||||||
link_file "$DOTFILES_DIR/config/niri/config.kdl" "$HOME/.config/niri/config.kdl"
|
|
||||||
link_file "$DOTFILES_DIR/config/niri/dms/binds.kdl" "$HOME/.config/niri/dms/binds.kdl"
|
|
||||||
link_file "$DOTFILES_DIR/config/fish/config.fish" "$HOME/.config/fish/config.fish"
|
link_file "$DOTFILES_DIR/config/fish/config.fish" "$HOME/.config/fish/config.fish"
|
||||||
link_file "$DOTFILES_DIR/config/kanata" "$HOME/.config/kanata"
|
link_file "$DOTFILES_DIR/config/kanata" "$HOME/.config/kanata"
|
||||||
link_file "$DOTFILES_DIR/config/vis" "$HOME/.config/vis"
|
link_file "$DOTFILES_DIR/config/emacs" "$HOME/.config/emacs"
|
||||||
link_file "$DOTFILES_DIR/config/yazi" "$HOME/.config/yazi"
|
|
||||||
link_file "$DOTFILES_DIR/scripts/bin" "$HOME/.local/bin"
|
link_file "$DOTFILES_DIR/scripts/bin" "$HOME/.local/bin"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
@@ -152,11 +149,12 @@ if [ "$DO_INSTALL" = true ]; then
|
|||||||
# network & download
|
# network & download
|
||||||
wget curl ca-certificates gnupg rsync
|
wget curl ca-certificates gnupg rsync
|
||||||
# core utilities & CLI tools
|
# core utilities & CLI tools
|
||||||
git vis yazi fd jq fzf ripgrep tree direnv make
|
git fd jq fzf ripgrep tree direnv make
|
||||||
bat ark unzip p7zip tar gzip bzip2 xz kanata
|
bat unzip 7zip tar gzip bzip2 xz ark
|
||||||
|
mpv xfce4-screenshooter xkill xwininfo
|
||||||
|
xdotool wmctrl
|
||||||
# build & dev tools
|
# build & dev tools
|
||||||
alacritty base-devel valgrind tree-sitter-cli go nodejs
|
emacs-x11 alacritty base-devel valgrind go
|
||||||
# cli text editing
|
|
||||||
)
|
)
|
||||||
|
|
||||||
MISSING_PACKAGES=()
|
MISSING_PACKAGES=()
|
||||||
|
|||||||
Executable
+281
@@ -0,0 +1,281 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# focus - small window helpers for xfwm4
|
||||||
|
# focus next|prev move focus right/left through windows (stops at the ends)
|
||||||
|
# focus up|down focus the nearest window directly above/below, if any
|
||||||
|
# focus tile master/stack tiling: active window left, the rest stacked right
|
||||||
|
# (a single window is simply maximized)
|
||||||
|
# Deps: wmctrl xdotool xprop xwininfo
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# ---- config -----------------------------------------------------------------
|
||||||
|
MASTER_RATIO=50 # master width as % of the usable width
|
||||||
|
GAP=0 # px between windows and around the screen edge
|
||||||
|
USE_WORKAREA=1 # 1 = ask xfwm4 for the usable area (already excludes panels)
|
||||||
|
PANEL_TOP=0 # extra px to keep free on each side; if USE_WORKAREA=0,
|
||||||
|
PANEL_BOTTOM=0 # put your panel sizes here instead
|
||||||
|
PANEL_LEFT=0
|
||||||
|
PANEL_RIGHT=0
|
||||||
|
SETTLE=0.05 # seconds to let xfwm4 finish un-maximizing before moving
|
||||||
|
VERIFY=1 # 1 = measure each window afterwards and fix pixel offsets
|
||||||
|
VERIFY_TRIES=2 # correction passes per window
|
||||||
|
|
||||||
|
# ---- generic helpers --------------------------------------------------------
|
||||||
|
die() { echo "${0##*/}: $*" >&2; exit 1; }
|
||||||
|
usage() { echo "usage: ${0##*/} next|prev|up|down|tile" >&2; exit 1; }
|
||||||
|
|
||||||
|
# window geometry from wmctrl, keyed by id (filled by collect_windows)
|
||||||
|
declare -A GX GY GW GH
|
||||||
|
|
||||||
|
need() {
|
||||||
|
local c
|
||||||
|
for c in "$@"; do command -v "$c" >/dev/null || die "missing dependency: $c"; done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Active window id in wmctrl's 0x%08x format (0x00000000 if none)
|
||||||
|
active_window() {
|
||||||
|
local d
|
||||||
|
d=$(xdotool getactivewindow 2>/dev/null) || d=0
|
||||||
|
printf '0x%08x' "$d"
|
||||||
|
}
|
||||||
|
|
||||||
|
# index_of ID -> prints index in WINS, or -1
|
||||||
|
index_of() {
|
||||||
|
local i
|
||||||
|
for i in "${!WINS[@]}"; do
|
||||||
|
[[ ${WINS[i]} == "$1" ]] && { echo "$i"; return; }
|
||||||
|
done
|
||||||
|
echo -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# collect_windows focus|tile -> fills WINS, ordered left to right on screen
|
||||||
|
# (then top to bottom), so "next" moves right and "prev" moves left.
|
||||||
|
# focus: normal windows + dialogs, minimized included (focusing restores them)
|
||||||
|
# vert: normal windows + dialogs, minimized skipped (they have no real position)
|
||||||
|
# tile: normal windows only, minimized skipped
|
||||||
|
collect_windows() {
|
||||||
|
local mode=$1 cur id desk x y w h props
|
||||||
|
local -a found=()
|
||||||
|
cur=$(xdotool get_desktop) || die "cannot read current desktop"
|
||||||
|
WINS=()
|
||||||
|
while read -r id desk x y w h _; do
|
||||||
|
[[ $desk == "$cur" || $desk == -1 ]] || continue # this desktop or sticky
|
||||||
|
props=$(xprop -id "$id" _NET_WM_WINDOW_TYPE _NET_WM_STATE 2>/dev/null) || continue
|
||||||
|
|
||||||
|
if [[ $props == *"_NET_WM_WINDOW_TYPE(ATOM)"* ]]; then
|
||||||
|
if [[ $mode == tile ]]; then
|
||||||
|
[[ $props == *_NET_WM_WINDOW_TYPE_NORMAL* ]] || continue
|
||||||
|
else
|
||||||
|
[[ $props == *_NET_WM_WINDOW_TYPE_NORMAL* || $props == *_NET_WM_WINDOW_TYPE_DIALOG* ]] || continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[[ $props == *_NET_WM_STATE_SKIP_TASKBAR* ]] && continue # panels, desktop, notifyd
|
||||||
|
[[ $mode != focus && $props == *_NET_WM_STATE_HIDDEN* ]] && continue
|
||||||
|
|
||||||
|
GX[$id]=$x GY[$id]=$y GW[$id]=$w GH[$id]=$h
|
||||||
|
|
||||||
|
found+=("$x $y $id")
|
||||||
|
done < <(wmctrl -lG)
|
||||||
|
|
||||||
|
(( ${#found[@]} )) || return 0
|
||||||
|
while read -r _ _ id; do WINS+=("$id"); done < <(printf '%s\n' "${found[@]}" | sort -n -k1,1 -k2,2)
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- focus ------------------------------------------------------------------
|
||||||
|
focus_cycle() {
|
||||||
|
local dir=$1 n idx
|
||||||
|
collect_windows focus
|
||||||
|
n=${#WINS[@]}
|
||||||
|
(( n > 0 )) || return 0
|
||||||
|
|
||||||
|
idx=$(index_of "$(active_window)")
|
||||||
|
if (( idx < 0 )); then
|
||||||
|
# nothing of ours focused (desktop/panel): enter at the matching end
|
||||||
|
[[ $dir == next ]] && idx=0 || idx=$(( n - 1 ))
|
||||||
|
elif [[ $dir == next ]]; then
|
||||||
|
(( idx < n - 1 )) || return 0 # already rightmost: stop, no wrap
|
||||||
|
(( idx += 1 ))
|
||||||
|
else
|
||||||
|
(( idx > 0 )) || return 0 # already leftmost: stop, no wrap
|
||||||
|
(( idx -= 1 ))
|
||||||
|
fi
|
||||||
|
wmctrl -ia "${WINS[idx]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# focus_vertical up|down -- nearest window straight above/below the active one.
|
||||||
|
# "Straight above/below" = shares some horizontal span with it. No match: do nothing.
|
||||||
|
focus_vertical() {
|
||||||
|
local dir=$1 act id ax1 ax2 acy cy dy best="" best_dy=-1
|
||||||
|
collect_windows vert
|
||||||
|
act=$(active_window)
|
||||||
|
[[ -n ${GX[$act]+x} ]] || return 0
|
||||||
|
|
||||||
|
ax1=${GX[$act]}; ax2=$(( ax1 + GW[$act] ))
|
||||||
|
acy=$(( GY[$act] + GH[$act] / 2 ))
|
||||||
|
|
||||||
|
for id in "${WINS[@]}"; do
|
||||||
|
[[ $id == "$act" ]] && continue
|
||||||
|
(( GX[$id] < ax2 && GX[$id] + GW[$id] > ax1 )) || continue # no horizontal overlap
|
||||||
|
cy=$(( GY[$id] + GH[$id] / 2 ))
|
||||||
|
if [[ $dir == up ]]; then dy=$(( acy - cy )); else dy=$(( cy - acy )); fi
|
||||||
|
(( dy > 0 )) || continue # wrong side
|
||||||
|
if (( best_dy < 0 || dy < best_dy )); then best=$id best_dy=$dy; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n $best ]] && wmctrl -ia "$best"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- geometry helpers -------------------------------------------------------
|
||||||
|
# workarea -> WA_X WA_Y WA_W WA_H (usable rectangle on this desktop)
|
||||||
|
workarea() {
|
||||||
|
local cur raw i
|
||||||
|
local -a a
|
||||||
|
cur=$(xdotool get_desktop)
|
||||||
|
raw=$(xprop -root _NET_WORKAREA 2>/dev/null)
|
||||||
|
if (( USE_WORKAREA )) && [[ $raw == *=* ]]; then
|
||||||
|
IFS=', ' read -r -a a <<< "${raw#*= }"
|
||||||
|
i=$(( cur * 4 ))
|
||||||
|
(( i + 3 < ${#a[@]} )) || i=0
|
||||||
|
WA_X=${a[i]} WA_Y=${a[i+1]} WA_W=${a[i+2]} WA_H=${a[i+3]}
|
||||||
|
else
|
||||||
|
read -r WA_W WA_H < <(xdotool getdisplaygeometry)
|
||||||
|
WA_X=0 WA_Y=0
|
||||||
|
fi
|
||||||
|
(( WA_X += PANEL_LEFT, WA_Y += PANEL_TOP,
|
||||||
|
WA_W -= PANEL_LEFT + PANEL_RIGHT, WA_H -= PANEL_TOP + PANEL_BOTTOM ))
|
||||||
|
}
|
||||||
|
|
||||||
|
# frame_extents ID -> FL FR FT FB (decoration size; 0 if not reported)
|
||||||
|
frame_extents() {
|
||||||
|
local raw
|
||||||
|
FL=0 FR=0 FT=0 FB=0
|
||||||
|
raw=$(xprop -id "$1" _NET_FRAME_EXTENTS 2>/dev/null) || return 0
|
||||||
|
[[ $raw == *=* ]] && IFS=', ' read -r FL FR FT FB <<< "${raw#*= }"
|
||||||
|
}
|
||||||
|
|
||||||
|
# client_position ID -> CX CY (real on-screen top-left of the client area)
|
||||||
|
client_position() {
|
||||||
|
read -r CX CY < <(xwininfo -id "$1" 2>/dev/null | awk '
|
||||||
|
/Absolute upper-left X/ {x=$NF} /Absolute upper-left Y/ {y=$NF}
|
||||||
|
END {print x+0, y+0}')
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- window actions ---------------------------------------------------------
|
||||||
|
# Drop states that make xfwm4 ignore move/resize (maximized, xfwm4 edge-tiling, fullscreen, shaded)
|
||||||
|
reset_state() {
|
||||||
|
wmctrl -ir "$1" -b remove,maximized_vert,maximized_horz
|
||||||
|
wmctrl -ir "$1" -b remove,fullscreen,shaded
|
||||||
|
}
|
||||||
|
|
||||||
|
# maximize ID -- clear fullscreen/shaded, then set the WM's maximized state
|
||||||
|
maximize() {
|
||||||
|
wmctrl -ir "$1" -b remove,fullscreen,shaded
|
||||||
|
wmctrl -ir "$1" -b add,maximized_vert,maximized_horz
|
||||||
|
wmctrl -ia "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# place ID X Y W H -- X Y W H is the OUTER rectangle including decorations
|
||||||
|
place() {
|
||||||
|
local id=$1 x=$2 y=$3 w=$4 h=$5 cw ch
|
||||||
|
frame_extents "$id"
|
||||||
|
cw=$(( w - FL - FR )); (( cw < 1 )) && cw=1
|
||||||
|
ch=$(( h - FT - FB )); (( ch < 1 )) && ch=1
|
||||||
|
# gravity 1 (NorthWest): x,y = top-left of the frame, w,h = client size
|
||||||
|
wmctrl -ir "$id" -e "1,$x,$y,$cw,$ch"
|
||||||
|
}
|
||||||
|
|
||||||
|
# verify ID X Y W H -- measure where the window really landed and nudge it if off
|
||||||
|
verify() {
|
||||||
|
local id=$1 x=$2 y=$3 w=$4 h=$5 try dx dy
|
||||||
|
for (( try = 0; try < VERIFY_TRIES; try++ )); do
|
||||||
|
frame_extents "$id"
|
||||||
|
client_position "$id"
|
||||||
|
dx=$(( CX - (x + FL) ))
|
||||||
|
dy=$(( CY - (y + FT) ))
|
||||||
|
(( dx == 0 && dy == 0 )) && return 0
|
||||||
|
place "$id" $(( x - dx )) $(( y - dy )) "$w" "$h"
|
||||||
|
sleep "$SETTLE"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- layout -----------------------------------------------------------------
|
||||||
|
# layout_master_stack N -> fills RECTS with "x y w h" outer rectangles, index 0 = master
|
||||||
|
# Integer remainders are handed out so the tiles cover the area exactly, no 1px gaps.
|
||||||
|
layout_master_stack() {
|
||||||
|
local n=$1 x0 y0 w0 h0 mw sw sx avail base rem i y hh
|
||||||
|
RECTS=()
|
||||||
|
x0=$(( WA_X + GAP )); y0=$(( WA_Y + GAP ))
|
||||||
|
w0=$(( WA_W - 2 * GAP )); h0=$(( WA_H - 2 * GAP ))
|
||||||
|
|
||||||
|
if (( n == 1 )); then
|
||||||
|
RECTS+=("$x0 $y0 $w0 $h0")
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
mw=$(( (w0 - GAP) * MASTER_RATIO / 100 ))
|
||||||
|
sw=$(( w0 - GAP - mw ))
|
||||||
|
sx=$(( x0 + mw + GAP ))
|
||||||
|
RECTS+=("$x0 $y0 $mw $h0")
|
||||||
|
|
||||||
|
(( n -= 1 ))
|
||||||
|
avail=$(( h0 - (n - 1) * GAP ))
|
||||||
|
base=$(( avail / n )); rem=$(( avail % n ))
|
||||||
|
y=$y0
|
||||||
|
for (( i = 0; i < n; i++ )); do
|
||||||
|
hh=$(( base + (i < rem ? 1 : 0) ))
|
||||||
|
RECTS+=("$sx $y $sw $hh")
|
||||||
|
(( y += hh + GAP ))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- tile -------------------------------------------------------------------
|
||||||
|
tile() {
|
||||||
|
local n idx master i
|
||||||
|
(( VERIFY )) && need xwininfo
|
||||||
|
collect_windows tile
|
||||||
|
n=${#WINS[@]}
|
||||||
|
(( n > 0 )) || return 0
|
||||||
|
|
||||||
|
# only one window: let xfwm4 maximize it (real maximized state, not fullscreen)
|
||||||
|
if (( n == 1 )); then
|
||||||
|
maximize "${WINS[0]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# active window becomes master, the rest keep their order in the stack
|
||||||
|
idx=$(index_of "$(active_window)")
|
||||||
|
if (( idx > 0 )); then
|
||||||
|
master=${WINS[idx]}
|
||||||
|
WINS=("$master" "${WINS[@]:0:idx}" "${WINS[@]:idx+1}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
workarea
|
||||||
|
layout_master_stack "$n"
|
||||||
|
|
||||||
|
for i in "${!WINS[@]}"; do reset_state "${WINS[i]}"; done
|
||||||
|
sleep "$SETTLE"
|
||||||
|
|
||||||
|
for i in "${!WINS[@]}"; do
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
place "${WINS[i]}" ${RECTS[i]}
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( VERIFY )); then
|
||||||
|
sleep "$SETTLE"
|
||||||
|
for i in "${!WINS[@]}"; do
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
verify "${WINS[i]}" ${RECTS[i]}
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
wmctrl -ia "${WINS[0]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- main -------------------------------------------------------------------
|
||||||
|
need wmctrl xdotool xprop
|
||||||
|
case ${1:-next} in
|
||||||
|
next|prev) focus_cycle "${1:-next}" ;;
|
||||||
|
up|down) focus_vertical "$1" ;;
|
||||||
|
tile) tile ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
Executable
+64
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
# Steam install recipe
|
||||||
|
# Target: Void Linux (x86_64 glibc only)
|
||||||
|
# Enables nonfree + multilib repos, installs Steam, 32-bit runtime libs, GPU drivers
|
||||||
|
# Usage: GPU=amd|nvidia|intel ./steam.sh (default: amd)
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GPU="${GPU:-amd}"
|
||||||
|
|
||||||
|
if [ "$(xbps-uhelper arch)" != "x86_64" ]; then
|
||||||
|
echo "Steam requires x86_64 glibc. Aborting." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Enabling nonfree and multilib repositories..."
|
||||||
|
sudo xbps-install -Sy void-repo-nonfree void-repo-multilib void-repo-multilib-nonfree
|
||||||
|
sudo xbps-install -Sy # sync the newly added repos
|
||||||
|
|
||||||
|
echo "Installing Steam and 32-bit runtime libraries..."
|
||||||
|
sudo xbps-install -y \
|
||||||
|
steam \
|
||||||
|
steam-udev-rules \
|
||||||
|
libgcc-32bit \
|
||||||
|
libstdc++-32bit \
|
||||||
|
libdrm-32bit \
|
||||||
|
libglvnd-32bit \
|
||||||
|
mesa-dri \
|
||||||
|
mesa-dri-32bit \
|
||||||
|
vulkan-loader \
|
||||||
|
vulkan-loader-32bit \
|
||||||
|
alsa-lib-32bit \
|
||||||
|
libpulseaudio-32bit
|
||||||
|
|
||||||
|
echo "Installing GPU drivers ($GPU)..."
|
||||||
|
case "$GPU" in
|
||||||
|
amd)
|
||||||
|
sudo xbps-install -y \
|
||||||
|
mesa-vulkan-radeon mesa-vulkan-radeon-32bit \
|
||||||
|
mesa-vaapi
|
||||||
|
;;
|
||||||
|
nvidia)
|
||||||
|
sudo xbps-install -y nvidia nvidia-libs nvidia-libs-32bit
|
||||||
|
;;
|
||||||
|
intel)
|
||||||
|
sudo xbps-install -y \
|
||||||
|
mesa-vulkan-intel mesa-vulkan-intel-32bit \
|
||||||
|
intel-video-accel
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown GPU '$GPU' (amd|nvidia|intel)" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Reloading udev rules..."
|
||||||
|
sudo udevadm control --reload
|
||||||
|
sudo udevadm trigger
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Steam installed. Log out/in (or reboot) before first launch."
|
||||||
|
echo ""
|
||||||
|
|
||||||
Executable
+67
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# square-xfwm4-corners.sh (v2)
|
||||||
|
# Makes ~/.themes/Default-Square: an exact copy of the xfwm4 "Default" theme
|
||||||
|
# with square top corners, keeping the thin dark outline and highlight.
|
||||||
|
# Usage: ./square-xfwm4-corners.sh [ACTIVE_TITLE_COLOR]
|
||||||
|
# e.g. ./square-xfwm4-corners.sh '#ff9900' (or a name like orange)
|
||||||
|
# no argument = keep the theme's normal title colour
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ACTIVE_TITLE_COLOR="${1:-}"
|
||||||
|
case "$ACTIVE_TITLE_COLOR" in
|
||||||
|
''|\#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]|\#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]) ;;
|
||||||
|
*[!a-zA-Z]*) echo "Colour must be #rgb, #rrggbb or a plain name like orange"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
SRC=/usr/share/themes/Default/xfwm4
|
||||||
|
DST_THEME="$HOME/.themes/Default-Square"
|
||||||
|
DST="$DST_THEME/xfwm4"
|
||||||
|
[ -d "$SRC" ] || { echo "Missing $SRC"; exit 1; }
|
||||||
|
|
||||||
|
# Warn if the installed theme differs from the version these overlays were made from
|
||||||
|
want=349096e386ab06feddff55aa404bed0a
|
||||||
|
have=$(md5sum "$SRC/top-left-active.png" 2>/dev/null | cut -d' ' -f1 || true)
|
||||||
|
[ "$have" = "$want" ] || echo "Warning: your Default theme differs from the expected version; result may be slightly off."
|
||||||
|
|
||||||
|
# Fresh copy (also cleans up the result of the first version of this script)
|
||||||
|
rm -rf "$DST_THEME"
|
||||||
|
mkdir -p "$DST_THEME"
|
||||||
|
cp -r "$SRC" "$DST"
|
||||||
|
|
||||||
|
# 1) Base layer (XPM): make the transparent corner pixels use the frame colour
|
||||||
|
for f in "$DST"/top-left-*.xpm "$DST"/top-right-*.xpm; do
|
||||||
|
awk '
|
||||||
|
/"[^"]*"/ && !hdr { hdr = 1; split(substr($0, index($0,"\"")+1), a, /[ \t"]+/); nc = a[3]; cpp = a[4]; print; next }
|
||||||
|
hdr && seen < nc && /"/ {
|
||||||
|
seen++; s = substr($0, index($0,"\"")+1); s = substr(s, 1, index(s,"\"")-1)
|
||||||
|
key[seen] = substr(s, 1, cpp); spec[seen] = substr(s, cpp+1); pre[seen] = substr($0, 1, index($0,"\"")-1)
|
||||||
|
isnone[seen] = (tolower(spec[seen]) ~ /c[ \t]+none/)
|
||||||
|
if (!isnone[seen] && fill == "") fill = spec[seen]
|
||||||
|
if (seen == nc) for (i = 1; i <= nc; i++) print pre[i] "\"" key[i] (isnone[i] ? fill : spec[i]) "\","
|
||||||
|
next }
|
||||||
|
{ print }' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 2) Overlay (PNG): square versions of the outline/highlight images
|
||||||
|
write_png() { printf '%s' "$2" | base64 -d > "$DST/$1"; }
|
||||||
|
write_png top-left-active.png 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAdCAYAAACXFC2jAAAASklEQVR42mNkYGBoYMADWLi5udm+fPnShlPB/////zMwMPzHqQBK41TAxEAAsPz79+8/ZSYQcgMdrBj1JpIbGBkZ/5FtwqgCCAAAJ9onK5/spQ0AAAAASUVORK5CYII='
|
||||||
|
write_png top-left-inactive.png 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAdCAYAAACXFC2jAAAASklEQVR42mNkYGBoYMADWLi5udm+fPnShlPB/////zMwMPzHqQBK41TAxEAAsPz79+8/ZSYQcgMdrBj1JpIbGBkZ/5FtwqgCCAAAJ9onK5/spQ0AAAAASUVORK5CYII='
|
||||||
|
write_png top-right-active.png 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAdCAYAAACXFC2jAAAAR0lEQVR42u2PMQ7AIAwDz6hjXszEy+MOZSUMlZi41dY5ETAokO1YhRHRH8Crgm2XBYDGhtKQmf5nODRx35wGSVnk+xtu4eMFmCwkTAAQh0MAAAAASUVORK5CYII='
|
||||||
|
write_png top-right-inactive.png 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAdCAYAAACXFC2jAAAAR0lEQVR42u2PMQ7AIAwDz6hjXszEy+MOZSUMlZi41dY5ETAokO1YhRHRH8Crgm2XBYDGhtKQmf5nODRx35wGSVnk+xtu4eMFmCwkTAAQh0MAAAAASUVORK5CYII='
|
||||||
|
|
||||||
|
# 3) Optional: colour of the focused window's title text
|
||||||
|
if [ -n "$ACTIVE_TITLE_COLOR" ]; then
|
||||||
|
rc="$DST/themerc"
|
||||||
|
if grep -q '^active_text_color=' "$rc"; then
|
||||||
|
sed -i "s|^active_text_color=.*|active_text_color=$ACTIVE_TITLE_COLOR|" "$rc"
|
||||||
|
else
|
||||||
|
echo "active_text_color=$ACTIVE_TITLE_COLOR" >> "$rc"
|
||||||
|
fi
|
||||||
|
echo "Active title colour: $ACTIVE_TITLE_COLOR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Created $DST_THEME"
|
||||||
|
xfconf-query -c xfwm4 -p /general/theme -s Default 2>/dev/null || true
|
||||||
|
xfconf-query -c xfwm4 -p /general/theme -s Default-Square 2>/dev/null \
|
||||||
|
&& echo "Applied theme 'Default-Square'." \
|
||||||
|
|| echo "Select 'Default-Square' in Settings > Window Manager > Style."
|
||||||
Reference in New Issue
Block a user