Doom Emacs: Key binding SPC-SPC for easy file navigation - emacs

For a couple of days, I've been trying to bind SPC SPC (now find-file or project-find-file) to a bottom popup that would display easy navigation to my files.
Possible solution - method 1 (modifying the below code snippet):
Here's the simple popup code (works perfectly and gets activated upon SPC e)
(map! :leader
(:prefix ("e" . "open config files")
:desc "alacritty.yml" "a" #'(lambda () (interactive) (find-file "~/.config/alacritty/alacritty.yml"))
:desc "nvim" "n" #'(lambda () (interactive) (find-file "~/.config/nvim/init.vim"))
:desc "polybar" "p" #'(lambda () (interactive) (find-file "~/.config/polybar/config")))
But I'd like to use SPC SPC instead of SPC e. When I change :prefix from e to SPC, I get this error:
Key sequence SPC starts with non-prefix key SPC.
How can I bind SPC SPC to a similar navigation (i.e. the above "open config files" menu activated with "SPC e"?
Possible solution - method 2 (creating custom function):
I suspect that what I want could also be done by the (custom) functioin. I managed to get SPC SPC to invoke my-own-nav-function (see the code below), but I could not make it work.
This is how I trigger the function (upon hitting "SPC SPC", the code triggers my-own-nav-function as expected):
(map! :leader
:desc "navigation function" "SPC" #'my-own-nav-function)
The function that I tried to create is this:
(defun my-own-nav-function ()
(interactive)
:desc "alacritty.yml" "a" #'(lambda () (interactive) (find-file "~/.config/alacritty/alacritty.yml"))
:desc "nvim" "n" #'(lambda () (interactive) (find-file "~/.config/nvim/init.vim"))
:desc "polybar" "p" #'(lambda () (interactive) (find-file "~/.config/polybar/config")))
I can navigate to this function via M-x and execute it, but it doesn't seem to be doing anything. If I could get that function work, it would solve my problem.
Note: I'm running Doom Emacs on Linux (GNU Emacs 27.2)

Related

How to remap keys in ido-find-file?

I have been trying to make a few changes to ido-mode to make it more useful. One of the things which I have been trying to do is to remap some of the keys which I use in ido-find-file. The main one is that I want to use C-d to call the ido-enter-dired function instead of having to press C-f+C-d which does the same thing.
This is my ido setup so far:
(defun ali/ido ()
"My configuration for ido-mode"
(require 'ido)
(setq ido-create-new-buffer 'always)
;; Making sure that ido works in M-x
(global-set-key
"\M-x"
(lambda ()
(interactive)
(call-interactively
(intern
(ido-completing-read
"M-x "
(all-completions "" obarray 'commandp))))))
;; Ido keybindings
(defun ido-keybindings ()
(define-key ido-completion-map (kbd "C-d") 'ido-enter-dired))
(add-hook 'ido-setup-hook 'ido-keybindings)
(ido-everywhere t)
(ido-mode 1))
However whenever, I try to use C-d in ido-find-file I always get this error:
Debugger entered--Lisp error: (error "Command attempted to use minibuffer while in minibuffer")
When called with the minibuffer active, your command uses a recursive minibuffer to read input using ido-completing-read.
Use this as your command instead:
(lambda ()
(interactive)
(let ((enable-recursive-minibuffers t)) ; <=====================
(call-interactively
(intern
(ido-completing-read
"M-x "
(all-completions "" obarray 'commandp))))))
C-h v enable-recursive-minibuffers tells us:
enable-recursive-minibuffers is a variable defined in C source code.
Its value is nil
Documentation:
Non-nil means to allow minibuffer commands while in the minibuffer.
This variable makes a difference whenever the minibuffer window is active.
Also see minibuffer-depth-indicate-mode, which may be handy if this
variable is non-nil.
You can customize this variable.

Rebuild cscope in emacs

I have cscope built-in in emacs.
When ever I change the code using emacs. The code change causes cscope to not behave the way I want it to.
eg.
Due to code change If I want to jump to the function definition. cscope does not take me to the definition of the func, instead it takes me to some other line.
Please tell if there is a way to rebuild cscope without closing the emacs window.
You will need https://github.com/dkogan/xcscope.el
and configuration :
(defun my-c-mode-common-hook ()
(require 'xcscope)
(cscope-setup)
(setq cscope-initial-directory "path to the cscope directory"))
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
and then
C-c s L (or M-x cscope-create-list-of-files-to-index)
C-c s I (or M-x cscope-index-files) => build or rebuild
Hope this help
I use the following function to build/rebuild cscope database:
(require 'xcscope)
(cscope-setup)
(setq cscope-option-use-inverted-index t)
(defadvice cscope-bury-buffer (after cscope-bury-buffer activate)
"Kill the *cscope* window after hitting q or Q instead of leaving it open."
(delete-window))
(defun cscope-create-database (top-directory)
"Create cscope* files in one step containing, do this before using cscope:
1. C-c s L
2. C-c s I
3. C-c s a
"
(interactive "DCreate cscope* database files in directory: ")
(progn
(cscope-create-list-of-files-to-index top-directory)
(cscope-index-files top-directory)
(setq cscope-initial-directory top-directory)
(sit-for 2)
(delete-windows-on "*cscope-indexing-buffer*")
(kill-buffer "*cscope-indexing-buffer*")
))
(bind-keys*
("C-c s r" . cscope-create-database))

Insert text string into ido minibuffer using non-interactive defun

Need to insert some text in the ido mini-buffer during ido-find-file using a defun bound to a key chord. This behavior is the same as if the following sequence was typed interactively, C-x C-f, followed by C-e to edit the mini-buffer, followed by deleting the current text then typing or yanking the text that I want to insert. To that end I have run this defun and just after ido-find-file:
(global-set-key [f10] 'mytest)
(defun mytest ()
(interactive)
(ido-edit-input) ;#1
(delete-minibuffer-contents) ;#2
(insert "C:/users/family/" )) ;#3
My expectation is that the mini-buffer would contain the given string (#3) after one invocation of mytest. However it seems as if I need to run mytest 2x to get the inserted string into the mini-buffer. After the first invocation the ido mini-buffer is in edit mode, however is as if only the #1 was run (the original text is still present). After the 2nd invocation of mytest the ido mini-buffer seems as if #1, #2 and #3 have been executed.
I am using a stand-alone mini-buffer which is part of the one-on-one library.
Running GNU emacs 24.4 on Windows.
Here is my custom configuration of ido, which I run at emacs startup.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;IDO Config
(setq ido-enable-flex-matching t)
;
(setq ido-everywhere t)
(ido-everywhere 1)
;
(require 'ido)
(ido-mode 1)
;
(setq ido-auto-merge-work-directories-length -1)
;
;https://github.com/gempesaw/ido-vertical-mode.el/blob/master/ido-vertical-mode.el
;; Display ido results vertically, rather than horizontally
(setq ido-decorations (quote ("\n-> " "" "\n " "\n ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))
(defun ido-disable-line-trucation ()
(set (make-local-variable 'truncate-lines) nil))
(add-hook 'ido-minibuffer-setup-hook 'ido-disable-line-trucation)
;
(setq ido-ignore-buffers '("\\` " "^\*Mess" "^\*Back" ".*Completion"
"^\*Ido" "^\*trace" "^\*compilation" "^\*GTAGS" "^\*Help" "^session\.*" "^\*"))
;
;use IDO for more things
(setq recentf-max-saved-items 100)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I have confirmed that the logic is somewhat sound by binding the individual commands then running them interactively. It seems as if running the same defs from lisp is acting differently than running the same interactively.
Ido-edit-input is C-e during ido-find-file
(global-set-key [f11] 'delete-minibuffer-contents)
(global-set-key [f12] (lambda () (interactive) (insert "C:/users/family")))
Also tried inserting (sit-for 1) in the mytest defun on the possibility that there is some timing issue.
How can the defun mytest be modified to insert a string (#3) with a single invocation?
This isn't the answer to the question in the title, but it does do what you apparently want:
(defun my-ido-find-file-in-dir ()
(interactive)
(let ((default-directory "C:/users/family"))
(call-interactively 'ido-find-file)))
(global-set-key [f10] 'my-ido-find-file-in-dir)

Emacs Org-mode: Quickly mark TODO as DONE

I'd like to have a shortcut to change the state of a TODO straight to DONE (and back) with the CLOSED time tag folded when I'm at any position on the line (not like speed-keys requiring to be before the first asterisk).
Currently I have 2 options:
C-c C-t d TAB (with org-use-fast-todo-selection set to t, d is my DONE state shortcut and TAB hides the subtree), or
S-right TAB (using org-shiftright, DONE is the first state after TODO).
Can you please help me bind this to a single shortcut like C-c C-d. Please note I have more states than TODO and DONE but this shortcut should just toggle between those too.
Bonus points: Additional command that also starts a new TODO item on the next line at the same level as the previous task.
Thank you very much!
Not sure what you mean by "time tag", but based on the workflows you listed, the following command should do what you want:
(defun org-toggle-todo-and-fold ()
(interactive)
(save-excursion
(org-back-to-heading t) ;; Make sure command works even if point is
;; below target heading
(cond ((looking-at "\*+ TODO")
(org-todo "DONE")
(hide-subtree))
((looking-at "\*+ DONE")
(org-todo "TODO")
(hide-subtree))
(t (message "Can only toggle between TODO and DONE.")))))
(define-key org-mode-map (kbd "C-c C-d") 'org-toggle-todo-and-fold)
As for inserting new TODO items on the same level as the current task, org-mode has built-in commands for this. You can read up on them by doing
C-h f org-insert-todo-heading RET
C-h f org-insert-todo-heading-respect-content RET
A simple toggle command could look like the following
(defun my-org-todo-toggle ()
(interactive)
(let ((state (org-get-todo-state))
post-command-hook)
(if (string= state "TODO")
(org-todo "DONE")
(org-todo "TODO"))
(run-hooks 'post-command-hook)
(org-flag-subtree t)))
(define-key org-mode-map (kbd "C-c C-d") 'my-org-todo-toggle)
The post-command-hook is a bit tricky, but is required since otherwise notes are added (and revealed) after the command, which makes the time log partially unfolded.
In order to start a new TODO item, you might have a look at the existing org-insert-todo-heading (bound to <M-S-return>)

Using 2 consecutive control key in Emacs [duplicate]

Let's say I bind the key to a certain function as follows:
(global-set-key (kbd "C-c =") 'function-foo)
Now, I want the key binding to work as:
After I press C-c = for the first time, if I want to repeat the function-foo, I don't need to press C-c again, but simply repeat pressing =. Then, after I call the function-foo for enough times, I can just press keys other than = (or explicitly press C-g) to quit.
How to do this?
This may be the thing you are looking for:
(defun function-foo ()
(interactive)
(do-your-thing)
(set-temporary-overlay-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "=") 'function-foo)
map)))
There's a smartrep.el package that does exactly what you need. The documentation is a bit scarce but you can get a grip of how it's supposed to be used by looking into numerous emacs configs found on github. For example (taken from here):
(require 'smartrep)
(smartrep-define-key
global-map "C-q" '(("n" . (scroll-other-window 1))
("p" . (scroll-other-window -1))
("N" . 'scroll-other-window)
("P" . (scroll-other-window '-))
("a" . (beginning-of-buffer-other-window 0))
("e" . (end-of-buffer-other-window 0))))
This is what I use. I like it because you don't have to specify the repeating key.
(require 'repeat)
(defun make-repeatable-command (cmd)
"Returns a new command that is a repeatable version of CMD.
The new command is named CMD-repeat. CMD should be a quoted
command.
This allows you to bind the command to a compound keystroke and
repeat it with just the final key. For example:
(global-set-key (kbd \"C-c a\") (make-repeatable-command 'foo))
will create a new command called foo-repeat. Typing C-c a will
just invoke foo. Typing C-c a a a will invoke foo three times,
and so on."
(fset (intern (concat (symbol-name cmd) "-repeat"))
`(lambda ,(help-function-arglist cmd) ;; arg list
,(format "A repeatable version of `%s'." (symbol-name cmd)) ;; doc string
,(interactive-form cmd) ;; interactive form
;; see also repeat-message-function
(setq last-repeatable-command ',cmd)
(repeat nil)))
(intern (concat (symbol-name cmd) "-repeat")))
You want your function-foo to use set-temporary-overlay-map.
In addition to what #juanleon suggested, which uses set-temporary-overlay-map, here is an alternative that I use quite a bit. It uses standard library repeat.el.
;; This function builds a repeatable version of its argument COMMAND.
(defun repeat-command (command)
"Repeat COMMAND."
(interactive)
(let ((repeat-previous-repeated-command command)
(last-repeatable-command 'repeat))
(repeat nil)))
Use that to define different repeatable commands. E.g.,
(defun backward-char-repeat ()
"Like `backward-char', but repeatable even on a prefix key."
(interactive)
(repeat-command 'backward-char))
Then bind such a command to a key with a repeatable suffix, e.g., C-c = (for C-c = = = =...)
See this SO post for more information.