an Emacs cursor movement hook, like the JavaScript mousemove event - emacs

I want to track the "current word" in the current buffer. which another (networked) application will be aware of.
I could do this by sending a request every time the cursor moves, whether from clicking or scrolling or arrowing or etc. i.e. any time the cursor's position in the buffer changes.
e.g.
(add-hook 'cursor-move-hook 'post-request-with-current-word)

Use a post-command-hook this will run after every command, including movement commands.
Obviously this will fire more often than you want, so in your hook, you could do something like keep track of the last position you were at when the hook was run and only fire the network request if the current point differs from the last like so:
(defvar last-post-command-position 0
"Holds the cursor position from the last run of post-command-hooks.")
(make-variable-buffer-local 'last-post-command-position)
(defun do-stuff-if-moved-post-command ()
(unless (equal (point) last-post-command-position)
(let ((my-current-word (thing-at-point 'word)))
;; replace (message ...) with your code
(message "%s" my-current-word)))
(setq last-post-command-position (point)))
(add-to-list 'post-command-hook #'do-stuff-if-moved-post-command)

Related

I expect this elisp function to visualize entire function, but it visualizes beginning to cursor

It looks like the function that I use is not correctly visualizing the entire function. Currently, the function only visually highlights the region from the beginning of the function to the current buffer cursor position.
I want to modify this function to select the function, from top to bottom.
(defun evil-visual-current-function ()
"Highlight the entire current function in Evil's visual mode."
(interactive)
(let ((function-name (which-function)))
(if function-name
(progn
(beginning-of-defun)
(evil-visual-make-selection (point) (end-of-defun) (point)))
(message "Not inside a function"))))
When you leave the save-excursion block, the cursor moves back to the original position, which changes the selected region. Change the function to:
(defun evil-visual-current-function ()
"Highlight the entire current function in Evil's visual mode."
(interactive)
(let ((function-name (which-function))
(if function-name
(progn
(beginning-of-defun)
(evil-visual-make-selection (point) (end-of-defun) (point)))
(message "Not inside a function"))))

Stop emacs erc from recentering

Emacs erc keep recentering. It is very hard to keep up with the conversations in a small buffer because of it.
I've tried the followings but none seems to work...
(erc-scrolltobottom-mode)
(require 'erc-goodies)
(setq erc-input-line-position -1)
(erc-add-scroll-to-bottom)
(add-hook 'erc-mode-hook 'erc-add-scroll-to-bottom)
(add-hook 'erc-insert-post-hook 'erc-scroll-to-bottom)
Is there a way to keep erc from recentering?
The issue is that Emacs (and not erc) tries to recenter the screen every time, the cursor moves out of visible portion. See the docstring of scroll-conservatively(C-hvscroll-conservativelyRET)
Scroll up to this many lines, to bring point back on screen. If point
moves off-screen, redisplay will scroll by up to
`scroll-conservatively' lines in order to bring point just barely onto
the screen again. If that cannot be done, then redisplay recenters
point as usual.
If the value is greater than 100, redisplay will never recenter point,
but will always scroll just enough text to bring point into view, even
if you move far away.
A value of zero means always recenter point if it moves off screen.
So setting scroll-conservatively in erc-mode-hook might do the trick
(add-to-list 'erc-mode-hook (lambda ()
(set (make-local-variable 'scroll-conservatively) 100)))
Actually there are a lot of ways to achieve what you want. Have a look at this section of the Emacs manual
SOLUTION # 1:  Comment out line 101 of the Github source code in the following link -- i.e., comment out the line of code that looks like this: (recenter (or erc-input-line-position -1))
https://github.com/emacsmirror/erc/blob/master/erc-goodies.el
(defun erc-scroll-to-bottom (window display-start)
"Recenter WINDOW so that `point' is on the last line.
This is added to `window-scroll-functions' by `erc-add-scroll-to-bottom'.
You can control which line is recentered to by customizing the
variable `erc-input-line-position'.
DISPLAY-START is ignored."
(if (window-live-p window)
;; Temporarily bind resize-mini-windows to nil so that users who have it
;; set to a non-nil value will not suffer from premature minibuffer
;; shrinkage due to the below recenter call. I have no idea why this
;; works, but it solves the problem, and has no negative side effects.
;; (Fran Litterio, 2003/01/07)
(let ((resize-mini-windows nil))
(erc-with-selected-window window
(save-restriction
(widen)
(when (and erc-insert-marker
;; we're editing a line. Scroll.
(> (point) erc-insert-marker))
(save-excursion
(goto-char (point-max))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LINE 101 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (recenter (or erc-input-line-position -1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(sit-for 0))))))))
SOLUTION # 2:  In your .emacs file, you can create a new function and a defalias like this:
(require 'erc-goodies)
(erc-scrolltobottom-mode)
(setq erc-input-line-position -1)
(erc-add-scroll-to-bottom)
(add-hook 'erc-mode-hook 'erc-add-scroll-to-bottom)
(add-hook 'erc-insert-post-hook 'erc-scroll-to-bottom)
(defun guimobob-erc-scroll-to-bottom (window display-start)
"Recenter WINDOW so that `point' is on the last line.
This is added to `window-scroll-functions' by `erc-add-scroll-to-bottom'.
You can control which line is recentered to by customizing the
variable `erc-input-line-position'.
DISPLAY-START is ignored."
(if (window-live-p window)
;; Temporarily bind resize-mini-windows to nil so that users who have it
;; set to a non-nil value will not suffer from premature minibuffer
;; shrinkage due to the below recenter call. I have no idea why this
;; works, but it solves the problem, and has no negative side effects.
;; (Fran Litterio, 2003/01/07)
(let ((resize-mini-windows nil))
(erc-with-selected-window window
(save-restriction
(widen)
(when (and erc-insert-marker
;; we're editing a line. Scroll.
(> (point) erc-insert-marker))
(save-excursion
(goto-char (point-max))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (recenter (or erc-input-line-position -1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(sit-for 0))))))))
(defalias 'erc-scroll-to-bottom 'guimobob-erc-scroll-to-bottom)

Running command line commands in Emacs, and receiving their output

I want to run a set of command line commands in a loop within emacs, with the loop stopping when the user taps a key.
This is in order to see an ascii 'video' appear in Emacs, which stops when you press a key.
I thought it would be fun to have image-to-ascii bit of text as a comment (with the image coming from my mac's camera).
I use imagesnap to take the camera image, and jp2a to convert it to ascii. I think imagesnap is mac only. Here's the code I have so far:
(defun ascii-video-comment ()
"Makes video comment, requires imagemagick, jp2a, imagesnap"
(interactive)
(shell-command "imagesnap -q ~/Desktop/emacs-snap.jpg")
(insert (shell-command-to-string "jp2a --width=48 ~/Desktop/emacs-snap.jpg"))
(shell-command "rm ~/Desktop/emacs-snap.jpg")
)
This just takes a snap from the camera, converts to ascii, inserts it into my file, and places the cursor after.
Like I say, I would like it to keep looping, giving the appearance of a slow ascii video, until i tap a key to select the current 'frame'.
Is this even possible?
EDIT
This is my current code, which I'm fairly happy with. It loops 20 times, and you can choose the current image by cancelling (C-g). Things seem to go wrong when you do it a second time though.
(defun ascii-video-comment ()
"Makes video comment, requires imagemagick, jp2a, imagesnap"
(interactive)
(cl-loop repeat 20 do
(shell-command "imagesnap -q ~/Desktop/ascii-video-comment.jpg")
(cua-set-mark)
(insert (shell-command-to-string "jp2a --width=120 ~/Desktop/ascii-video-comment.jpg"))
(shell-command "rm ~/Desktop/ascii-video-comment.jpg")
(comment-region (mark) (point))
(cua-set-mark)
(pop-global-mark)
(sit-for 0.1)
(undo)
)
)
On your EDIT "final code": don't use interactive commands in a lisp program: you code becomes brittle and inefficient.
E.g., the doc string for shell-command (C-h f shell-command RET) explicitly states:
In Elisp, you will often be better served by calling call-process or
start-process directly, since it offers more control and does not
impose the use of a shell (with its need to quote arguments)
Also, use delete-file instead of (shell-command "rm ...").
Do not use cua-set-mark, pop-global-mark, and, especially, undo in programs.
Bind a variable instead:
(let ((beg (point)))
(call-process "jp2a" nil t t "--width=120" "~/Desktop/ascii-video-comment.jpg")
(comment-region beg (point))
(sit-for 0.1)
(delete-region beg (point)))
AFAIR, Emacs doesn't provide API to poll for pending events, so there are two options. UPD: disregard that, should've read the manual beforehand, Emacs does provide API to poll for pending events:
(defun start-printing-messages-2 ()
(interactive)
(while (not (input-pending-p))
(loop-body-function)
(redisplay 'force)))
If you want a delay between command execution, there's sit-for for you:
(defun start-printing-messages-3 ()
(interactive)
(while (sit-for 0.05)
(loop-body-function)))
If you want that delay to start counting from beginning of loop body rather than its end (if your loop body might take significant time), you need to set up full-fledged timer execution: you basically run a function in a timer and add a post-command-hook that will kill that timer:
(defvar loop-run-count 0)
(defvar loop-timer-object nil)
(defun loop-body-function ()
(setq loop-run-count (1+ loop-run-count))
(message "The function was run %s times" loop-run-count))
(defun stop-printing-messages ()
(when loop-timer-object
(cancel-timer loop-timer-object)
(remove-hook 'post-command-hook 'stop-printing-messages)))
(defun start-printing-messages ()
(interactive)
(setq loop-run-count 0)
;; post-command-hook is added via timer too, because otherwise it
;; might get called right after this function completes and this
;; would kill the timer that didn't even start yet.
;; get killed right after creation.
(run-with-timer
0.01 nil (lambda ()
(add-hook 'post-command-hook 'stop-printing-messages)))
(setq loop-timer-object
(run-with-timer nil 0.01 'loop-body-function)))
You can wait for input with while-no-input and sit-for.
For the use case you describe, sit-for is what you need.
Note that you should combine the two shell calls with && or make a shell
script.
Here is a toy command that does what you need, but only flashing random numbers.
(defun flash-me ()
"flash random number until you press a key"
(interactive)
(let ((beg (copy-marker (point)))
(end (copy-marker (point) t)))
(loop do (progn
(delete-region beg end)
(insert (shell-command-to-string "echo $RANDOM")))
while (sit-for 1))
(set-marker beg nil)
(set-marker end nil)))

Select the previously-selected window in emacs

I need an emacs built-in function or elisp function that can take me to the previously-selected window. I thought that (select-window (get-lru-window)) would do it, but if I run it several times, seems to just cycle between windows instead of swapping back and forth between them, which is what I expect.
Any other ideas?
There doesn't seem to be a way to get the most recently selected window in emacs (as opposed to the least recently used returned by get-lru-window). Internally emacs tracks use_time on windows, and get-lru-window uses that to find the "oldest" window. But unfortunately that is not exposed in elisp.
The window list is ordered in cyclic window ordering which doesn't help in your case.
The buffer-list is however ordered most-to-least recently used buffer (or not really strictly, there is a (bury-buffer) function to move a buffer last).
This means that, if you can transform your problem into something like "how can I switch to the buffer in a different window that was most recently the selected buffer", it should be possible.
One way would be to do something like this:
(defun switch-to-previous-buffer-in-a-different-window ()
(interactive)
(let* ((otherbuf (other-buffer (current-buffer) t))
(otherwin (get-buffer-window otherbuf)))
(if otherwin
(select-window otherwin)
(message "Last buffer (%s) is not currently visible" (buffer-name otherbuf)))))
Or the shorter, and more featureful:
(defun switch-to-previous-buffer-possibly-creating-new-window ()
(interactive)
(pop-to-buffer (other-buffer (current-buffer) t)))
Here other-buffer is used to get the most recently used buffer (except current-buffer). This should work fine as long as you don't switch buffers in the windows, because then other-buffer will no longer return the buffer in the other window, but the buffer you switched from in current window.
So instead of using other-buffer lets walk the buffer-list ourself to find the best candidate:
(defun switch-to-the-window-that-displays-the-most-recently-selected-buffer ()
(interactive)
(let* ((buflist (buffer-list (selected-frame))) ; get buffer list in this frames ordered
(buflist (delq (current-buffer) buflist)) ; if there are multiple windows showing same buffer.
(winlist (mapcar 'get-buffer-window buflist)) ; buf->win
(winlist (delq nil winlist)) ; remove non displayed windows
(winlist (delq (selected-window) winlist))) ; remove current-window
(if winlist
(select-window (car winlist))
(message "Couldn't find a suitable window to switch to"))))
Hope this helps.
If the last window switch was done programmatically, then it is possible to select the previously selected window.
(defun your-function ()
(interactive)
(let ((sw (selected-window)))
(do-something-useful-and-switch-window)
(select-window sw)))
If the last window switch was done manually, then it should be possible to overload the window switching command to update a global list of window selection order, which is then used to switch back.
(defun gs/pop-to-previous-window ()
(interactive)
(let ((win (get-mru-window t t t)))
(select-window win)))

kill the associated buffer when close the emacs-client frame by pressing Alt+F4

I get used to emacsclient for the speedy response like vim, by putting emacs into sever mode with command "emacs --daemon". But I found it quite annoying that lots of buffers kept alive when I viewed some files and then closed them by pressing Alt+F4. I have to kill the buffer explicitly before closing the frame.
I want to know, if there is a way to make emacsclient behave more like a lightweight GUI editor(e.g. vim) in this point?
I think you're asking for trouble, but you you could try this:
(add-hook 'delete-frame-functions
(lambda (frame)
(let* ((window (frame-selected-window frame))
(buffer (and window (window-buffer window))))
(when (and buffer (buffer-file-name buffer))
(kill-buffer buffer)))))
I suggest that you use the command quit-window which does precisely what you want (with the prefix argument); it is already the binding for q in special-mode (i.e., not self-insert) buffers. You can bind it to, say, C-f4, and it will kill the buffer and the frame when you type C-u C-f4.
Do something like the following:
(defun my-kill-buffer-and-frame ()
"kill the current buffer and the current frame"
(interactive)
(when (y-or-n-p "Are you sure you wish to delete the current frame?")
(kill-buffer)
(delete-frame)))
If you're sure you always wnt to do it, you can get rid of the prompt:
(defun my-kill-buffer-and-frame ()
"kill the current buffer and the current frame"
(interactive)
(kill-buffer)
(delete-frame))
Then bind it to a key of your choice, like so:
(global-set-key [(f5)] 'my-kill-buffer-and-frame)
Enjoy!