Compare commits
4 commits
54a1298000
...
dd8f97d60d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd8f97d60d | ||
|
|
f96e613ca5 | ||
|
|
f779d171fb | ||
|
|
be949bbc1e |
263
init.org
263
init.org
|
|
@ -210,7 +210,8 @@ Add package repositories and rank them by priority
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq-default tab-width 4
|
(setq-default tab-width 4
|
||||||
fill-column 80
|
fill-column 80
|
||||||
indent-tabs-mode nil)
|
indent-tabs-mode nil
|
||||||
|
lexical-binding t)
|
||||||
(setq use-short-answers t)
|
(setq use-short-answers t)
|
||||||
(setq initial-major-mode 'org-mode)
|
(setq initial-major-mode 'org-mode)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -311,7 +312,11 @@ Helper function for switching themes.
|
||||||
** emacs-related
|
** emacs-related
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq help-window-select t
|
(setq help-window-select t
|
||||||
help-window-keep-selected t)
|
help-window-keep-selected t
|
||||||
|
scroll-conservatively 20
|
||||||
|
scroll-margin 3
|
||||||
|
scroll-preserve-screen-position t
|
||||||
|
mouse-wheel-progressive-speed nil)
|
||||||
#+end_src
|
#+end_src
|
||||||
** Fonts
|
** Fonts
|
||||||
Font size [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Face-Attributes.html][(height)]] in emacs works in $\frac{1}{10}$ths of points, so ~110~ is the same as ~11~ points.
|
Font size [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Face-Attributes.html][(height)]] in emacs works in $\frac{1}{10}$ths of points, so ~110~ is the same as ~11~ points.
|
||||||
|
|
@ -482,7 +487,14 @@ Honestly not very happy with this at the moment, but it's kind of hacked togethe
|
||||||
esup-depth 1))
|
esup-depth 1))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
** =xref=
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package xref
|
||||||
|
:straight (:type built-in)
|
||||||
|
)
|
||||||
|
#+end_src
|
||||||
** =general.el =
|
** =general.el =
|
||||||
|
|
||||||
TODO: figure out how to get which-key to correctly display the ‘m‘ label
|
TODO: figure out how to get which-key to correctly display the ‘m‘ label
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
|
@ -497,9 +509,10 @@ TODO: figure out how to get which-key to correctly display the ‘m‘ label
|
||||||
:straight t
|
:straight t
|
||||||
:init
|
:init
|
||||||
(define-prefix-command 'nemo/xref-command 'nemo/xref-map "xref")
|
(define-prefix-command 'nemo/xref-command 'nemo/xref-map "xref")
|
||||||
(define-prefix-command 'nemo/buffers-command 'nemo/buffers-map "Buffers..")
|
(define-prefix-command 'nemo/buffers-command 'nemo/buffers-map "Buffers")
|
||||||
(define-prefix-command 'nemo/windows-command 'nemo/windows-map "Windows..")
|
(define-prefix-command 'nemo/windows-command 'nemo/windows-map "Windows")
|
||||||
(define-prefix-command 'nemo/files-command 'nemo/files-map "Files..")
|
(define-prefix-command 'nemo/files-command 'nemo/files-map "Files")
|
||||||
|
(define-prefix-command 'nemo/custom-command 'nemo/custom-map "Custom")
|
||||||
:config
|
:config
|
||||||
(general-define-key
|
(general-define-key
|
||||||
:states '(emacs normal)
|
:states '(emacs normal)
|
||||||
|
|
@ -529,7 +542,8 @@ TODO: figure out how to get which-key to correctly display the ‘m‘ label
|
||||||
"g" '("xref" . nemo/xref-command)
|
"g" '("xref" . nemo/xref-command)
|
||||||
"b" '("Buffers" . nemo/buffers-command)
|
"b" '("Buffers" . nemo/buffers-command)
|
||||||
"w" '("Windows" . nemo/windows-command)
|
"w" '("Windows" . nemo/windows-command)
|
||||||
"f" '("Files" . nemo/files-command))
|
"f" '("Files" . nemo/files-command)
|
||||||
|
"c" '("Custom" . nemo/custom-command))
|
||||||
|
|
||||||
(general-def
|
(general-def
|
||||||
:keymaps 'nemo/xref-map
|
:keymaps 'nemo/xref-map
|
||||||
|
|
@ -545,7 +559,7 @@ TODO: figure out how to get which-key to correctly display the ‘m‘ label
|
||||||
"n" '("Switch to next buffer" . switch-to-next-buffer)
|
"n" '("Switch to next buffer" . switch-to-next-buffer)
|
||||||
"b" '("Consult buffer" . consult-buffer)
|
"b" '("Consult buffer" . consult-buffer)
|
||||||
"d" '("Kill current buffer" . kill-current-buffer)
|
"d" '("Kill current buffer" . kill-current-buffer)
|
||||||
"s" '("Scratch buffer" . scratch-buffer))
|
"s" '("Scratch buffer" . scratch))
|
||||||
|
|
||||||
(general-def
|
(general-def
|
||||||
:keymaps 'nemo/windows-map
|
:keymaps 'nemo/windows-map
|
||||||
|
|
@ -558,7 +572,12 @@ TODO: figure out how to get which-key to correctly display the ‘m‘ label
|
||||||
"i" '("Edit init.org" . nemo/edit-init-org)
|
"i" '("Edit init.org" . nemo/edit-init-org)
|
||||||
"s" '("Save" . save-buffer)
|
"s" '("Save" . save-buffer)
|
||||||
"r" '("Ripgrep" . consult-ripgrep)
|
"r" '("Ripgrep" . consult-ripgrep)
|
||||||
|
"y" '("Yank Current Filename" . nemo/buffer-file-name-to-clipboard)
|
||||||
"R" '("Ripgrep in dir" . nemo/consult-ripgrep-dir))
|
"R" '("Ripgrep in dir" . nemo/consult-ripgrep-dir))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:keymaps 'nemo/custom-map
|
||||||
|
"d" '("Whisper record" . whisper-run))
|
||||||
)
|
)
|
||||||
#+end_src
|
#+end_src
|
||||||
** =dired=
|
** =dired=
|
||||||
|
|
@ -645,6 +664,7 @@ Todo: figure out how best to use =image-dired=.
|
||||||
:keymaps 'nemo/dired-map
|
:keymaps 'nemo/dired-map
|
||||||
"p" '("Preview Files" . dired-preview-mode)
|
"p" '("Preview Files" . dired-preview-mode)
|
||||||
"+" '("Create File/Directory" . nemo/dired-create-file-or-directory)
|
"+" '("Create File/Directory" . nemo/dired-create-file-or-directory)
|
||||||
|
"f" '("Yank File Name" . dired-copy-filename-as-kill)
|
||||||
"#" '("Toggle Dotfiles" . dired-omit-mode))
|
"#" '("Toggle Dotfiles" . dired-omit-mode))
|
||||||
|
|
||||||
(setopt dired-compress-directory-default-suffix ".tar.zst"
|
(setopt dired-compress-directory-default-suffix ".tar.zst"
|
||||||
|
|
@ -907,7 +927,7 @@ Also use =undo-fu=, which evil can use.
|
||||||
"p" '(:keymap project-prefix-map :wk "Projectile")
|
"p" '(:keymap project-prefix-map :wk "Projectile")
|
||||||
)
|
)
|
||||||
:config
|
:config
|
||||||
(setq projectile-project-search-path '("~/code/"))
|
(setq projectile-project-search-path '("/var/code/"))
|
||||||
(projectile-mode))
|
(projectile-mode))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
@ -932,7 +952,36 @@ Also use =undo-fu=, which evil can use.
|
||||||
:straight t)
|
:straight t)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
* Stuff
|
* Stuff
|
||||||
|
|
||||||
|
** =scratch.el=
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package scratch
|
||||||
|
:straight t)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Dictation
|
||||||
|
I want to test out dictation using whisper.el, which uses OpenAI’s whisper model locally.
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package whisper
|
||||||
|
:straight (:type git :host github :repo "natrys/whisper.el")
|
||||||
|
:bind
|
||||||
|
(("<f9>" . whisper-run))
|
||||||
|
:config
|
||||||
|
(setopt whisper-model "small.en"
|
||||||
|
whisper-language "en"
|
||||||
|
;; whisper--mode-line-recording-indicator "⏺"
|
||||||
|
whisper-isntall-directory (concat user-emacs-directory "whisper")
|
||||||
|
whisper-translate nil
|
||||||
|
whisper-return-cursor 'end
|
||||||
|
whisper-use-threads (/ (num-processors) 2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
** Mini-buffer escape
|
** Mini-buffer escape
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(setq minibuffer-prompt-properties
|
(setq minibuffer-prompt-properties
|
||||||
|
|
@ -952,7 +1001,6 @@ Also use =undo-fu=, which evil can use.
|
||||||
|
|
||||||
(global-set-key (kbd "<escape>") 'nemo/abort-minibuffer-if-active)
|
(global-set-key (kbd "<escape>") 'nemo/abort-minibuffer-if-active)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
* Writing
|
* Writing
|
||||||
** Olivetti
|
** Olivetti
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
|
@ -961,7 +1009,7 @@ Also use =undo-fu=, which evil can use.
|
||||||
:defer t
|
:defer t
|
||||||
;; :bind (:map custom-bindings-map ("C-c o" . olivetti-mode))
|
;; :bind (:map custom-bindings-map ("C-c o" . olivetti-mode))
|
||||||
:hook (org-mode . olivetti-mode)
|
:hook (org-mode . olivetti-mode)
|
||||||
:hook (olivetti-mode-on . (lambda () (olivetti-set-width 88)))
|
:hook (olivetti-mode-on . (lambda () (olivetti-set-width 120)))
|
||||||
:config
|
:config
|
||||||
(setq olivetti-style t))
|
(setq olivetti-style t))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -984,7 +1032,7 @@ Use =ispell= with company mode for completion in text-modes
|
||||||
:straight t
|
:straight t
|
||||||
:defer t
|
:defer t
|
||||||
:config
|
:config
|
||||||
(setq ispell-dictionary "en_GB"))
|
(setq ispell-dictionary "/etc/profiles/per-user/user/share/hunspell/en_GB"))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** LaTeX
|
** LaTeX
|
||||||
|
|
@ -1033,6 +1081,15 @@ PDF tools for latex previewing:
|
||||||
)
|
)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
** Markdown
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package markdown-mode
|
||||||
|
:ensure t
|
||||||
|
:mode ("\\.md\\'" . markdown-mode)
|
||||||
|
:config
|
||||||
|
(setq markdown-command "multimarkdown"))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
** Org
|
** Org
|
||||||
Taken from [[https://sophiebos.io/posts/prettifying-emacs-org-mode/][ here]].
|
Taken from [[https://sophiebos.io/posts/prettifying-emacs-org-mode/][ here]].
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
|
@ -1095,7 +1152,7 @@ Inline images as well.
|
||||||
|
|
||||||
In case LaTeX previews are too small, use this to increase them.
|
In case LaTeX previews are too small, use this to increase them.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(plist-put org-format-latex-options :scale 1.35)
|
(plist-put org-format-latex-options :scale 0.5)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
=pretty-entities= allows for latex symbols to be embedded into org-mode.
|
=pretty-entities= allows for latex symbols to be embedded into org-mode.
|
||||||
|
|
@ -1638,7 +1695,6 @@ Use =inheritenv= and =envrc= to load ~.envrc~ direnv files:
|
||||||
** Copilot 😭
|
** Copilot 😭
|
||||||
|
|
||||||
*** Copilot.el
|
*** Copilot.el
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package copilot
|
(use-package copilot
|
||||||
:straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
|
:straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
|
||||||
|
|
@ -1697,6 +1753,45 @@ Use =inheritenv= and =envrc= to load ~.envrc~ direnv files:
|
||||||
)
|
)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
*** COMMENT =minuet.el=
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package minuet
|
||||||
|
:straight t
|
||||||
|
:hook ((prog-mode markdown-mode conf-toml-mode) . minuet-auto-suggestion-mode)
|
||||||
|
:bind (("TAB" . minuet-accept-suggestion)
|
||||||
|
("C-<tab>" . minuet-accept-suggestion)
|
||||||
|
("M-<tab>" . minuet-accept-suggestion-line))
|
||||||
|
:init
|
||||||
|
(define-prefix-command 'nemo/minuet-map)
|
||||||
|
(setenv "DEEPSEEK_API_KEY" (s-chop-suffix "\n" (shell-command-to-string "rbw get 'Deepseek Minuet'")))
|
||||||
|
:general-config
|
||||||
|
(leader-def
|
||||||
|
"c" '("Minuet" . nemo/minuet-map))
|
||||||
|
(general-def
|
||||||
|
:keymaps 'nemo/minuet-map
|
||||||
|
"c" '("Show Completion" . minuet-show-suggestion)
|
||||||
|
"C" '("Show Completions" . minuet-complete-with-minibuffer)
|
||||||
|
"m" '("Configure" . minuet-configure-provider)
|
||||||
|
:map minuet-active-mode-map
|
||||||
|
"M-p" 'minuet-previous-suggestion
|
||||||
|
"M-n" 'minuet-next-suggestion
|
||||||
|
"M-RET" 'minuet-accept-suggestion
|
||||||
|
"M-DEL" 'minuet-reject-suggestion
|
||||||
|
"M-S-RET" 'minuet-accept-suggestion-line)
|
||||||
|
|
||||||
|
:config
|
||||||
|
(setq minuet-provider 'openai-fim-compatible
|
||||||
|
minuet-auto-suggestion-throttle-delay 0.5
|
||||||
|
minuet-auto-suggestion-debounce-delay 0.1
|
||||||
|
minuet-n-completions 1)
|
||||||
|
|
||||||
|
(plist-put minuet-openai-fim-compatible-options :end-point "https://api.deepseek.com/beta/completions")
|
||||||
|
(plist-put minuet-openai-fim-compatible-options :api-key "DEEPSEEK_API_KEY")
|
||||||
|
(plist-put minuet-openai-fim-compatible-options :model "deepseek-v4-flash")
|
||||||
|
|
||||||
|
(minuet-set-optional-options minuet-openai-fim-compatible-options :max_tokens 56)
|
||||||
|
(minuet-set-optional-options minuet-openai-fim-compatible-options :top_p 0.9))
|
||||||
|
#+end_src
|
||||||
*** COMMENT Ollama
|
*** COMMENT Ollama
|
||||||
I feel so bad for this.. but its not awful..
|
I feel so bad for this.. but its not awful..
|
||||||
|
|
||||||
|
|
@ -1814,7 +1909,7 @@ I feel so bad for this.. but its not awful..
|
||||||
)
|
)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** COMMENT Yasnippet
|
** Yasnippet
|
||||||
Auto-completion requires yasnippet for some competions, such as function arguments and parens.
|
Auto-completion requires yasnippet for some competions, such as function arguments and parens.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package yasnippet
|
(use-package yasnippet
|
||||||
|
|
@ -1850,6 +1945,17 @@ build formatting on save functionality:
|
||||||
** Eglot
|
** Eglot
|
||||||
Use =eglot= as an alternative to =lsp-mode=:
|
Use =eglot= as an alternative to =lsp-mode=:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
(defun nemo/kotlin-lsp-socket (interactively)
|
||||||
|
"Start kotlin-lsp in socket mode."
|
||||||
|
(let ((port 9998)
|
||||||
|
(host "127.0.0.1"))
|
||||||
|
(unless (ignore-errors (delete-process (open-network-stream "test" nil host port)))
|
||||||
|
(message "Starting kotlin-lsp in socket mode on %s:%d" host port)
|
||||||
|
(start-process "kotlin-lsp" "*kotlin-lsp*"
|
||||||
|
"kotlin-lsp" "--socket" "127.0.0.1:9998")
|
||||||
|
(sleep-for 5))
|
||||||
|
(list host port)))
|
||||||
|
|
||||||
(use-package eglot
|
(use-package eglot
|
||||||
:straight t
|
:straight t
|
||||||
:hook ((rust-mode nix-mode prog-mode) . eglot-ensure)
|
:hook ((rust-mode nix-mode prog-mode) . eglot-ensure)
|
||||||
|
|
@ -1864,22 +1970,44 @@ Use =eglot= as an alternative to =lsp-mode=:
|
||||||
'eglot-server-programs
|
'eglot-server-programs
|
||||||
'(just-mode
|
'(just-mode
|
||||||
"just-lsp"))
|
"just-lsp"))
|
||||||
|
(add-to-list
|
||||||
|
'eglot-server-programs
|
||||||
|
'((kotlin-mode kotlin-ts-mode) .
|
||||||
|
nemo/kotlin-lsp-socket))
|
||||||
(setq-default eglot-workspace-configuration
|
(setq-default eglot-workspace-configuration
|
||||||
'(:rust-analyzer
|
'(:rust-analyzer
|
||||||
(:cargo (:buildScripts (:enable t)
|
(:cargo (:buildScripts (:enable t)
|
||||||
:allFeatures t
|
:allFeatures t
|
||||||
:features "all"
|
:features "all"
|
||||||
:extraEnv (:RUSTFLAGS "-Clinker=clang -Clink-arg=-fuse-ld=mold"))
|
:extraEnv (:RUSTFLAGS "-Clinker=clang -Clink-arg=-fuse-ld=mold"))
|
||||||
:check (:command "clippy")
|
:check (:command "clippy")
|
||||||
:completion (:autoimport (:enable t))
|
:completion
|
||||||
:inlayHints (
|
(:autoimport (:enable t)
|
||||||
;; :maxLength 20
|
:postfix (:enable t)
|
||||||
:bindingModeHints (:enable t)
|
:snippets
|
||||||
:closureReturnTypeHints (:enable t))
|
(:custom
|
||||||
:procMacro (:enable t)))
|
(:mem_replace
|
||||||
)
|
(:postfix "replace"
|
||||||
|
:body "mem::replace(&mut ${receiver}, ${0:new_value})"
|
||||||
|
:description "Replace the value and return the old value"
|
||||||
|
:requires "core::mem"
|
||||||
|
:scope "expr"))))
|
||||||
|
:inlayHints (
|
||||||
|
;; :maxLength 20
|
||||||
|
:bindingModeHints (:enable t)
|
||||||
|
:closureReturnTypeHints (:enable t))
|
||||||
|
:procMacro (:enable t))))
|
||||||
(setq eglot-code-action-indications '(margin mode-line)
|
(setq eglot-code-action-indications '(margin mode-line)
|
||||||
eglot-extend-to-xref t
|
eglot-extend-to-xref t
|
||||||
|
eglot-connect-timeout 60
|
||||||
|
eglot-request-timeout 60
|
||||||
|
eglot-extend-to-xref t
|
||||||
|
eglot-sync-connect 1
|
||||||
|
eglot-report-progress t
|
||||||
|
eglot-autoshutdown t
|
||||||
|
eglot-events-buffer-size 0
|
||||||
|
;; eglot-events-buffer-config '(:size 5000 :format short)
|
||||||
|
eglot-max-file-watches 5000
|
||||||
completion-category-overrides '((eglot (styles orderless))
|
completion-category-overrides '((eglot (styles orderless))
|
||||||
(eglot-capf (styles orderless)))
|
(eglot-capf (styles orderless)))
|
||||||
flymake-show-diagnostics-at-end-of-line 'fancy
|
flymake-show-diagnostics-at-end-of-line 'fancy
|
||||||
|
|
@ -1889,21 +2017,23 @@ Use =eglot= as an alternative to =lsp-mode=:
|
||||||
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
|
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
|
||||||
:general-config
|
:general-config
|
||||||
(general-def
|
(general-def
|
||||||
:keymaps 'nemo/eglot-map
|
:keymaps 'nemo/eglot-map
|
||||||
"r r" '("Rename" . eglot-rename)
|
"r r" '("Rename" . eglot-rename)
|
||||||
"a a" '("Code Action" . eglot-code-action-quickfix)
|
"a a" '("Code Action" . eglot-code-action-quickfix)
|
||||||
"a A" '("Code Action (all)" . eglot-code-actions)
|
"a A" '("Code Action (all)" . eglot-code-actions)
|
||||||
"g d" '("Go to Definition" . xref-find-definitions)
|
"g d" '("Go to Definition" . xref-find-definitions)
|
||||||
"g r" '("Go to References" . xref-find-references)
|
"g r" '("Go to References" . xref-find-references)
|
||||||
"g g" '("Go to Declaration" . eglot-find-declaration)
|
"g g" '("Go to Declaration" . eglot-find-declaration)
|
||||||
"g i" '("Go to Implementation" . eglot-find-implementation)
|
"g i" '("Go to Implementation" . eglot-find-implementation)
|
||||||
"g t" '("Go to Type Definition" . eglot-find-typeDefinition)
|
"g t" '("Go to Type Definition" . eglot-find-typeDefinition)
|
||||||
"h h" '("Help" . eldoc-box-help-at-point)
|
"h h" '("Help" . eldoc-box-help-at-point)
|
||||||
"w r" '("Restart Server" . eglot-reconnect)
|
"w r" '("Restart Server" . eglot-reconnect)
|
||||||
"w q" '("Shutdown Server" . eglot-shutdown)
|
"w q" '("Shutdown Server" . eglot-shutdown)
|
||||||
"= =" '("Format Buffer" . eglot-format-buffer)
|
"= =" '("Format Buffer" . eglot-format-buffer)
|
||||||
"= r" '("Format Region" . eglot-format-region)
|
"= r" '("Format Region" . eglot-format-region)
|
||||||
)
|
)
|
||||||
|
(general-def '(emacs normal) :keymaps 'eglot-mode-map
|
||||||
|
"C-<down-mouse-1>" 'xref-find-definitions-at-mouse)
|
||||||
(leader-major-def
|
(leader-major-def
|
||||||
:keymaps 'eglot-mode-map
|
:keymaps 'eglot-mode-map
|
||||||
"l" '("Eglot" . nemo/eglot-map)
|
"l" '("Eglot" . nemo/eglot-map)
|
||||||
|
|
@ -1920,11 +2050,11 @@ Use =eglot= as an alternative to =lsp-mode=:
|
||||||
|
|
||||||
(use-package consult-eglot
|
(use-package consult-eglot
|
||||||
:straight t
|
:straight t
|
||||||
:after (consult eglot)
|
:after eglot
|
||||||
:config
|
:config
|
||||||
(general-define-key
|
(general-def
|
||||||
:prefix-map 'nemo/eglot-command-map
|
:keymaps 'nemo/eglot-map
|
||||||
"c s" '("Symbols" . consult-eglot-symbols))
|
"c s" '("Symbols" . consult-eglot-symbols))
|
||||||
)
|
)
|
||||||
|
|
||||||
(use-package breadcrumb
|
(use-package breadcrumb
|
||||||
|
|
@ -2471,6 +2601,42 @@ delimiters < and >'s."
|
||||||
:defer t)
|
:defer t)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
** Kotlin
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defun nemo/eglot-uri-to-path-kotlin-advice (orig-fun uri &rest args)
|
||||||
|
(if (and (stringp uri) (string-prefix-p "jar:///" uri))
|
||||||
|
(apply orig-fun (replace-regexp-in-string "^jar:///" "jar:file:///" uri) args)
|
||||||
|
(apply orig-fun uri args)))
|
||||||
|
|
||||||
|
(defun nemo/eglot-path-to-uri-kotlin-advice (orig-fun path &rest args)
|
||||||
|
(if (and (stringp path) (string-prefix-p "jar:file:///" path))
|
||||||
|
(apply orig-fun (replace-regexp-in-string "^jar:file:///" "jar:///" path) args)
|
||||||
|
(apply orig-fun path args)))
|
||||||
|
|
||||||
|
(use-package kotlin-ts-mode
|
||||||
|
:straight t
|
||||||
|
:mode ("\\.kt\\'" . kotlin-ts-mode)
|
||||||
|
:config
|
||||||
|
(if (fboundp 'eglot-uri-to-path)
|
||||||
|
(progn
|
||||||
|
(advice-add 'eglot-uri-to-path :around #'nemo/eglot-uri-to-path-kotlin-advice)
|
||||||
|
(advice-add 'eglot-path-to-uri :around #'nemo/eglot-path-to-uri-kotlin-advice)
|
||||||
|
)
|
||||||
|
(progn
|
||||||
|
(advice-add 'eglot--uri-to-path :around #'nemo/eglot-uri-to-path-kotlin-advice)
|
||||||
|
(advice-add 'eglot--path-to-uri :around #'nemo/eglot-path-to-uri-kotlin-advice))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(use-package jarchive
|
||||||
|
:straight t
|
||||||
|
:config
|
||||||
|
(jarchive-mode))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
** Web
|
** Web
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package web-mode
|
(use-package web-mode
|
||||||
|
|
@ -2568,12 +2734,12 @@ Use =nix-mode= to edit nix files:
|
||||||
(add-to-list 'eglot-server-programs '(scheme-mode . ("guile-lsp-server"))))
|
(add-to-list 'eglot-server-programs '(scheme-mode . ("guile-lsp-server"))))
|
||||||
|
|
||||||
(use-package geiser
|
(use-package geiser
|
||||||
:deter t
|
:defer t
|
||||||
:custom
|
:custom
|
||||||
(geiser-active-implementations '(guile)))
|
(geiser-active-implementations '(guile)))
|
||||||
|
|
||||||
(use-package geiser-guile
|
(use-package geiser-guile
|
||||||
:deter t
|
:defer t
|
||||||
:after geiser
|
:after geiser
|
||||||
:custom
|
:custom
|
||||||
(geiser-guile-binary "guile"))
|
(geiser-guile-binary "guile"))
|
||||||
|
|
@ -2645,6 +2811,17 @@ Open the current file with a =sudo= tramp:
|
||||||
)
|
)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defun nemo/buffer-file-name-to-clipboard ()
|
||||||
|
"Copy the current buffer's file name to the user's clipboard"
|
||||||
|
(interactive)
|
||||||
|
(let* ((filename buffer-file-name))
|
||||||
|
(message filename)
|
||||||
|
(if filename
|
||||||
|
(kill-new (file-truename filename))))
|
||||||
|
)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
* Keybinds
|
* Keybinds
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(define-key custom-bindings-map (kbd "C-c l") 'org-store-link)
|
(define-key custom-bindings-map (kbd "C-c l") 'org-store-link)
|
||||||
|
|
|
||||||
25
local-lisp/dired-hide-dotfiles.el
Normal file
25
local-lisp/dired-hide-dotfiles.el
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
;;; dired-hide-dotfiles.el --- Hide dotfiles in dired buffers -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'dired)
|
||||||
|
|
||||||
|
(defgroup dired-hide-dotfiles nil
|
||||||
|
:group 'dired)
|
||||||
|
|
||||||
|
(define-minor-mode dired-hide-dotfiles-mode
|
||||||
|
:init-value nil
|
||||||
|
:group 'dired
|
||||||
|
(if dired-hide-dotfiles-mode
|
||||||
|
(progn
|
||||||
|
(add-hook 'dired-after-readin-hook #'dired-hide-dotfiles)
|
||||||
|
(dired-hide-dotfiles))
|
||||||
|
(remove-hook 'dired-after-readin-hook #'dired-hide-dotfiles)
|
||||||
|
(revert-buffer))
|
||||||
|
|
||||||
|
(defun dired-hide-dotfiles ()
|
||||||
|
"Hide dotfiles in dired buffer."
|
||||||
|
(let ((inhibit-message t))
|
||||||
|
(dired-mark-files-regexp "^\\.|^.*/\\.")
|
||||||
|
(dired-do-kill-lines nil "Hid %d dotfiles."))))
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'dired-hide-dotfiles)
|
||||||
221
local-lisp/nemo-whisper.el
Normal file
221
local-lisp/nemo-whisper.el
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
;;; -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
(require 'whisper)
|
||||||
|
|
||||||
|
;; Optional: install/load posframe if you want floating display.
|
||||||
|
;; `nemo-whisper-use-posframe' controls whether it is used.
|
||||||
|
(require 'posframe nil t)
|
||||||
|
|
||||||
|
(defgroup nemo-whisper nil
|
||||||
|
"Whisper recording utilities."
|
||||||
|
:group 'whisper)
|
||||||
|
|
||||||
|
(defcustom nemo-whisper-use-posframe t
|
||||||
|
"Display the Whisper buffer in a floating posframe when non-nil."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'nemo-whisper)
|
||||||
|
|
||||||
|
(defcustom nemo-whisper-hide-posframe-after-transcription t
|
||||||
|
"Hide the posframe after copying the transcription to the kill ring."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'nemo-whisper)
|
||||||
|
|
||||||
|
(defcustom nemo-whisper-posframe-width 80
|
||||||
|
"Width of the Whisper posframe."
|
||||||
|
:type 'integer
|
||||||
|
:group 'nemo-whisper)
|
||||||
|
|
||||||
|
(defcustom nemo-whisper-posframe-height 8
|
||||||
|
"Height of the Whisper posframe."
|
||||||
|
:type 'integer
|
||||||
|
:group 'nemo-whisper)
|
||||||
|
|
||||||
|
(defvar nemo-whisper--buffer nil
|
||||||
|
"Buffer currently used for Whisper recording.")
|
||||||
|
|
||||||
|
(defvar nemo-whisper--previous-buffer nil
|
||||||
|
"Buffer that was selected before Whisper capture started.")
|
||||||
|
|
||||||
|
(defvar nemo-whisper--recording-p nil
|
||||||
|
"Whether Whisper is currently recording.")
|
||||||
|
|
||||||
|
(defvar nemo-whisper--transcribing-p nil
|
||||||
|
"Whether Whisper is currently transcribing.")
|
||||||
|
|
||||||
|
(defvar nemo-whisper--posframe-active-p nil
|
||||||
|
"Whether the current capture buffer is displayed in a posframe.")
|
||||||
|
|
||||||
|
|
||||||
|
(defvar nemo-whisper--capture-map
|
||||||
|
(let ((map (make-sparse-keymap)))
|
||||||
|
;; Bind both forms because terminal and GUI Emacs can report Escape
|
||||||
|
;; differently.
|
||||||
|
(define-key map (kbd "ESC") #'nemo-whisper-escape)
|
||||||
|
(define-key map [escape] #'nemo-whisper-escape)
|
||||||
|
map)
|
||||||
|
"Keymap for a Whisper capture buffer.")
|
||||||
|
|
||||||
|
(define-minor-mode nemo-whisper-capture-mode
|
||||||
|
"Minor mode used by the Whisper capture buffer."
|
||||||
|
:init-value nil
|
||||||
|
:lighter " Whisper"
|
||||||
|
:keymap nemo-whisper--capture-map)
|
||||||
|
|
||||||
|
(defun nemo-whisper--display-buffer (buffer)
|
||||||
|
"Display BUFFER normally or in a posframe."
|
||||||
|
(if (and nemo-whisper-use-posframe
|
||||||
|
(fboundp 'posframe-show)
|
||||||
|
(display-graphic-p))
|
||||||
|
(progn
|
||||||
|
(setq nemo-whisper--posframe-active-p t)
|
||||||
|
|
||||||
|
(posframe-show
|
||||||
|
buffer
|
||||||
|
:position nil
|
||||||
|
:poshandler #'posframe-poshandler-frame-center
|
||||||
|
:width nemo-whisper-posframe-width
|
||||||
|
:height nemo-whisper-posframe-height
|
||||||
|
:border-width 2
|
||||||
|
:internal-border-width 8
|
||||||
|
:internal-border-color "gray50"
|
||||||
|
:accept-focus t)
|
||||||
|
|
||||||
|
;; Explicitly focus the child frame. Without this, keyboard input
|
||||||
|
;; may continue going to the previously selected Emacs frame.
|
||||||
|
(let ((window (get-buffer-window buffer t)))
|
||||||
|
(when (window-live-p window)
|
||||||
|
(select-frame-set-input-focus (window-frame window))
|
||||||
|
(select-window window))))
|
||||||
|
|
||||||
|
(setq nemo-whisper--posframe-active-p nil)
|
||||||
|
(pop-to-buffer buffer)))
|
||||||
|
|
||||||
|
(defun nemo-whisper--remove-recording-preview ()
|
||||||
|
"Remove the recording preview before Whisper inserts its result."
|
||||||
|
(let ((inhibit-read-only t))
|
||||||
|
(erase-buffer)
|
||||||
|
(goto-char (point-min))))
|
||||||
|
|
||||||
|
(defun nemo-whisper--stop-recording ()
|
||||||
|
"Stop recording and start Whisper transcription."
|
||||||
|
(when (and nemo-whisper--buffer
|
||||||
|
(buffer-live-p nemo-whisper--buffer)
|
||||||
|
nemo-whisper--recording-p)
|
||||||
|
(setq nemo-whisper--recording-p nil
|
||||||
|
nemo-whisper--transcribing-p t)
|
||||||
|
|
||||||
|
(with-current-buffer nemo-whisper--buffer
|
||||||
|
;; Remove “Recording...” so the transcription is the only text
|
||||||
|
;; inserted into the buffer.
|
||||||
|
(nemo-whisper--remove-recording-preview)
|
||||||
|
(whisper-run))
|
||||||
|
|
||||||
|
(message "Recording stopped; transcribing...")))
|
||||||
|
|
||||||
|
(defun nemo-whisper--copy-result-to-kill-ring ()
|
||||||
|
"Copy the completed transcription to the kill ring."
|
||||||
|
(let ((text (string-trim
|
||||||
|
(buffer-substring-no-properties
|
||||||
|
(point-min)
|
||||||
|
(point-max)))))
|
||||||
|
(unless (string-empty-p text)
|
||||||
|
(kill-new text)
|
||||||
|
(message "Whisper transcription copied to the kill ring"))
|
||||||
|
|
||||||
|
(setq nemo-whisper--transcribing-p nil)
|
||||||
|
|
||||||
|
;; Select the completed transcription. This makes a subsequent ESC
|
||||||
|
;; return to the previous buffer when the capture buffer remains visible.
|
||||||
|
(goto-char (point-min))
|
||||||
|
(push-mark (point-max) t t)
|
||||||
|
|
||||||
|
(when (and nemo-whisper--posframe-active-p
|
||||||
|
nemo-whisper-hide-posframe-after-transcription
|
||||||
|
(fboundp 'posframe-hide))
|
||||||
|
(posframe-hide (buffer-name)))))
|
||||||
|
|
||||||
|
(defun nemo-whisper--return-to-previous-buffer ()
|
||||||
|
"Return to the buffer active before Whisper capture started."
|
||||||
|
(when (and nemo-whisper--posframe-active-p
|
||||||
|
(fboundp 'posframe-hide)
|
||||||
|
nemo-whisper--buffer)
|
||||||
|
(posframe-hide (buffer-name nemo-whisper--buffer)))
|
||||||
|
|
||||||
|
(let ((previous-buffer nemo-whisper--previous-buffer))
|
||||||
|
(setq nemo-whisper--buffer nil
|
||||||
|
nemo-whisper--previous-buffer nil
|
||||||
|
nemo-whisper--recording-p nil
|
||||||
|
nemo-whisper--transcribing-p nil
|
||||||
|
nemo-whisper--posframe-active-p nil)
|
||||||
|
|
||||||
|
(when (buffer-live-p previous-buffer)
|
||||||
|
(pop-to-buffer previous-buffer))))
|
||||||
|
|
||||||
|
(defun nemo-whisper-escape ()
|
||||||
|
"Stop recording, or return to the previous buffer after transcription."
|
||||||
|
(interactive)
|
||||||
|
(cond
|
||||||
|
(nemo-whisper--recording-p
|
||||||
|
(nemo-whisper--stop-recording))
|
||||||
|
|
||||||
|
(nemo-whisper--transcribing-p
|
||||||
|
(message "Whisper is still transcribing; please wait"))
|
||||||
|
|
||||||
|
(t
|
||||||
|
(nemo-whisper--return-to-previous-buffer))))
|
||||||
|
|
||||||
|
(defun nemo-whisper-record-to-kill-ring ()
|
||||||
|
"Record speech and copy the transcription to the kill ring.
|
||||||
|
|
||||||
|
Invoke this command to create a capture buffer and start recording.
|
||||||
|
Press ESC to stop recording. After transcription completes, press ESC
|
||||||
|
again to return to the previously selected buffer."
|
||||||
|
(interactive)
|
||||||
|
(cond
|
||||||
|
;; If called while recording, treat the command as a stop command.
|
||||||
|
(nemo-whisper--recording-p
|
||||||
|
(nemo-whisper--stop-recording))
|
||||||
|
|
||||||
|
;; Do not interrupt an active transcription.
|
||||||
|
(nemo-whisper--transcribing-p
|
||||||
|
(message "Whisper is still transcribing; please wait"))
|
||||||
|
|
||||||
|
;; Start a new capture.
|
||||||
|
(t
|
||||||
|
(setq nemo-whisper--previous-buffer
|
||||||
|
(window-buffer (selected-window))
|
||||||
|
nemo-whisper--buffer
|
||||||
|
(generate-new-buffer "*Whisper capture*")
|
||||||
|
nemo-whisper--recording-p t
|
||||||
|
nemo-whisper--transcribing-p nil)
|
||||||
|
|
||||||
|
(with-current-buffer nemo-whisper--buffer
|
||||||
|
(text-mode)
|
||||||
|
(nemo-whisper-capture-mode 1)
|
||||||
|
|
||||||
|
;; Insert the temporary preview text.
|
||||||
|
(insert (propertize "Recording...\n"
|
||||||
|
'face 'font-lock-warning-face))
|
||||||
|
|
||||||
|
;; Ask Whisper to insert its result into this buffer.
|
||||||
|
(setq-local whisper-insert-text-at-point t)
|
||||||
|
|
||||||
|
;; Prevent Whisper from opening another transcription buffer.
|
||||||
|
(setq-local whisper-display-transcription-buffer nil)
|
||||||
|
|
||||||
|
;; This hook is buffer-local, so it will not run in Whisper's
|
||||||
|
;; separate transcription buffer.
|
||||||
|
(add-hook 'whisper-after-insert-hook
|
||||||
|
#'nemo-whisper--copy-result-to-kill-ring
|
||||||
|
nil
|
||||||
|
t))
|
||||||
|
|
||||||
|
(nemo-whisper--display-buffer nemo-whisper--buffer)
|
||||||
|
|
||||||
|
;; The first invocation starts recording.
|
||||||
|
(with-current-buffer nemo-whisper--buffer
|
||||||
|
(whisper-run))
|
||||||
|
|
||||||
|
(message "Recording started; press ESC when finished speaking"))))
|
||||||
|
|
||||||
|
(provide 'nemo-whisper)
|
||||||
272
local-lisp/whisper-posframe.el
Normal file
272
local-lisp/whisper-posframe.el
Normal file
|
|
@ -0,0 +1,272 @@
|
||||||
|
;;; whisper-posframe.el --- Record speech into a posframe -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'whisper)
|
||||||
|
(require 'posframe)
|
||||||
|
|
||||||
|
(defgroup whisper-posframe nil
|
||||||
|
"Record speech into a temporary posframe buffer."
|
||||||
|
:group 'whisper)
|
||||||
|
|
||||||
|
(defcustom whisper-posframe-buffer-name "*whisper-capture*"
|
||||||
|
"Name of the temporary Whisper capture buffer."
|
||||||
|
:type 'string
|
||||||
|
:group 'whisper-posframe)
|
||||||
|
|
||||||
|
(defcustom whisper-posframe-width 80
|
||||||
|
"Width of the Whisper posframe in columns."
|
||||||
|
:type 'integer
|
||||||
|
:group 'whisper-posframe)
|
||||||
|
|
||||||
|
(defcustom whisper-posframe-height 12
|
||||||
|
"Height of the Whisper posframe in lines."
|
||||||
|
:type 'integer
|
||||||
|
:group 'whisper-posframe)
|
||||||
|
|
||||||
|
(defvar whisper-posframe--parent-frame nil)
|
||||||
|
|
||||||
|
(defvar whisper-posframe-mode-map
|
||||||
|
(let ((map (make-sparse-keymap)))
|
||||||
|
;; Finish recording and begin transcription.
|
||||||
|
(define-key map (kbd "C-c C-c") #'whisper-posframe-finish)
|
||||||
|
|
||||||
|
;; Cancel recording/transcription without copying anything.
|
||||||
|
(define-key map (kbd "C-c C-k") #'whisper-posframe-cancel)
|
||||||
|
|
||||||
|
;; Make C-g and Escape dismiss the capture.
|
||||||
|
(define-key map (kbd "C-g") #'whisper-posframe-cancel)
|
||||||
|
(define-key map (kbd "<escape>") #'whisper-posframe-cancel)
|
||||||
|
|
||||||
|
map)
|
||||||
|
"Keymap for `whisper-posframe-mode'.")
|
||||||
|
|
||||||
|
(defvar-local whisper-posframe--status-timer nil)
|
||||||
|
|
||||||
|
(defun whisper-posframe--recording-p ()
|
||||||
|
"Return non-nil when Whisper is recording."
|
||||||
|
(process-live-p whisper--recording-process))
|
||||||
|
|
||||||
|
(defun whisper-posframe--transcribing-p ()
|
||||||
|
"Return non-nil when Whisper is transcribing."
|
||||||
|
(process-live-p whisper--transcribing-process))
|
||||||
|
|
||||||
|
(defvar whisper-posframe--capture-buffer nil)
|
||||||
|
|
||||||
|
(defun whisper-posframe--set-status (status)
|
||||||
|
"Display STATUS at the beginning of the capture buffer."
|
||||||
|
(when (derived-mode-p 'whisper-posframe-mode)
|
||||||
|
(let ((inhibit-read-only t))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
|
||||||
|
;; Remove the previous status line.
|
||||||
|
(when (looking-at "^\\[Whisper:.*\\]\n")
|
||||||
|
(delete-region (point)
|
||||||
|
(line-beginning-position 2)))
|
||||||
|
|
||||||
|
;; Insert the new status line as actual displayed buffer text.
|
||||||
|
(insert
|
||||||
|
(propertize
|
||||||
|
(format "[Whisper: %s]\n" status)
|
||||||
|
'face 'font-lock-keyword-face
|
||||||
|
'read-only t
|
||||||
|
'rear-nonsticky '(read-only face)))))))
|
||||||
|
|
||||||
|
(defun whisper-posframe--update-status ()
|
||||||
|
"Update the status line according to Whisper's current process."
|
||||||
|
(when (buffer-live-p (current-buffer))
|
||||||
|
(cond
|
||||||
|
((whisper-posframe--recording-p)
|
||||||
|
(whisper-posframe--set-status
|
||||||
|
"recording — C-c C-c to finish, C-g or Esc to cancel"))
|
||||||
|
|
||||||
|
((whisper-posframe--transcribing-p)
|
||||||
|
(whisper-posframe--set-status
|
||||||
|
"transcribing…"))
|
||||||
|
|
||||||
|
(t
|
||||||
|
;; This can occur briefly while whisper.el is compiling, checking
|
||||||
|
;; its model, or transitioning between recording and transcription.
|
||||||
|
(whisper-posframe--set-status
|
||||||
|
"preparing Whisper…")))))
|
||||||
|
|
||||||
|
(defun whisper-posframe--stop-status-timer ()
|
||||||
|
"Stop the status update timer."
|
||||||
|
(when (timerp whisper-posframe--status-timer)
|
||||||
|
(cancel-timer whisper-posframe--status-timer)
|
||||||
|
(setq whisper-posframe--status-timer nil)))
|
||||||
|
|
||||||
|
(defun whisper-posframe--copy-and-close ()
|
||||||
|
"Copy only the transcription and close the capture posframe."
|
||||||
|
(let ((buffer whisper-posframe--capture-buffer))
|
||||||
|
(when (buffer-live-p buffer)
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(whisper-posframe--stop-status-timer)
|
||||||
|
|
||||||
|
(let ((inhibit-read-only t)
|
||||||
|
text)
|
||||||
|
;; Remove the status line from the actual capture buffer.
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(when (looking-at "^\\[Whisper:.*\\]\n")
|
||||||
|
(delete-region (point)
|
||||||
|
(line-beginning-position 2))))
|
||||||
|
|
||||||
|
;; Extract only the remaining transcription.
|
||||||
|
(setq text
|
||||||
|
(string-trim
|
||||||
|
(buffer-substring-no-properties
|
||||||
|
(point-min)
|
||||||
|
(point-max))))
|
||||||
|
|
||||||
|
(when (> (length text) 0)
|
||||||
|
(kill-new text)
|
||||||
|
(message "Whisper transcription copied to the kill ring")))))
|
||||||
|
|
||||||
|
;; Clear Whisper's asynchronous insertion target.
|
||||||
|
(set-marker whisper--marker nil)
|
||||||
|
(setq whisper--point-buffer nil)
|
||||||
|
|
||||||
|
;; Delete the posframe and the known capture buffer.
|
||||||
|
(ignore-errors
|
||||||
|
(posframe-delete-frame whisper-posframe-buffer-name))
|
||||||
|
|
||||||
|
(when (buffer-live-p buffer)
|
||||||
|
(kill-buffer buffer))
|
||||||
|
|
||||||
|
(setq whisper-posframe--capture-buffer nil)))
|
||||||
|
|
||||||
|
|
||||||
|
(define-derived-mode whisper-posframe-mode text-mode "Whisper"
|
||||||
|
"Major mode for a temporary Whisper capture buffer."
|
||||||
|
(use-local-map whisper-posframe-mode-map)
|
||||||
|
|
||||||
|
(setq-local whisper-insert-text-at-point t)
|
||||||
|
(setq-local whisper-display-transcription-buffer nil)
|
||||||
|
|
||||||
|
(whisper-posframe--set-status "preparing Whisper…")
|
||||||
|
|
||||||
|
;; This hook runs after whisper.el has inserted the final transcription.
|
||||||
|
(add-hook 'whisper-after-insert-hook
|
||||||
|
#'whisper-posframe--copy-and-close
|
||||||
|
nil
|
||||||
|
t))
|
||||||
|
|
||||||
|
(defun whisper-posframe--delete ()
|
||||||
|
"Delete the Whisper posframe, if it exists."
|
||||||
|
(when (buffer-live-p (get-buffer whisper-posframe-buffer-name))
|
||||||
|
(ignore-errors
|
||||||
|
(posframe-delete-frame whisper-posframe-buffer-name))))
|
||||||
|
|
||||||
|
(defun whisper-posframe-finish ()
|
||||||
|
"Stop recording and begin Whisper transcription."
|
||||||
|
(interactive)
|
||||||
|
(cond
|
||||||
|
((whisper-posframe--recording-p)
|
||||||
|
(whisper-posframe--set-status "transcribing…")
|
||||||
|
;; whisper-run toggles recording off and starts transcription.
|
||||||
|
(whisper-run))
|
||||||
|
|
||||||
|
((whisper-posframe--transcribing-p)
|
||||||
|
(message "Whisper is already transcribing"))
|
||||||
|
|
||||||
|
(t
|
||||||
|
(message "Whisper is not currently recording"))))
|
||||||
|
|
||||||
|
(defun whisper-posframe-cancel ()
|
||||||
|
"Cancel the active Whisper operation and close the posframe."
|
||||||
|
(interactive)
|
||||||
|
(when (or (whisper-recording-p)
|
||||||
|
(whisper-transcribing-p))
|
||||||
|
;; `whisper-run' interrupts recording or cancels transcription,
|
||||||
|
;; depending on Whisper's current state.
|
||||||
|
(whisper-run))
|
||||||
|
|
||||||
|
(whisper-posframe--stop-status-timer)
|
||||||
|
(set-marker whisper--marker nil)
|
||||||
|
(setq whisper--point-buffer nil)
|
||||||
|
|
||||||
|
(whisper-posframe--delete)
|
||||||
|
|
||||||
|
(let ((buffer (current-buffer)))
|
||||||
|
(when (buffer-live-p buffer)
|
||||||
|
(kill-buffer buffer)))
|
||||||
|
|
||||||
|
(message "Whisper recording canceled"))
|
||||||
|
|
||||||
|
|
||||||
|
(defun whisper-posframe--focus (buffer frame)
|
||||||
|
"Focus FRAME and select its window displaying BUFFER."
|
||||||
|
(when (frame-live-p frame)
|
||||||
|
(select-frame-set-input-focus frame)
|
||||||
|
(when-let ((window (get-buffer-window buffer frame)))
|
||||||
|
(select-window window))
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(goto-char (point-max)))))
|
||||||
|
|
||||||
|
(defun whisper-posframe--start-whisper (buffer)
|
||||||
|
"Start Whisper with BUFFER as its explicit insertion target."
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(setq-local whisper-insert-text-at-point t)
|
||||||
|
|
||||||
|
;; These are the variables whisper.el uses asynchronously when
|
||||||
|
;; inserting the completed transcription.
|
||||||
|
(setq whisper--point-buffer buffer)
|
||||||
|
(set-marker whisper--marker (point) buffer)
|
||||||
|
|
||||||
|
(whisper-run)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun whisper-posframe-record ()
|
||||||
|
"Open a posframe and start recording with Whisper."
|
||||||
|
(interactive)
|
||||||
|
(require 'whisper)
|
||||||
|
(require 'posframe)
|
||||||
|
|
||||||
|
(when (or (whisper-recording-p)
|
||||||
|
(whisper-transcribing-p))
|
||||||
|
(user-error "Whisper is already busy"))
|
||||||
|
|
||||||
|
(let ((buffer (get-buffer-create whisper-posframe-buffer-name)))
|
||||||
|
(setq whisper-posframe--capture-buffer buffer)
|
||||||
|
(setq whisper-posframe--parent-frame (selected-frame))
|
||||||
|
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(erase-buffer)
|
||||||
|
(whisper-posframe-mode)
|
||||||
|
|
||||||
|
;; Refresh the visible status every 200 ms.
|
||||||
|
(setq-local whisper-posframe--status-timer
|
||||||
|
(run-at-time
|
||||||
|
0
|
||||||
|
0.2
|
||||||
|
(lambda (buffer)
|
||||||
|
(when (buffer-live-p buffer)
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(whisper-posframe--update-status))))
|
||||||
|
buffer)))
|
||||||
|
|
||||||
|
;; `:accept-focus t' ensures that C-g, Escape, and the other local
|
||||||
|
;; keybindings are received by the posframe.
|
||||||
|
(let ((posframe
|
||||||
|
(posframe-show
|
||||||
|
buffer
|
||||||
|
:parent-frame (selected-frame)
|
||||||
|
:position (point)
|
||||||
|
:poshandler #'posframe-poshandler-frame-center
|
||||||
|
:width whisper-posframe-width
|
||||||
|
:height whisper-posframe-height
|
||||||
|
:internal-border-color "gray50"
|
||||||
|
:border-width 2
|
||||||
|
:accept-focus t)))
|
||||||
|
|
||||||
|
;; Focus after posframe-show has created and displayed the child frame.
|
||||||
|
(run-at-time
|
||||||
|
0 nil
|
||||||
|
(lambda ()
|
||||||
|
(whisper-posframe--focus buffer posframe))))
|
||||||
|
|
||||||
|
;; Start recording. `whisper-run' records into the current buffer.
|
||||||
|
(whisper-posframe--start-whisper buffer)))
|
||||||
|
|
||||||
|
(provide 'whisper-posframe)
|
||||||
|
;;; whisper-posframe.el ends here
|
||||||
Loading…
Reference in a new issue