If I have two buffers open (side-by-side) and I move from one window to another, can I replace previously selected word in the first (now inactive) window with the one that is under cursor in active window?
_ is cursor
_______________
| foo | _bar |
| | |
| | |
| | |
|_______|_______|
is there an internal command that can quickly let me replace foo with bar?
No internal commands, but this is Emacs:
(defun replace-word-other-window ()
(interactive)
(let ((sym (thing-at-point 'symbol))
bnd)
(other-window 1)
(if (setq bnd (bounds-of-thing-at-point 'symbol))
(progn
(delete-region (car bnd) (cdr bnd))
(insert sym))
(message "no symbol at point in other window"))
(other-window -1)))
update: advanced version
(defun region-or-symbol-bounds ()
(if (region-active-p)
(cons (region-beginning)
(region-end))
(bounds-of-thing-at-point 'symbol)))
(defun replace-word-other-window ()
(interactive)
(let* ((bnd-1 (region-or-symbol-bounds))
(str-1 (buffer-substring-no-properties
(car bnd-1)
(cdr bnd-1)))
(bnd-2 (progn
(other-window 1)
(region-or-symbol-bounds))))
(if bnd-2
(progn
(delete-region (car bnd-2) (cdr bnd-2))
(insert str-1))
(message "no region or symbol at point in other window"))
(other-window -1)))
Related
Is it possible to calculate a new window-start/end without a redisplay occurring? If so, then an example would be greatly appreciated. If not, then what is the best way to approximate it?
Example: We want to move to a new area of the buffer somewhere off screen, and place overlays when we get there. We might be using page-down or scroll-down or paragraph-down or end-of-buffer. When we get to that new point, we want to calculate the new window-start and the new window-end. However, we want to avoid a momentary naked looking buffer without any overlays. Ideally, the redisplay would occur once those overlays are added. I want to restrict new overlays to the new region based upon the new window-start/end.
Point-Min: point = 1
Old Window Start: point = 1000
Old Window End: point = 1500
New Window Start: point = 3500
New Window End: point = 4000
Point-Max: point = 6000
Problem: When using the post-command-hook to try and calculate the new window-start and new window-end, the previous display positions are being used instead -- i.e., the old window-start and the old window-end.
Here is a sample of the project I am working on. Absent fixing the window-start \ window-end problem, I get the following error:
Error in post-command-hook (my-eol-ruler-function):
(error "Invalid search bound (wrong side of point)")`.
The error happens when going from (point-min) to the end of the buffer with the interactive function end-of-buffer. In the context of this error, (point-max) is beyond the old window-end.
EDIT: Updated code to include a message: (message "point: %s | window-start: %s | window-end: %s | point-max: %s" (point) (window-start) (window-end) (point-max) ). The message is used to demonstrate that the new window-start and new window-end are not calculated within the post-command-hook because a redisplay has not yet occurred. However, I am trying to avoid a redisplay until after the new overlays have been placed -- otherwise, a naked buffer without overlays is visible for a split second.
(defvar my-eol-ruler nil
"A horizontal ruler stretching from eol (end of line) to the window edge.")
(make-variable-buffer-local 'my-eol-ruler)
(defvar my-eol-pilcrow nil
"A pilcrow symbol placed at the end of every line except the current line.")
(make-variable-buffer-local 'my-eol-pilcrow)
(defun my-eol-ruler-function ()
(let* (
(opoint (point))
(window-width (window-width))
(window-start (window-start))
(window-end (window-end))
(col-eovl
(save-excursion
(vertical-motion 1)
(skip-chars-backward " \r\n" (- (point) 1))
(- (current-column) (progn (vertical-motion 0) (current-column)))))
(my-current-line-length (- (- window-width col-eovl) 3))
(pilcrow
(propertize (char-to-string ?\u00B6)
'face '(:foreground "white")
'cursor t))
(pilcrow-underlined
(propertize (char-to-string ?\u00B6)
'face '(:foreground "white" :underline "yellow")
'cursor t))
(underline (propertize (char-to-string ?\u2009)
'display `(space :width ,my-current-line-length)
'face '(:underline "yellow")
'cursor t)))
(when (or my-eol-ruler my-eol-pilcrow)
(dolist (description `(
,my-eol-ruler
,my-eol-pilcrow ))
(remove-overlays (point-min) (point-max)
'after-string description)) )
(setq my-eol-ruler (concat pilcrow-underlined underline))
(setq my-eol-pilcrow pilcrow)
(save-excursion
(end-of-line)
(overlay-put (make-overlay (point) (point))
'after-string my-eol-ruler ) )
(message "point: %s | window-start: %s | window-end: %s | point-max: %s"
(point)
(window-start)
(window-end)
(point-max) )
(save-excursion
(goto-char window-end)
(while (re-search-backward "\n" window-start t)
(let* (
(pbol (point-at-bol))
(pbovl (save-excursion (vertical-motion 0) (point)))
(peol (point))
(peol-pbol-region-p
(if (region-active-p)
(= peol pbol)))
(eol-inside-region-p
(if (region-active-p)
(and
(<= reg-beg peol)
(> reg-end peol))))
(col-eovl
(save-excursion
(vertical-motion 1)
(skip-chars-backward " \r\n" (- (point) 1))
(- (current-column) (progn (vertical-motion 0) (current-column)))))
(my-last-column (current-column))
(window-width-bug-p (= my-last-column (- window-width 1)))
(shazbot-pbol
(save-excursion
(end-of-line)
(re-search-backward "\s\\|\t" pbol t) (+ (point) 1)))
(wrapped-window-width-bug-p (= col-eovl (- window-width 1))) )
(when
(or
(< opoint pbol)
(> opoint peol))
(overlay-put (make-overlay peol peol) 'after-string my-eol-pilcrow))))) ))
(add-hook 'post-command-hook 'my-eol-ruler-function)
Beginning of the buffer, before the error occurs.
End of the buffer -- the error occurs when executing the interactive function end-of-buffer from a point at the beginning of the buffer.
Error in post-command-hook (my-eol-ruler-function):
(error "Invalid search bound (wrong side of point)")
See also Emacs bug tracker feature request #22404 (which has not yet been implemented, but the mailing archive contains a rough draft rudimentary patch that creates a new hook for this specific issue): https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22404
Minor-mode for testing window-start and window-end BEFORE visual redisplay.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; test-mode
;; A minor-mode for testing `window-start` / `window-end` BEFORE visual redisplay.
(defvar test-this-command nil
"This local variable is set within the `post-command-hook`; and,
is also used by the `window-scroll-functions` hook.")
(make-variable-buffer-local 'test-this-command)
(defun test-post-command-hook-fn ()
"A function attached to the `post-command-hook`."
(setq test-this-command this-command)
(test-demo-fn))
(defun test-window-scroll-functions-fn (win _start)
"A function attached to the `window-scroll-functions` hook."
(test-demo-fn))
(defun test-demo-fn ()
"This is a test-mode demonstration function."
(when
(and
test-mode
test-this-command
(window-live-p (get-buffer-window (current-buffer)))
(not (minibufferp))
(pos-visible-in-window-p (point)
(get-buffer-window (current-buffer) (selected-frame)) t))
(let* (
(selected-window (selected-window))
(window-start (window-start selected-window))
(window-end (window-end selected-window t)) )
(message "window-start: %s | window-end: %s" window-start window-end)
(setq test-this-command nil) )))
(define-minor-mode test-mode
"A minor-mode for testing `window-start` / `window-end` BEFORE visual redisplay."
:init-value nil
:lighter " TEST"
:keymap nil
:global nil
:group nil
(cond
(test-mode
(set (make-local-variable 'scroll-conservatively) 101)
(add-hook 'post-command-hook 'test-post-command-hook-fn nil t)
(add-hook 'window-scroll-functions 'test-window-scroll-functions-fn nil t)
(when (called-interactively-p 'any)
(message "Turned ON `test-mode`.")))
(t
(kill-local-variable 'scroll-conservatively)
(kill-local-variable 'test-this-command)
(remove-hook 'post-command-hook 'test-post-command-hook-fn t)
(remove-hook 'window-scroll-functions 'test-window-scroll-functions-fn t)
(when (called-interactively-p 'any)
(message "Turned OFF `test-mode`.") ))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Offhand, I'd say that the error is raised because you pass a BOUND arg to a search function. For example:
(re-search-backward "\n" window-start t)
(re-search-backward "\s\\|\t" pbol t)
Check your values of window-start and pbol. Remember that when you search backward the bound must not be greater than the current position (point).
I think you want to use jit-lock-register instead of post-command-hook. This way, the redisplay code will call you back once it has decided of a window-start and you'll be able to add the overlays you want before the buffer's content is displayed.
Is there a select region function that will preserve the selection if the region scrolls out of sight?
There are two kinds of selected region that I use on a daily basis. The first kind is with the shift key using an interactive code "^" in various movement functions -- e.g., left or right. The second kind is set-mark-command. In the first case, the highlighted region is deselected when I scroll up or down. In the second case, the highlighted region changes / moves if the selected region touches the top or bottom of the window when scrolling.
Ideally, I would like to select a region and then be free to move around the buffer from point-min to point-max.
I do not think there is such a function. The thing is emacs moves the point on scrolling (when the point moves out of window) that is why the selected region changes. See this question
That looks promising:
https://sites.google.com/site/steveyemacsutils/multi-select-el
There is also a multi-region.el at emacswiki.org
INITIAL (March 4, 2014): First rough draft. lawlist-mwheel-scroll is a modification of mwheel-scroll within mwheel.el -- the primary modification was to remove (let ((newpoint (point))) (goto-char opoint) (deactivate-mark) (goto-char newpoint)) and replace it with a fixed overlay based upon region-begin and region-end immediately before scrolling up or down.
EDIT (March 5, 2014): Revised lawlist-mwheel-scroll to behave more like mwheel-scroll was originally intended within mwheel.el. Because regions can be selected from left to right, or from right to left, the original-point could be on either side of the selected region. Therefore, region-begin and region-end are not used to calculate whether the point has moved -- we use original-point and compare it to the potential new (point) after scrolling has occurred. Consolidated the contents of the prior function lawlist-select-region into the function lawlist-activate-deactivate-mark such that the former is no longer used.
(global-set-key (kbd "C-c c") 'lawlist-copy-selected-region)
(global-set-key (kbd "C-SPC") 'lawlist-activate-deactivate-mark)
(global-set-key [(wheel)] 'lawlist-mwheel-scroll)
(global-set-key [(wheel-down)] 'lawlist-mwheel-scroll)
(global-set-key [(wheel-up)] 'lawlist-mwheel-scroll)
(defvar region-begin nil
"The beginning of the selected region.")
(make-variable-buffer-local 'region-begin)
(defvar region-end nil
"The ending of the selected region.")
(make-variable-buffer-local 'region-end)
(defun lawlist-activate-deactivate-mark ()
(interactive)
(cond
;; newly selected region -- no prior overlay
((and
(region-active-p)
(not region-begin)
(not region-end))
(setq region-begin (region-beginning))
(setq region-end (region-end))
(overlay-put (make-overlay region-begin region-end) 'priority 1001)
(overlay-put (make-overlay region-begin region-end) 'face isearch-face)
(deactivate-mark t))
;; prior overlay + newly selected region
((and
(region-active-p)
region-begin
region-end)
(mapc 'delete-overlay (overlays-in region-begin region-end))
(setq region-begin (region-beginning))
(setq region-end (region-end))
(overlay-put (make-overlay region-begin region-end) 'priority 1001)
(overlay-put (make-overlay region-begin region-end) 'face isearch-face)
(deactivate-mark t))
;; prior overlay -- no selected region -- inside of overlay
((and
(not (region-active-p))
region-begin
region-end
(and
(>= (point) region-begin)
(<= (point) region-end)))
(message "[b]egin | [e]nd | [c]urrent | [d]eactivate")
(let* ((extend-region (read-char-exclusive)))
(cond
((eq extend-region ?b)
(set-marker (mark-marker) region-begin (current-buffer))
(setq mark-active t))
((eq extend-region ?e)
(set-marker (mark-marker) region-end (current-buffer))
(setq mark-active t))
((eq extend-region ?c)
(set-marker (mark-marker) (point) (current-buffer))
(setq mark-active t))
((eq extend-region ?d)
(deactivate-mark t))))
(mapc 'delete-overlay (overlays-in region-begin region-end)))
;; prior overlay -- no selected region -- outside of overlay
((and
(not (region-active-p))
region-begin
region-end
(or
(< (point) region-begin)
(> (point) region-end)))
(mapc 'delete-overlay (overlays-in region-begin region-end))
(setq region-begin nil)
(setq region-end nil)
(deactivate-mark t))
(t
(set-mark-command nil))))
(defun lawlist-copy-selected-region ()
(interactive)
(cond
;; prior overlay + newly selected region
((and
(region-active-p)
region-begin
region-end)
(mapc 'delete-overlay (overlays-in region-begin region-end))
(setq region-begin (region-beginning))
(setq region-end (region-end)))
;; prior overlay + no region selected
((and
(not (region-active-p))
region-begin
region-end)
(mapc 'delete-overlay (overlays-in region-begin region-end)))
;; newly selected region -- no prior overlay
((and
(region-active-p)
(not region-begin)
(not region-end))
(setq region-begin (region-beginning))
(setq region-end (region-end))) )
(if (and region-begin region-end)
(progn
(copy-region-as-kill region-begin region-end)
(message "copied: %s"
(concat
(truncate-string-to-width
(buffer-substring-no-properties region-begin region-end)
40)
(if
(>
(length
(buffer-substring-no-properties region-begin region-end))
40)
" . . ."
"")))
(setq region-begin nil)
(setq region-end nil))
(message "To copy, you must first select a region.")))
(defun lawlist-mwheel-scroll (event)
"Scroll up or down according to the EVENT.
This should only be bound to mouse buttons 4 and 5."
(interactive (list last-input-event))
(let* (
(curwin
(if mouse-wheel-follow-mouse
(prog1
(selected-window)
(select-window (mwheel-event-window event)))))
(buffer (window-buffer curwin))
(original-point
(with-current-buffer buffer
(when (eq (car-safe transient-mark-mode) 'only)
(point))))
(mods
(delq 'click (delq 'double (delq 'triple (event-modifiers event)))))
(amt (assoc mods mouse-wheel-scroll-amount)))
(with-current-buffer buffer
(when (eq (car-safe transient-mark-mode) 'only)
(setq region-begin (region-beginning))
(setq region-end (region-end))))
(if amt (setq amt (cdr amt))
(let ((list-elt mouse-wheel-scroll-amount))
(while (consp (setq amt (pop list-elt))))))
(if (floatp amt) (setq amt (1+ (truncate (* amt (window-height))))))
(when (and mouse-wheel-progressive-speed (numberp amt))
(setq amt (* amt (event-click-count event))))
(unwind-protect
(let ((button (mwheel-event-button event)))
(cond
((eq button mouse-wheel-down-event)
(condition-case nil (funcall mwheel-scroll-down-function amt)
(beginning-of-buffer
(unwind-protect
(funcall mwheel-scroll-down-function)
(set-window-start (selected-window) (point-min))))))
((eq button mouse-wheel-up-event)
(condition-case nil (funcall mwheel-scroll-up-function amt)
(end-of-buffer (while t (funcall mwheel-scroll-up-function)))))
(t (error "Bad binding in mwheel-scroll"))))
(if curwin (select-window curwin)))
(with-current-buffer buffer
(when
(and
original-point
(/= (point) original-point))
(overlay-put (make-overlay region-begin region-end) 'priority 1001)
(overlay-put (make-overlay region-begin region-end) 'face isearch-face)
(deactivate-mark t) )))
(when (and mouse-wheel-click-event mouse-wheel-inhibit-click-time)
(if mwheel-inhibit-click-event-timer
(cancel-timer mwheel-inhibit-click-event-timer)
(add-hook 'pre-command-hook 'mwheel-filter-click-events))
(setq mwheel-inhibit-click-event-timer
(run-with-timer mouse-wheel-inhibit-click-time nil
'mwheel-inhibit-click-timeout))))
(put 'lawlist-mwheel-scroll 'scroll-command t)
How can I display the name of a bookmark (from 'bookmark' or 'bookmark+') in the mode line of emacs, instead of the file name?
A slightly strange request, but here you go (works for files and dired buffers):
(defun show-bookmarks-mode-line ()
(interactive)
(let (bname text)
(and
(setq bname (if (eq major-mode 'dired-mode)
default-directory
(buffer-file-name)))
(setq bname (expand-file-name bname))
(setq text
(delq nil
(mapcar
(lambda (x)
(and (equal bname
(expand-file-name
(bookmark-get-filename x)))
(substring-no-properties (car x))))
bookmark-alist)))
(setq text
(mapconcat
#'identity
text
", "))
(let ((mode-line-buffer-identification
(propertize text 'face 'mode-line-buffer-id)))
(force-mode-line-update)
(sit-for 5))
(force-mode-line-update))))
Could you elaborate on why you need it?
Basically I want the *Messages* buffer to always scroll to the bottom when a new message arrives.
Can I do that?
I found auto-revert-tail-mode but that works for buffers that are visiting files.
When I tried it in the Messages buffer, it popped an error:
auto-revert-tail-mode: This buffer is not visiting a file
For multiple frames you probably want:
(defadvice message (after message-tail activate)
"goto point max after a message"
(with-current-buffer "*Messages*"
(goto-char (point-max))
(walk-windows (lambda (window)
(if (string-equal (buffer-name (window-buffer window)) "*Messages*")
(set-window-point window (point-max))))
nil
t)))
Just put point at the end of the buffer M->. If you don't manually move it it will stay there -- IOW, you will always see the tail.
This code seems a bit overkill, but a the simple (goto-char (point-max)) wasn't working for me:
(defadvice message (after message-tail activate)
"goto point max after a message"
(with-current-buffer "*Messages*"
(goto-char (point-max))
(let ((windows (get-buffer-window-list (current-buffer) nil t)))
(while windows
(set-window-point (car windows) (point-max))
(setq windows (cdr windows))))))
Here's an implementation that uses the new advice style.
(defun message-buffer-goto-end-of-buffer (&rest args)
(let* ((win (get-buffer-window "*Messages*"))
(buf (and win (window-buffer win))))
(and win (not (equal (current-buffer) buf))
(set-window-point
win (with-current-buffer buf (point-max))))))
(advice-add 'message :after 'message-buffer-goto-end-of-buffer)
i run 23.3 and there were still way too many occasions where the built-in 'solution' and the orginal defadvice on the message function just didn't cut it, so i wrapped that code in a list / toggle / timer set up and it's working beautifully - no more frustration when debugging!
it's generic, so works on any buffer, although i only really use it for..
(toggle-buffer-tail "*Messages*" "on")
..hope it's useful to someone.
;alist of 'buffer-name / timer' items
(defvar buffer-tail-alist nil)
(defun buffer-tail (name)
"follow buffer tails"
(cond ((or (equal (buffer-name (current-buffer)) name)
(string-match "^ \\*Minibuf.*?\\*$" (buffer-name (current-buffer)))))
((get-buffer name)
(with-current-buffer (get-buffer name)
(goto-char (point-max))
(let ((windows (get-buffer-window-list (current-buffer) nil t)))
(while windows (set-window-point (car windows) (point-max))
(with-selected-window (car windows) (recenter -3)) (setq windows (cdr windows))))))))
(defun toggle-buffer-tail (name &optional force)
"toggle tailing of buffer NAME. when called non-interactively, a FORCE arg of 'on' or 'off' can be used to to ensure a given state for buffer NAME"
(interactive (list (cond ((if name name) (read-from-minibuffer
(concat "buffer name to tail"
(if buffer-tail-alist (concat " (" (caar buffer-tail-alist) ")") "") ": ")
(if buffer-tail-alist (caar buffer-tail-alist)) nil nil
(mapcar '(lambda (x) (car x)) buffer-tail-alist)
(if buffer-tail-alist (caar buffer-tail-alist)))) nil)))
(let ((toggle (cond (force force) ((assoc name buffer-tail-alist) "off") (t "on")) ))
(if (not (or (equal toggle "on") (equal toggle "off")))
(error "invalid 'force' arg. required 'on'/'off'")
(progn
(while (assoc name buffer-tail-alist)
(cancel-timer (cdr (assoc name buffer-tail-alist)))
(setq buffer-tail-alist (remove* name buffer-tail-alist :key 'car :test 'equal)))
(if (equal toggle "on")
(add-to-list 'buffer-tail-alist (cons name (run-at-time t 1 'buffer-tail name))))
(message "toggled 'tail buffer' for '%s' %s" name toggle)))))
edit: changed functionality to display tail at the bottom of the window
Here's an amendment over Peter's / Trey's solutions
(defun modi/messages-auto-tail (&rest _)
"Make *Messages* buffer auto-scroll to the end after each message."
(let* ((buf-name "*Messages*")
;; Create *Messages* buffer if it does not exist
(buf (get-buffer-create buf-name)))
;; Activate this advice only if the point is _not_ in the *Messages* buffer
;; to begin with. This condition is required; otherwise you will not be
;; able to use `isearch' and other stuff within the *Messages* buffer as
;; the point will keep moving to the end of buffer :P
(when (not (string= buf-name (buffer-name)))
;; Go to the end of buffer in all *Messages* buffer windows that are
;; *live* (`get-buffer-window-list' returns a list of only live windows).
(dolist (win (get-buffer-window-list buf-name nil :all-frames))
(with-selected-window win
(goto-char (point-max))))
;; Go to the end of the *Messages* buffer even if it is not in one of
;; the live windows.
(with-current-buffer buf
(goto-char (point-max))))))
(advice-add 'message :after #'modi/messages-auto-tail)
I would like to export from Org-Mode tables to s-expressions.
| first | second | thrid |
|--------+--------+--------|
| value1 | value2 | value3 |
| value4 | value5 | value6 |
Would turn into:
((:FIRST "value1" :SECOND "value2" :THIRD "value3")
(:FIRST "value4" :SECOND "value5" :THIRD "value6"))
I plan on writing such a setup if it doesn't exist yet but figured I'd tap into the stackoverflow before I start reinventing the wheel.
This does the trick. It has minimal error checking.
The interface to use is either the programmatic interface:
(org-table-to-sexp <location-of-beginning-of-table> <location-of-end-of-table>)
In which case it'll return the sexp you requested.
If you wanted an interactive usage, you can call the following command to operate on the table in the region. So, set the mark at the beginning of the table, move to the end, and type:
M-x insert-org-table-to-sexp
That will insert the desired sexp immediately after the table in the current buffer.
Here is the code:
(defun org-table-to-sexp-parse-line ()
"Helper, returns the current line as a list of strings"
(save-excursion
(save-match-data
(let ((result nil)
(end-of-line (save-excursion (end-of-line) (point))))
(beginning-of-line)
(while (re-search-forward "\\([^|]*\\)|" end-of-line t)
(let ((match (mapconcat 'identity (split-string (match-string-no-properties 1)) " ")))
(if (< 0 (length match))
;; really want to strip spaces from front and back
(push match result))))
(reverse result)))))
(require 'cl)
(defun org-table-to-sexp (b e)
"Parse an org-mode table to sexp"
(save-excursion
(save-match-data
(goto-char b)
(let ((headers (mapcar
(lambda (str)
(make-symbol (concat ":" (upcase str))))
(org-table-to-sexp-parse-line)))
(sexp nil))
(forward-line 1) ;skip |--+--+--| line
(while (< (point) e)
(forward-line 1)
(let ((line-result nil))
(mapcar* (lambda (h e)
(push h line-result)
(push e line-result))
headers
(org-table-to-sexp-parse-line))
(if line-result
(push (reverse line-result)
sexp))))
sexp))))
(defun insert-org-table-to-sexp (b e)
"Convert the table specified by the region and insert the sexp after the table"
(interactive "r")
(goto-char (max b e))
(print (org-table-to-sexp b e) (current-buffer)))