nixos-dotfiles

nixos-dotfiles

https://git.tonybtw.com/nixos-dotfiles.git git://git.tonybtw.com/nixos-dotfiles.git

Initial commit.

Commit
0a009640093717ab0e6677229ca807920cbc0e54
Author
tonybanters <tonybanters@gmail.com>
Date
2026-01-26 08:22:10

Diff

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6ea7464
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+elpa/
+eln-cache/
+auto-save-list/
+tramp
+transient/
+recentf
+custom.el
+*.elc
+*~
+\#*\#
diff --git a/config.el b/config.el
new file mode 100644
index 0000000..9ba0ced
--- /dev/null
+++ b/config.el
@@ -0,0 +1,187 @@
+;;; config.el --- Configuration -*- lexical-binding: t -*-
+
+(when (file-directory-p "/run/current-system/sw/lib")
+  (add-to-list 'treesit-extra-load-path "/run/current-system/sw/lib"))
+
+(setq epg-pinentry-mode 'loopback)
+
+(add-hook 'org-mode-hook 'visual-line-mode)
+
+(defun rc/get-default-font ()
+  (cond
+   ((eq system-type 'windows-nt) "Consolas-13")
+   ((eq system-type 'gnu/linux) "Iosevka Nerd Font-24")))
+
+(add-to-list 'default-frame-alist `(font . ,(rc/get-default-font)))
+
+(tool-bar-mode 0)
+(menu-bar-mode 0)
+(scroll-bar-mode 0)
+(column-number-mode 1)
+(show-paren-mode 1)
+(global-display-line-numbers-mode 1)
+
+(setq-default c-basic-offset 4
+              c-default-style '((java-mode . "java")
+                                (awk-mode . "awk")
+                                (other . "bsd")))
+
+(add-hook 'c-mode-hook (lambda ()
+                         (interactive)
+                         (c-toggle-comment-style -1)))
+
+(add-hook 'rust-mode-hook
+          (lambda ()
+            (setq-local eglot-workspace-configuration
+                        '(:rust-analyzer
+                          (:cargo (:allFeatures t)
+                           :rustfmt (:extraArgs ["--edition" "2021"]))))
+            (add-hook 'before-save-hook 'eglot-format-buffer nil t)))
+
+(add-hook 'before-save-hook 'delete-trailing-whitespace)
+
+(require 'dired-x)
+(require 'dired-aux)
+(setq dired-omit-files
+      (concat dired-omit-files "\\|^\\..+$"))
+(setq-default dired-dwim-target t)
+(setq dired-listing-switches "-alh")
+
+(setq-default indent-tabs-mode nil)
+(setq-default tab-width 4)
+(setq make-backup-files nil)
+(setq auto-save-default nil)
+
+(defvar my/base-dir "/home/tony")
+
+(defun my/set-base-dir ()
+  "Set the root directory for searches."
+  (interactive)
+  (setq my/base-dir (read-directory-name "Set base directory: " my/base-dir))
+  (message "Search root set to: %s" my/base-dir))
+
+(defun my/consult-fd ()
+  "Find files from base dir."
+  (interactive)
+  (let ((default-directory my/base-dir))
+    (consult-fd)))
+
+(defun my/fzf-find-file ()
+  "Find files from base dir using fzf."
+  (interactive)
+  (let ((default-directory my/base-dir))
+    (fzf-find-file)))
+
+(defun my/affe-find ()
+  "Find files from base dir using affe (async fuzzy)."
+  (interactive)
+  (affe-find my/base-dir))
+
+(load (expand-file-name "telescope.el" user-emacs-directory))
+
+(defun my/telescope-find-files ()
+  "Find files from base dir using telescope."
+  (interactive)
+  (telescope-find-files my/base-dir))
+
+(defun my/consult-ripgrep ()
+  "Ripgrep from base dir."
+  (interactive)
+  (consult-ripgrep my/base-dir))
+
+(defun my/consult-ripgrep-symbol ()
+  "Ripgrep symbol at point from base dir."
+  (interactive)
+  (consult-ripgrep my/base-dir (thing-at-point 'symbol t)))
+
+(defun my/find-emacs-config ()
+  "Find files in emacs config dir."
+  (interactive)
+  (let ((default-directory "/home/tony/.emacs.d/"))
+    (consult-fd)))
+
+(defun my/switch-project ()
+  "Pick a project from ~/repos, set base-dir, open dired."
+  (interactive)
+  (let* ((repos-dir "~/repos/")
+         (dirs (seq-filter
+                (lambda (f) (file-directory-p (expand-file-name f repos-dir)))
+                (directory-files repos-dir nil "^[^.]")))
+         (chosen (completing-read "Project: " dirs nil t)))
+    (when chosen
+      (let ((project-dir (expand-file-name chosen repos-dir)))
+        (setq my/base-dir project-dir)
+        (dired project-dir)
+        (message "Base dir: %s" project-dir)))))
+
+(defun my/vterm-here ()
+  "Open vterm in current window."
+  (interactive)
+  (let ((default-directory (or (and buffer-file-name (file-name-directory buffer-file-name))
+                               default-directory))
+        (display-buffer-alist nil))  ; bypass all display rules
+    (pop-to-buffer-same-window (vterm "*vterm*"))))
+
+(setq display-buffer-alist
+      '(("\\*xref\\*\\|\\*compilation\\*\\|\\*grep\\*"
+         (display-buffer-reuse-window display-buffer-below-selected)
+         (window-height . 0.35))))
+
+(defun my/close-popup-window ()
+  "Close windows showing xref, compilation, grep, or help buffers."
+  (interactive)
+  (dolist (win (window-list))
+    (when (string-match-p "\\*xref\\*\\|\\*compilation\\*\\|\\*grep\\*\\|\\*Help\\*"
+                          (buffer-name (window-buffer win)))
+      (delete-window win))))
+
+(defun my/reformat-parenthesized-content ()
+  "Reformat comma-separated content inside parentheses to multiple lines."
+  (interactive)
+  (let* ((line (thing-at-point 'line t))
+         (inside (and (string-match "(\\([^)]+\\))" line)
+                      (match-string 1 line))))
+    (if (not inside)
+        (message "No content found inside parentheses")
+      (let* ((prefix (and (string-match "^\\(.*?\\)(" line)
+                          (match-string 1 line)))
+             (suffix (and (string-match ")\\(.*\\)$" line)
+                          (match-string 1 line)))
+             (parts (split-string inside "," t "[ \t]*"))
+             (new-lines (list (concat prefix "("))))
+        (dotimes (i (length parts))
+          (let ((part (nth i parts)))
+            (if (< i (1- (length parts)))
+                (push (concat "        " part ",") new-lines)
+              (push (concat "        " part) new-lines))))
+        (push (concat "    )" (string-trim-right suffix)) new-lines)
+        (setq new-lines (nreverse new-lines))
+        (beginning-of-line)
+        (kill-line 1)
+        (insert (mapconcat 'identity new-lines "\n") "\n")))))
+
+(add-hook 'prog-mode-hook
+          (lambda ()
+            (modify-syntax-entry ?- "w")
+            (modify-syntax-entry ?_ "w")))
+
+(require 'erc)
+(require 'erc-services)
+(erc-services-mode 1)
+
+(setq erc-nick "tonybtw"
+      erc-user-full-name "tony"
+      erc-prompt-for-nickserv-password nil
+      erc-nickserv-identify-mode 'autodetect
+      erc-use-auth-source-for-nickserv-password t)
+
+(setq erc-autojoin-channels-alist
+      '(("libera.chat" "#technicalrenaissance")))
+
+(defun my/erc-connect-libera ()
+  "Connect to Libera.Chat via ERC."
+  (interactive)
+  (erc-tls :server "irc.libera.chat"
+           :port 6697
+           :nick "tonybtw"
+           :user "tony"))
diff --git a/init.el b/init.el
new file mode 100644
index 0000000..928b114
--- /dev/null
+++ b/init.el
@@ -0,0 +1,40 @@
+;;; init.el --- Main entry point -*- lexical-binding: t -*-
+
+(setq byte-compile-warnings '(not obsolete))
+(setq warning-suppress-log-types '((comp) (bytecomp)))
+(setq native-comp-async-report-warnings-errors 'silent)
+
+(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
+(package-initialize)
+
+(add-to-list 'package-archives
+             '("melpa" . "https://melpa.org/packages/") t)
+
+(defvar rc/package-contents-refreshed nil)
+
+(defun rc/package-refresh-contents-once ()
+  (when (not rc/package-contents-refreshed)
+    (setq rc/package-contents-refreshed t)
+    (package-refresh-contents)))
+
+(defun rc/require-one-package (package)
+  (when (not (package-installed-p package))
+    (rc/package-refresh-contents-once)
+    (package-install package)))
+
+(defun rc/require (&rest packages)
+  (dolist (package packages)
+    (rc/require-one-package package)))
+
+(defun rc/require-theme (theme)
+  (let ((theme-package (intern (concat (symbol-name theme) "-theme"))))
+    (rc/require theme-package)
+    (load-theme theme t)))
+
+; Load config files
+(load (expand-file-name "packages.el" user-emacs-directory))
+(load (expand-file-name "config.el" user-emacs-directory))
+(load (expand-file-name "keybinds.el" user-emacs-directory))
+
+(when (file-exists-p custom-file)
+  (load-file custom-file))
diff --git a/keybinds.el b/keybinds.el
new file mode 100644
index 0000000..d4f8d69
--- /dev/null
+++ b/keybinds.el
@@ -0,0 +1,144 @@
+;;; keybinds.el --- All keybindings -*- lexical-binding: t -*-
+
+;; C-c to escape insert mode
+(define-key evil-insert-state-map (kbd "C-c") 'evil-normal-state)
+
+;;; Global keys
+(global-set-key (kbd "M-x") 'execute-extended-command)
+(global-set-key (kbd "C-x b") 'consult-buffer)
+(global-set-key (kbd "C-c m s") 'magit-status)
+(global-set-key (kbd "C-c m l") 'magit-log)
+
+;;; Multiple cursors
+(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
+(global-set-key (kbd "C->")         'mc/mark-next-like-this)
+(global-set-key (kbd "C-<")         'mc/mark-previous-like-this)
+(global-set-key (kbd "C-c C-<")     'mc/mark-all-like-this)
+(global-set-key (kbd "C-\"")        'mc/skip-to-next-like-this)
+(global-set-key (kbd "C-:")         'mc/skip-to-previous-like-this)
+
+;;; Move text
+(global-set-key (kbd "M-p") 'move-text-up)
+(global-set-key (kbd "M-n") 'move-text-down)
+
+;;; Dired evil bindings
+(with-eval-after-load 'dired
+  (evil-define-key 'normal dired-mode-map
+    "." 'dired-create-empty-file
+    "h" 'dired-up-directory
+    "l" 'dired-find-file
+    "n" 'evil-search-next
+    "N" 'evil-search-previous))
+
+;;; Org mode evil bindings
+(defun my/org-heading-has-checkbox-p ()
+  "Check if current heading has [ ] or [X] checkbox."
+  (save-excursion
+    (beginning-of-line)
+    (looking-at "^\\*+\\s-+\\[[ X-]\\]")))
+
+(defun my/org-update-parent-cookie ()
+  "Update parent heading's [/] or [n/m] cookie by counting child heading checkboxes."
+  (save-excursion
+    (when (org-up-heading-safe)
+      (let ((start (point))
+            (end (save-excursion (org-end-of-subtree t) (point)))
+            (level (org-current-level))
+            (checked 0)
+            (total 0))
+        ;; Count direct child headings with checkboxes
+        (save-excursion
+          (while (re-search-forward (format "^\\*\\{%d\\}\\s-+\\[\\([ X-]\\)\\]" (1+ level)) end t)
+            (setq total (1+ total))
+            (when (string= (match-string 1) "X")
+              (setq checked (1+ checked)))))
+        ;; Update the cookie in parent heading
+        (beginning-of-line)
+        (when (re-search-forward "\\[\\([0-9]*/[0-9]*\\|/\\)\\]" (line-end-position) t)
+          (replace-match (format "[%d/%d]" checked total) t t))))))
+
+(defun my/org-toggle-heading-checkbox ()
+  "Toggle [ ] <-> [X] in current heading and update parent cookie."
+  (save-excursion
+    (beginning-of-line)
+    (when (re-search-forward "\\[\\([ X-]\\)\\]" (line-end-position) t)
+      (replace-match (if (string= (match-string 1) " ") "[X]" "[ ]") t t)))
+  (my/org-update-parent-cookie))
+
+(defun my/org-dwim-at-point ()
+  "Do-what-I-mean at point: toggle checkbox, follow link, or cycle TODO."
+  (interactive)
+  (cond
+   ;; Heading with [ ] or [X]
+   ((my/org-heading-has-checkbox-p)
+    (my/org-toggle-heading-checkbox))
+   ;; List checkbox
+   ((org-at-item-checkbox-p)
+    (org-toggle-checkbox))
+   ;; Link
+   ((org-in-regexp org-link-any-re)
+    (org-open-at-point))
+   ;; Regular TODO heading
+   ((org-at-heading-p)
+    (org-todo))
+   (t (org-return))))
+
+(with-eval-after-load 'org
+  (evil-define-key 'normal org-mode-map
+    (kbd "RET") 'my/org-dwim-at-point
+    (kbd "<return>") 'my/org-dwim-at-point
+    "t" 'org-todo))
+
+;;; LSP keybindings
+(with-eval-after-load 'eglot
+  (evil-define-key 'normal eglot-mode-map
+    "K" 'eldoc-box-help-at-point
+    "gd" 'xref-find-definitions
+    "gr" 'xref-find-references))
+
+;;; Leader keybindings (SPC)
+(evil-leader/set-key
+  ;; files
+  "ff" 'my/telescope-find-files
+  "fF" 'my/fzf-find-file
+  "fg" 'my/consult-ripgrep
+  "fs" 'my/consult-ripgrep-symbol
+  "fo" 'consult-recent-file
+  "fl" 'consult-line
+  "fi" 'my/find-emacs-config
+  "fp" 'my/switch-project
+  ;; buffers
+  "bb" 'consult-buffer
+  "fb" 'consult-buffer
+  "bp" 'previous-buffer
+  "bn" 'next-buffer
+  "bd" 'kill-current-buffer
+  "bm" 'ibuffer
+  ;; custom
+  "cr" 'my/set-base-dir
+  "cd" (lambda () (interactive) (dired (file-name-directory (or buffer-file-name default-directory))))
+  "cl" 'my/close-popup-window
+  "cn" 'next-error
+  "cp" 'previous-error
+  "cc" 'compile
+  "cm" 'recompile
+  "cb" (lambda () (interactive) (compile "bear -- make"))
+  ;; magit
+  "ms" 'magit-status
+  "ml" 'magit-log
+  ;; ssh/servers
+  ; "st" 'my/connect-tonydev
+  ;; terminal
+  "to" 'my/vterm-here
+  ;; window
+  "wv" 'split-window-right
+  "ws" 'split-window-below
+  "wd" 'delete-window
+  "wh" 'evil-window-left
+  "wj" 'evil-window-down
+  "wk" 'evil-window-up
+  "wl" 'evil-window-right
+  ;; reformat
+  "qq" 'my/reformat-parenthesized-content
+  ;; ERC
+  "ec" 'my/erc-connect-libera)
diff --git a/packages.el b/packages.el
new file mode 100644
index 0000000..cc182c1
--- /dev/null
+++ b/packages.el
@@ -0,0 +1,221 @@
+;;; packages.el --- Package configuration -*- lexical-binding: t -*-
+
+;;; evil mode (vim bindings)
+(setq evil-want-keybinding nil)  ; required before loading evil-collection
+(setq evil-search-module 'evil-search)  ; required for cgn
+(setq evil-undo-system 'undo-redo)  ; use emacs 28+ native undo-redo
+(rc/require 'evil 'evil-leader 'evil-collection 'evil-commentary)
+(global-evil-leader-mode)
+(evil-leader/set-leader "<SPC>")
+(evil-mode 1)
+(evil-collection-init)
+(evil-commentary-mode 1)
+
+;;; Vertico + Consult + Orderless (telescope-like fuzzy finding)
+(rc/require 'vertico 'consult 'orderless 'marginalia 'vertico-posframe 'fzf 'affe)
+(vertico-mode 1)
+(vertico-posframe-mode 1)
+(marginalia-mode 1)
+(recentf-mode 1)
+
+(setq vertico-posframe-parameters
+      '((left-fringe . 8)
+        (right-fringe . 8)))
+(setq vertico-posframe-poshandler #'posframe-poshandler-frame-center)
+
+(setq completion-styles '(orderless basic)
+      completion-category-defaults nil
+      completion-category-overrides '((file (styles . (partial-completion)))))
+
+;; Flex matching (fzf-style: characters in sequence)
+(setq orderless-matching-styles '(orderless-literal orderless-flex))
+
+;; Affe (async fuzzy finder using orderless)
+(setq affe-find-command "fd --color=never -t f")
+
+(setq consult-fd-args '("fd" "--color=never" "--type" "f" "--hidden" "--follow" "--exclude" ".git"))
+
+;; Live preview as you navigate
+(setq consult-preview-key 'any)
+
+;;; magit
+(rc/require 'magit)
+(setq magit-auto-revert-mode nil)
+
+;;; multiple cursors
+(rc/require 'multiple-cursors)
+
+;;; Move Text
+(rc/require 'move-text)
+
+;;; Company (autocompletion)
+(rc/require 'company)
+(global-company-mode)
+
+;;; Language modes
+(rc/require 'nix-mode 'zig-mode 'rust-mode 'php-mode 'web-mode 'go-mode 'typescript-mode)
+
+
+;;; Tree-sitter text objects (vif, vaf, vic, vac, etc.)
+(rc/require 'tree-sitter 'tree-sitter-langs 'evil-textobj-tree-sitter)
+(global-tree-sitter-mode)
+(add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode)
+(define-key evil-outer-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.outer"))
+(define-key evil-inner-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.inner"))
+(define-key evil-outer-text-objects-map "c" (evil-textobj-tree-sitter-get-textobj "class.outer"))
+(define-key evil-inner-text-objects-map "c" (evil-textobj-tree-sitter-get-textobj "class.inner"))
+
+;;; CSS color preview
+(rc/require 'rainbow-mode)
+(add-hook 'css-mode-hook 'rainbow-mode)
+(add-hook 'php-mode-hook 'rainbow-mode)
+(add-hook 'html-mode-hook 'rainbow-mode)
+(add-hook 'js-mode-hook 'rainbow-mode)
+(add-hook 'web-mode-hook 'rainbow-mode)
+(add-hook 'scss-mode-hook 'rainbow-mode)
+(add-hook 'conf-mode-hook 'rainbow-mode)
+(add-hook 'toml-mode-hook 'rainbow-mode)
+(add-hook 'yaml-mode-hook 'rainbow-mode)
+(add-hook 'conf-toml-mode-hook 'rainbow-mode)
+
+;;; Treesitter context (sticky function header)
+(rc/require 'topsy)
+(add-hook 'prog-mode-hook 'topsy-mode)
+
+;;; Org mode
+(rc/require 'org-superstar 'org-fancy-priorities)
+
+(setq org-directory "~/org/")
+(setq org-agenda-files '("~/repos/agendas/private.org"))
+
+;; Pretty bullets
+(add-hook 'org-mode-hook #'org-superstar-mode)
+(setq org-superstar-headline-bullets-list '("◉" "●" "○" "◆" "●" "○" "◆"))
+
+;; Priority icons
+(add-hook 'org-mode-hook #'org-fancy-priorities-mode)
+(setq org-fancy-priorities-list '("⚑" "▲" "»"))
+
+;; Syntax highlighting in code blocks
+(setq org-src-fontify-natively t
+      org-src-tab-acts-natively t
+      org-hide-block-startup nil
+      org-src-preserve-indentation nil
+      org-edit-src-content-indentation 0)
+
+;; Hide emphasis markers (*bold*, /italic/, etc.)
+(setq org-hide-emphasis-markers t)
+
+;; Visual tweaks
+(setq org-ellipsis " ▾")           ; nicer fold indicator
+(setq org-startup-folded 'content) ; show headings on open
+(add-hook 'org-mode-hook #'org-indent-mode) ; clean indentation
+
+;; Make RET follow links and toggle checkboxes
+(setq org-return-follows-link t)
+
+;;; Org Present (presentation mode)
+(rc/require 'org-present 'visual-fill-column)
+
+(defun my/org-present-start ()
+  ;; Smaller, more readable font scaling
+  (setq-local face-remapping-alist
+              '((default (:height 1.3) default)
+                (header-line (:height 2.0) variable-pitch)
+                (org-document-title (:height 1.5) org-document-title)
+                (org-level-1 (:height 1.3) org-level-1)
+                (org-level-2 (:height 1.2) org-level-2)
+                (org-level-3 (:height 1.1) org-level-3)
+                (org-code (:height 1.0) org-code)
+                (org-block (:height 1.0) org-block)))
+  ;; Center content
+  (setq visual-fill-column-width 80)
+  (setq visual-fill-column-center-text t)
+  (visual-fill-column-mode 1)
+  ;; Word wrap
+  (visual-line-mode 1)
+  ;; Hide UI
+  (setq header-line-format " ")
+  (display-line-numbers-mode 0)
+  (org-display-inline-images))
+
+(defun my/org-present-end ()
+  (setq-local face-remapping-alist nil)
+  (setq header-line-format nil)
+  (visual-fill-column-mode 0)
+  (visual-line-mode 0)
+  (display-line-numbers-mode 1)
+  (org-remove-inline-images))
+
+(add-hook 'org-present-mode-hook #'my/org-present-start)
+(add-hook 'org-present-mode-quit-hook #'my/org-present-end)
+
+;;; LSP (eglot is built-in to Emacs 29+)
+(require 'eglot)
+(rc/require 'eldoc-box)
+
+;; Auto-start LSP for these modes
+(add-hook 'zig-mode-hook 'eglot-ensure)
+(add-hook 'nix-mode-hook 'eglot-ensure)
+(add-hook 'rust-mode-hook 'eglot-ensure)
+(add-hook 'c-mode-hook 'eglot-ensure)
+(add-hook 'php-mode-hook 'eglot-ensure)
+(add-hook 'go-mode-hook 'eglot-ensure)
+(add-hook 'typescript-mode-hook 'eglot-ensure)
+(add-hook 'tsx-ts-mode-hook 'eglot-ensure)
+
+;; LSP server configurations
+(with-eval-after-load 'eglot
+  ;; PHP
+  (add-to-list 'eglot-server-programs
+               '(php-mode . ("intelephense" "--stdio")))
+  (add-to-list 'eglot-server-programs
+               '(web-mode . ("intelephense" "--stdio")))
+  ;; TypeScript/TSX (typescript-language-server)
+  (add-to-list 'eglot-server-programs
+               '(typescript-mode . ("typescript-language-server" "--stdio")))
+  (add-to-list 'eglot-server-programs
+               '(tsx-ts-mode . ("typescript-language-server" "--stdio"))))
+
+;; File associations for TypeScript React
+(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
+(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode))
+
+;; Go format on save
+(add-hook 'go-mode-hook
+          (lambda ()
+            (add-hook 'before-save-hook 'eglot-format-buffer nil t)))
+
+(add-hook 'web-mode-hook 'eglot-ensure)
+
+
+;;; Direnv integration (loads devshell environment)
+(rc/require 'envrc)
+(envrc-global-mode)
+
+;;; vterm (terminal emulator)
+(rc/require 'vterm)
+(defun rc/find-shell ()
+  "Find a suitable shell, checking common locations."
+  (or (getenv "SHELL")
+      (seq-find #'file-executable-p
+                '("/bin/bash"                      ; FHS standard
+                  "/usr/bin/bash"                  ; Some distros
+                  "/run/current-system/sw/bin/bash" ; NixOS
+                  "/bin/sh"))                      ; Ultimate fallback
+      "/bin/sh"))
+(setq vterm-shell (rc/find-shell))
+(setq vterm-kill-buffer-on-exit t)
+
+;;; Theme
+;; (rc/require-theme 'gruber-darker)
+(rc/require 'doom-themes)
+(load-theme 'doom-palenight t)
+
+;;; Clean up modeline (hide minor modes)
+(setq eldoc-minor-mode-string nil)
+(setq company-lighter nil)
+(setq-default abbrev-mode nil)
+(with-eval-after-load 'flymake (setq flymake-mode-line-format nil))
+(with-eval-after-load 'envrc (setq envrc-lighter nil))
+(with-eval-after-load 'evil-commentary (setq evil-commentary-mode-lighter nil))
diff --git a/telescope.el b/telescope.el
new file mode 100644
index 0000000..a91ea57
--- /dev/null
+++ b/telescope.el
@@ -0,0 +1,320 @@
+;;; telescope.el --- Telescope-like fuzzy finder -*- lexical-binding: t -*-
+
+(require 'posframe)
+
+(defgroup telescope nil
+  "Telescope-like fuzzy finder."
+  :group 'convenience)
+
+(defcustom telescope-fd-command "fd -t f --color=never --hidden --exclude .git"
+  "Command to list files."
+  :type 'string
+  :group 'telescope)
+
+(defcustom telescope-results-width-pct 0.35
+  "Width of results window as percentage of frame."
+  :type 'float
+  :group 'telescope)
+
+(defcustom telescope-preview-width-pct 0.50
+  "Width of preview window as percentage of frame."
+  :type 'float
+  :group 'telescope)
+
+(defcustom telescope-height-pct 0.70
+  "Height of telescope as percentage of frame."
+  :type 'float
+  :group 'telescope)
+
+(defcustom telescope-gap 2
+  "Gap between results and preview panes in characters."
+  :type 'integer
+  :group 'telescope)
+
+(defcustom telescope-padding 2
+  "Internal padding within panes in characters."
+  :type 'integer
+  :group 'telescope)
+
+;; Internal state
+(defvar telescope--input "")
+(defvar telescope--files nil)
+(defvar telescope--filtered nil)
+(defvar telescope--selected 0)
+(defvar telescope--base-dir nil)
+(defvar telescope--results-buffer " *telescope-results*")
+(defvar telescope--preview-buffer " *telescope-preview*")
+
+(defun telescope--get-files (dir)
+  "Get all files in DIR using fd."
+  (let ((default-directory dir))
+    (split-string
+     (shell-command-to-string (concat telescope-fd-command " ."))
+     "\n" t)))
+
+(defun telescope--fzf-filter (files query)
+  "Filter FILES with QUERY using fzf --filter."
+  (if (or (null files) (string-empty-p query))
+      (seq-take files 100)
+    (with-temp-buffer
+      (insert (string-join files "\n"))
+      (call-process-region (point-min) (point-max) "fzf" t t nil "--filter" query)
+      (split-string (buffer-string) "\n" t))))
+
+(defun telescope--render-results ()
+  "Render the results buffer."
+  (with-current-buffer (get-buffer-create telescope--results-buffer)
+    (let* ((inhibit-read-only t)
+           (pad (make-string telescope-padding ?\s))
+           (max-results (- telescope--height 5))  ; leave room for prompt/footer/padding
+           (content-width (- telescope--results-width (* telescope-padding 2) 2))
+           (separator (make-string (min content-width 80) ?─)))
+      (erase-buffer)
+      ;; Top padding
+      (insert "\n")
+      ;; Prompt
+      (insert pad)
+      (insert (propertize "> " 'face '(:foreground "#87afff" :weight bold)))
+      (insert telescope--input)
+      (insert (propertize "█" 'face 'cursor))
+      (insert "\n")
+      (insert pad)
+      (insert (propertize separator 'face '(:foreground "#444444")))
+      (insert "\n")
+      ;; Results
+      (if (null telescope--filtered)
+          (progn
+            (insert pad)
+            (insert (propertize "  No matches\n" 'face '(:foreground "#666666" :slant italic))))
+        (let ((idx 0))
+          (dolist (file (seq-take telescope--filtered max-results))
+            (let* ((max-len (- content-width 4))
+                   (display (if (> (length file) max-len)
+                                (concat "..." (substring file (- 3 max-len)))
+                              file))
+                   (selected (= idx telescope--selected))
+                   (face (if selected
+                             '(:background "#3a3a3a" :weight bold)
+                           nil))
+                   (prefix (if selected "→ " "  ")))
+              (insert pad)
+              (insert (propertize (concat prefix display "\n") 'face face)))
+            (cl-incf idx))))
+      ;; Footer
+      (insert pad)
+      (insert (propertize separator 'face '(:foreground "#444444")))
+      (insert "\n")
+      (insert pad)
+      (insert (propertize (format "%d/%d"
+                                  (min (1+ telescope--selected) (length telescope--filtered))
+                                  (length telescope--filtered))
+                          'face '(:foreground "#666666"))))))
+
+(defun telescope--update-preview ()
+  "Update preview buffer with selected file content."
+  (with-current-buffer (get-buffer-create telescope--preview-buffer)
+    (let ((inhibit-read-only t)
+          (pad (make-string telescope-padding ?\s)))
+      (erase-buffer)
+      (if-let* ((selected (nth telescope--selected telescope--filtered))
+                (path (expand-file-name selected telescope--base-dir))
+                (_ (and (file-exists-p path)
+                        (file-regular-p path)
+                        (not (file-directory-p path)))))
+          (condition-case nil
+              (progn
+                ;; Top padding
+                (insert "\n")
+                ;; File name header
+                (insert pad)
+                (insert (propertize (file-name-nondirectory path) 'face '(:foreground "#87afff" :weight bold)))
+                (insert "\n")
+                (insert pad)
+                (insert (propertize (make-string (min 60 (- telescope--preview-width 4)) ?─) 'face '(:foreground "#444444")))
+                (insert "\n")
+                ;; Content with left padding
+                (let ((start (point)))
+                  (insert-file-contents path nil 0 10000)
+                  (goto-char start)
+                  ;; Add padding to each line
+                  (while (not (eobp))
+                    (insert pad)
+                    (forward-line 1)))
+                (goto-char (point-min))
+                ;; Apply syntax highlighting
+                (when-let ((mode (assoc-default path auto-mode-alist 'string-match)))
+                  (delay-mode-hooks (funcall mode))
+                  (font-lock-ensure)))
+            (error
+             (erase-buffer)
+             (insert "\n" pad)
+             (insert (propertize "Cannot preview file" 'face '(:foreground "#666666")))))
+        (insert "\n" pad)
+        (insert (propertize "No preview available" 'face '(:foreground "#666666")))))))
+
+(defvar telescope--results-x 0)
+(defvar telescope--results-y 0)
+(defvar telescope--preview-x 0)
+(defvar telescope--results-width 55)
+(defvar telescope--preview-width 75)
+(defvar telescope--height 25)
+
+(defun telescope--calc-dimensions ()
+  "Calculate frame dimensions based on percentages."
+  (let ((frame-cols (frame-width))
+        (frame-rows (frame-height)))
+    (setq telescope--results-width (max 30 (floor (* frame-cols telescope-results-width-pct))))
+    (setq telescope--preview-width (max 40 (floor (* frame-cols telescope-preview-width-pct))))
+    (setq telescope--height (max 15 (floor (* frame-rows telescope-height-pct))))))
+
+(defun telescope--calc-positions ()
+  "Calculate frame positions."
+  (telescope--calc-dimensions)
+  (let* ((char-width (frame-char-width))
+         (char-height (frame-char-height))
+         (border-px 4)
+         (gap-px (* telescope-gap char-width))
+         (total-pixel-width (+ (* telescope--results-width char-width)
+                               (* telescope--preview-width char-width)
+                               (* 2 border-px)
+                               gap-px))
+         (total-pixel-height (* telescope--height char-height))
+         (start-x (max 0 (/ (- (frame-pixel-width) total-pixel-width) 2)))
+         (start-y (max 0 (/ (- (frame-pixel-height) total-pixel-height) 2))))
+    (setq telescope--results-x start-x)
+    (setq telescope--results-y start-y)
+    (setq telescope--preview-x (+ start-x (* telescope--results-width char-width) border-px gap-px))))
+
+(defun telescope--results-poshandler (_info)
+  "Position handler for results frame."
+  (cons telescope--results-x telescope--results-y))
+
+(defun telescope--preview-poshandler (_info)
+  "Position handler for preview frame."
+  (cons telescope--preview-x telescope--results-y))
+
+(defun telescope--show-frames ()
+  "Display the telescope posframes."
+  (telescope--calc-positions)
+  ;; Results frame (left)
+  (posframe-show telescope--results-buffer
+                 :position (point-min)
+                 :poshandler #'telescope--results-poshandler
+                 :width telescope--results-width
+                 :height telescope--height
+                 :border-width 2
+                 :border-color "#5f5fff"
+                 :background-color "#1c1c1c"
+                 :foreground-color "#d0d0d0"
+                 :override-parameters '((cursor-type . nil)))
+  ;; Preview frame (right)
+  (posframe-show telescope--preview-buffer
+                 :position (point-min)
+                 :poshandler #'telescope--preview-poshandler
+                 :width telescope--preview-width
+                 :height telescope--height
+                 :border-width 2
+                 :border-color "#5f87af"
+                 :background-color "#1c1c1c"
+                 :foreground-color "#d0d0d0"
+                 :override-parameters '((cursor-type . nil))))
+
+(defun telescope--hide-frames ()
+  "Hide telescope posframes."
+  (posframe-hide telescope--results-buffer)
+  (posframe-hide telescope--preview-buffer))
+
+(defun telescope--refresh ()
+  "Refresh filtered results and display."
+  (setq telescope--filtered (telescope--fzf-filter telescope--files telescope--input))
+  (setq telescope--selected (min telescope--selected
+                                  (max 0 (1- (length telescope--filtered)))))
+  (telescope--render-results)
+  (telescope--update-preview)
+  (telescope--show-frames))
+
+(defun telescope--select-next ()
+  "Select next item."
+  (when telescope--filtered
+    (let ((max-visible (- telescope--height 5)))
+      (setq telescope--selected
+            (min (1+ telescope--selected)
+                 (1- (min (length telescope--filtered) max-visible)))))
+    (telescope--render-results)
+    (telescope--update-preview)
+    (telescope--show-frames)))
+
+(defun telescope--select-prev ()
+  "Select previous item."
+  (setq telescope--selected (max 0 (1- telescope--selected)))
+  (telescope--render-results)
+  (telescope--update-preview)
+  (telescope--show-frames))
+
+(defun telescope--backspace ()
+  "Delete last character from input."
+  (when (> (length telescope--input) 0)
+    (setq telescope--input (substring telescope--input 0 -1))
+    (telescope--refresh)))
+
+(defun telescope--insert-char (char)
+  "Insert CHAR into input."
+  (setq telescope--input (concat telescope--input (char-to-string char)))
+  (telescope--refresh))
+
+;;;###autoload
+(defun telescope-find-files (&optional dir)
+  "Find files in DIR using telescope interface."
+  (interactive)
+  (let ((dir (expand-file-name (or dir default-directory))))
+    (setq telescope--base-dir dir)
+    (setq telescope--input "")
+    (setq telescope--selected 0)
+    (setq telescope--files (telescope--get-files dir))
+    (setq telescope--filtered (seq-take telescope--files 100))
+    (telescope--render-results)
+    (telescope--update-preview)
+    (telescope--show-frames)
+    (let ((result nil))
+      (unwind-protect
+          (while (null result)
+            (let ((key (read-key (propertize " " 'face '(:height 0.1)))))
+              (cond
+               ;; Quit
+               ((memq key '(?\e ?\C-g ?\C-c))
+                (setq result 'cancel))
+               ;; Confirm selection
+               ((memq key '(?\r ?\C-m))
+                (if telescope--filtered
+                    (setq result (expand-file-name
+                                   (nth telescope--selected telescope--filtered)
+                                   telescope--base-dir))
+                  (setq result 'cancel)))
+               ;; Navigation
+               ((or (memq key '(?\C-n ?\C-j)) (equal key 'down))
+                (telescope--select-next))
+               ((or (memq key '(?\C-p ?\C-k)) (equal key 'up))
+                (telescope--select-prev))
+               ;; Scroll
+               ((memq key '(?\C-d))
+                (dotimes (_ 5) (telescope--select-next)))
+               ((memq key '(?\C-u))
+                (dotimes (_ 5) (telescope--select-prev)))
+               ;; Delete
+               ((memq key '(?\C-h ?\C-? 127 backspace))
+                (telescope--backspace))
+               ;; Clear input
+               ((memq key '(?\C-w))
+                (setq telescope--input "")
+                (telescope--refresh))
+               ;; Regular character input
+               ((and (characterp key) (>= key 32) (<= key 126))
+                (telescope--insert-char key)))))
+        ;; Cleanup
+        (telescope--hide-frames))
+      ;; Handle result
+      (unless (eq result 'cancel)
+        (find-file result)))))
+
+(provide 'telescope)
+;;; telescope.el ends here