Error message: let: Wrong type argument: overlayp, (#<overlay from 478 to 480 in *Calendar*>)
mouse-1 successfully marks a date in the calendar. The built-in functions only provide for deleting all of the overlays, instead of just one particular date. Could anyone please give me a hand to delete the overlay for just one marked date -- I was thinking this could be either mouse-2 or U. I thought of using skip-syntax-forwards/backwards because some of the dates have just one digit, and some have two digits -- the cursor may be between two digits or on either side of the date. I assume we need a beginning and ending point.
(define-key calendar-mode-map [mouse-1] (lambda () (interactive)
(calendar-mark-visible-date (calendar-cursor-to-date t))))
(define-key calendar-mode-map "U" (lambda () (interactive)
(cond
((save-excursion (> 0 (skip-syntax-backward "w")))
(skip-syntax-backward "w")
(let ((beg (point)))
(skip-syntax-forward "w")
(let ((end (point)))
(delete-overlay (overlays-in beg end)))))
((save-excursion (< 0 (skip-syntax-forward "w")))
(skip-syntax-forward "w")
(let ((end (point)))
(skip-syntax-backward "w")
(let ((beg (point)))
(delete-overlay (overlays-in beg end))))))))
EDIT (December 12, 2013): First working draft based upon the helpful answer from #Drew. Added mouse-set-point and interactive code to support said function. Consolidated keyboard shortcuts so that mouse-1 activates / deactivates the overlay at point -- now uses overlays-at.
EDIT (January 1, 2014): To distinguish between one or more overlays at point, see the following thread: How to distinguish between different overlays at point With the examples in that thread, different actions can occur depending upon whether a particular overlay exists at point.
(defvar lawlist-calendar-face (make-face 'lawlist-calendar-face))
(set-face-attribute 'lawlist-calendar-face nil
:background "LightCoral" :foreground "black")
(define-key calendar-mode-map [mouse-1] (lambda (event) (interactive "e")
(mouse-set-point event)
(if (not (overlays-at (point)))
(calendar-mark-visible-date (calendar-cursor-to-date t) lawlist-calendar-face)
(cond
;; cursor is one whitespace to the left of 1 to 9
((and
(save-excursion (< 0 (skip-chars-forward " \t")))
(not (save-excursion (< 0 (skip-syntax-forward "w")))))
(save-excursion
(let ((beg (point)))
(skip-chars-forward " \t")
(skip-syntax-forward "w")
(let ((end (point)))
(mapc 'delete-overlay (overlays-in beg end))))))
;; cursor is sandwiched between a digit on each side.
((and
(save-excursion (> 0 (skip-syntax-backward "w")))
(save-excursion (< 0 (skip-syntax-forward "w"))))
(save-excursion
(skip-syntax-backward "w")
(let ((beg (point)))
(skip-syntax-forward "w")
(let ((end (point)))
(mapc 'delete-overlay (overlays-in beg end))))))
;; cursor is to the far right of one or two digit dates
((and
(save-excursion (> 0 (skip-syntax-backward "w")))
(not (save-excursion (< 0 (skip-syntax-forward "w")))))
(save-excursion
(skip-syntax-backward "w")
(let ((beg (point)))
(skip-syntax-forward "w")
(let ((end (point)))
(mapc 'delete-overlay (overlays-in beg end))))))
;; cursor to the far left of one or two digits dates
((and
(save-excursion (< 0 (skip-syntax-forward "w")))
(not (save-excursion (> 0 (skip-syntax-backward "w")))))
(save-excursion
(skip-syntax-forward "w")
(let ((end (point)))
(skip-syntax-backward "w")
(let ((beg (point)))
(mapc 'delete-overlay (overlays-in beg end))))))))))
Wrt the error:
delete-overlay expects a single overlay as its argument. You are passing it a list (empty or nonempty) of overlays instead. You should iterate over the list, e.g., with while or dolist or mapc.
Related
I'm trying to add source blocks to the visibility cycling tree. Essentially I want a source block to be treated as a child of its heading. Consider the following org-mode document:
* Heading 1
** Heading 2
#+BEGIN_SRC R
print("hello world")
#+END_SRC
** Heading 3
I would like to be able to press TAB on heading one to cycle through the folding of the various parts including the source block. Currently org-mode does seem to have the facilities for folding the source block, because I can fold that if I go to #+BEGIN_SRC R and hit tab, but it doesnt seem to be being treated in the global cycling. Any suggestions to add it?
Thanks!
This is a slight modification of the code contained in the link mentioned in my first comment above: https://stackoverflow.com/a/21594242/2112489
All I did was replace the begin / end html regexp for the SRC regexp. Go ahead and give it a whirl and see if it is what you're looking for. I left my prior footnote modification in there.
(require 'org)
(defalias 'org-cycle-hide-drawers 'lawlist-block-org-cycle-hide-drawers)
(defun lawlist-block-org-cycle-hide-drawers (state)
"Re-hide all drawers, footnotes or html blocks after a visibility state change."
(when
(and
(derived-mode-p 'org-mode)
(not (memq state '(overview folded contents))))
(save-excursion
(let* (
(globalp (memq state '(contents all)))
(beg (if globalp (point-min) (point)))
(end
(cond
(globalp
(point-max))
((eq state 'children)
(save-excursion (outline-next-heading) (point)))
(t (org-end-of-subtree t)) )))
(goto-char beg)
(while
(re-search-forward
".*\\[fn\\|^\\#\\+BEGIN_SRC.*$\\|^[ \t]*:PROPERTIES:[ \t]*$" end t)
(lawlist-org-flag t))))))
(defalias 'org-cycle-internal-local 'lawlist-block-org-cycle-internal-local)
(defun lawlist-block-org-cycle-internal-local ()
"Do the local cycling action."
(let ((goal-column 0) eoh eol eos has-children children-skipped struct)
(save-excursion
(if (org-at-item-p)
(progn
(beginning-of-line)
(setq struct (org-list-struct))
(setq eoh (point-at-eol))
(setq eos (org-list-get-item-end-before-blank (point) struct))
(setq has-children (org-list-has-child-p (point) struct)))
(org-back-to-heading)
(setq eoh (save-excursion (outline-end-of-heading) (point)))
(setq eos (save-excursion (1- (org-end-of-subtree t t))))
(setq has-children
(or
(save-excursion
(let ((level (funcall outline-level)))
(outline-next-heading)
(and
(org-at-heading-p t)
(> (funcall outline-level) level))))
(save-excursion
(org-list-search-forward (org-item-beginning-re) eos t)))))
(beginning-of-line 2)
(if (featurep 'xemacs)
(while
(and
(not (eobp))
(get-char-property (1- (point)) 'invisible))
(beginning-of-line 2))
(while
(and
(not (eobp))
(get-char-property (1- (point)) 'invisible))
(goto-char (next-single-char-property-change (point) 'invisible))
(and
(eolp)
(beginning-of-line 2))))
(setq eol (point)))
(cond
((= eos eoh)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-pre-cycle-hook 'empty))
(org-unlogged-message "EMPTY ENTRY")
(setq org-cycle-subtree-status nil)
(save-excursion
(goto-char eos)
(outline-next-heading)
(if (outline-invisible-p)
(org-flag-heading nil))))
((and
(or
(>= eol eos)
(not (string-match "\\S-" (buffer-substring eol eos))))
(or
has-children
(not (setq children-skipped
org-cycle-skip-children-state-if-no-children))))
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-pre-cycle-hook 'children))
(if (org-at-item-p)
;; then
(org-list-set-item-visibility (point-at-bol) struct 'children)
;; else
(org-show-entry)
(org-with-limited-levels (show-children))
(when (eq org-cycle-include-plain-lists 'integrate)
(save-excursion
(org-back-to-heading)
(while (org-list-search-forward (org-item-beginning-re) eos t)
(beginning-of-line 1)
(let* (
(struct (org-list-struct))
(prevs (org-list-prevs-alist struct))
(end (org-list-get-bottom-point struct)))
(mapc (lambda (e) (org-list-set-item-visibility e struct 'folded))
(org-list-get-all-items (point) struct prevs))
(goto-char (if (< end eos) end eos)))))))
(org-unlogged-message "CHILDREN")
(save-excursion
(goto-char eos)
(outline-next-heading)
(if (outline-invisible-p)
(org-flag-heading nil)))
(setq org-cycle-subtree-status 'children)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-cycle-hook 'children)))
((or
children-skipped
(and
(eq last-command this-command)
(eq org-cycle-subtree-status 'children)))
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-pre-cycle-hook 'subtree))
(outline-flag-region eoh eos nil)
(org-unlogged-message
(if children-skipped
"SUBTREE (NO CHILDREN)"
"SUBTREE"))
(setq org-cycle-subtree-status 'subtree)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-cycle-hook 'subtree)))
((eq org-cycle-subtree-status 'subtree)
(org-show-subtree)
(message "ALL")
(setq org-cycle-subtree-status 'all))
(t
(run-hook-with-args 'org-pre-cycle-hook 'folded)
(outline-flag-region eoh eos t)
(org-unlogged-message "FOLDED")
(setq org-cycle-subtree-status 'folded)
(unless (org-before-first-heading-p)
(run-hook-with-args 'org-cycle-hook 'folded))))))
(defun lawlist-org-flag (flag)
"When FLAG is non-nil, hide any of the following: html code block;
footnote; or, the properties drawer. Otherwise make it visible."
(save-excursion
(beginning-of-line 1)
(cond
((looking-at ".*\\[fn")
(let* (
(begin (match-end 0))
end-footnote)
(if (re-search-forward "\\]"
(save-excursion (outline-next-heading) (point)) t)
(progn
(setq end-footnote (point))
(outline-flag-region begin end-footnote flag))
(user-error "Error beginning at point %s." begin))))
((looking-at "^\\#\\+BEGIN_SRC.*$\\|^[ \t]*:PROPERTIES:[ \t]*$")
(let* ((begin (match-end 0)))
(if (re-search-forward "^\\#\\+END_SRC.*$\\|^[ \t]*:END:"
(save-excursion (outline-next-heading) (point)) t)
(outline-flag-region begin (point-at-eol) flag)
(user-error "Error beginning at point %s." begin)))))))
(defun lawlist-toggle-block-visibility ()
"For this function to work, the cursor must be on the same line as the regexp."
(interactive)
(if
(save-excursion
(beginning-of-line 1)
(looking-at
".*\\[fn\\|^\\#\\+BEGIN_SRC.*$\\|^[ \t]*:PROPERTIES:[ \t]*$"))
(lawlist-org-flag (not (get-char-property (match-end 0) 'invisible)))
(message "Sorry, you are not on a line containing the beginning regexp.")))
I am looking for some assistance, please, to track down why the runtime of following overlay function increases with each successive run.
From what I can tell, the runtime should be the same if the text in the buffer remains the same -- i.e., just moving the cursor left / right should not increase the runtime (but it does).
I tried the following, but to no avail: (setq buffer-undo-list t); killing all local variables; (setq-default cache-long-scans nil).
This function is a scaled down version for purposes of creating a minimal working example. The full version starts of with a .1 second runtime and increases .1 seconds each successive run until the function becomes unusable.
(add-hook 'post-command-hook (lambda ()
(draw-vertical-line (window-start) (window-end))))
(defun draw-vertical-line (start end)
"Erase and redraw the vertical-line between START and END."
(measure-time
(setq my-cursor-point (point))
(setq my-current-col (current-column))
(save-excursion
(if (not (eq start (progn (goto-char start) (point-at-bol))))
(setq start (progn (goto-char start) (beginning-of-line) (point)))))
(save-excursion
(let* (my-last-column my-overlay beg-ov end-ov)
(goto-char end)
(mapc #'(lambda (o) (when (overlay-get o 'my-overlay-properties)
(delete-overlay o))) (overlays-in start end))
(goto-char end)
(while (re-search-backward "\n" start t)
(setq my-last-column (current-column))
(my-not-wrapped-line-function) )))))
(defun my-not-wrapped-line-function ()
(unless (eq (buffer-size) 0)
(setq beg-ov (save-excursion (move-to-column my-current-col) (point)))
(setq end-ov (+ 1 beg-ov))
(setq my-overlay (make-overlay beg-ov end-ov ))
(cond
;; text, excluding tabs
((and
(or
(< my-current-col my-last-column)
(and (eobp) (= my-current-col my-last-column)))
(not-tab-looking-back-p)
(not (eq my-cursor-point beg-ov)))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'text-exclude-tabs t)
(overlay-put my-overlay 'face '(:background "yellow" :foreground "black") ) )
;; tab with text to the right
((and
(tab-left-p)
(tab-looking-forward-p)
(tab-p)
(not (eq my-cursor-point beg-ov))
(< my-current-col my-last-column))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'tab-text-right t)
(overlay-put my-overlay 'face '(:foreground "purple" :weight bold) ) )
;; tab with text to the left
((and
(not-tab-left-p)
(tab-p)
(not (eq my-cursor-point beg-ov))
(< my-current-col my-last-column))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'tab-text-left t)
(overlay-put my-overlay 'face '(:foreground "green" :weight bold) ) )
;; tab sandwiched between a tab on each side
((and
(tab-p)
(tab-sandwiched-p)
(not (eq my-cursor-point beg-ov))
(< my-current-col my-last-column))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'tab-sandwiched t)
(overlay-put my-overlay 'face '(:foreground "orange" :weight bold) ) )
;; end of line, but not wrapped
((and
(= my-current-col my-last-column)
(eolp)
(not (eq my-cursor-point beg-ov)))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'eol t)
(overlay-put my-overlay 'face '(:foreground "brown" :weight bold) ) )
;; cursor -- not wrapped -- not end of line
((and
(not
(catch 'found
(dolist (ol (overlays-at beg-ov))
(and (overlay-get ol 'hl-p)
(throw 'found t)))))
(not (region-active-p))
(eq my-cursor-point beg-ov)
(not (eq (preceding-char) 9))
(< my-current-col my-last-column))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'my-cursor-not-wrapped-not-eol t)
(overlay-put my-overlay 'face '(:background "black" :weight bold) ) )
;; cursor -- end of line, but not a wrapped line
((and
(not (region-active-p))
(eq my-cursor-point beg-ov)
;; (not (eq (preceding-char) 9))
(= my-current-col my-last-column))
(overlay-put my-overlay 'my-overlay-properties t)
(overlay-put my-overlay 'my-cursor-eol-not-wrapped t)
(overlay-put my-overlay 'face '(:foreground "SteelBlue" :weight bold) ) ) )))
(defvar my-cursor-point nil
"Point used to prevent the formation of a cursor overlay.
It must be set within the function `draw-vertical-line`.")
(make-variable-buffer-local 'my-cursor-point)
(defsubst tab-left-p ()
(not (not (save-excursion
(if my-current-col
(move-to-column my-current-col)
(current-column))
(unless (bobp) (backward-char 1)) (eq (char-after (point)) 9)))))
(defsubst not-tab-left-p ()
(not (save-excursion
(if my-current-col
(move-to-column my-current-col)
(current-column))
(unless (bobp) (backward-char 1)) (eq (char-after (point)) 9))))
(defsubst tab-p ()
(save-excursion
(if my-current-col
(move-to-column my-current-col)
(current-column))
(eq (char-after (point)) 9)))
(defsubst not-tab-looking-back-p ()
(not (save-excursion
(if my-current-col
(move-to-column (+ 1 my-current-col))
(move-to-column (+ 1 (current-column))))
(eq (preceding-char) 9))))
(defsubst tab-looking-forward-p ()
(not (save-excursion
(if my-current-col
(move-to-column (+ 1 my-current-col))
(move-to-column (+ 1 current-column)))
(eq (char-after (point)) 9))))
(defsubst tab-sandwiched-p ()
(let ((my-current-col
(if my-current-col
my-current-col
(current-column))))
(not (eq
(save-excursion (move-to-column my-current-col)
(re-search-backward "\t" (point-at-bol) t) (point))
(save-excursion (move-to-column (+ my-current-col 1))
(re-search-backward "\t" (point-at-bol) t) (point))))))
(defmacro measure-time (&rest body)
"Measure the time it takes to evaluate BODY."
`(let ((time (current-time)))
,#body
(message "%.06f" (float-time (time-since time)))))
The current implementation of overlays is algorithnically very poor. Many basic operations (such as move-overlay, inserting/deleting text, or even sometimes just moving point) have time O(N), where N is the number of overlays. Sometimes you can tremendously speed things up by jusdicious use of overlay-recenter.
We know how to fix those algorithmic problems, and I'd be very happy to help someone work on the implementation.
Since my guess in the comments was correct, posting an actual answer for more visibility in case someone has a similar problem:
delete-overlay may not be doing what you expect. From the manual:
— Function: delete-overlay overlay
This function deletes overlay. The overlay continues to exist as a Lisp object, and its property list is unchanged, but it ceases to be attached to the buffer it belonged to, and ceases to have any effect on display.
A deleted overlay is not permanently disconnected. You can give it a position in a buffer again by calling move-overlay.
Maybe you have a giant pile of disconnected overlays eating up memory or causing a lot of processing.
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)
I have been unable to come up with a method to test for a syntax condition without moving the cursor -- e.g., skip-syntax-forward and skip-chars-forward both move the cursor in order to return t or a positive value. How can I return t or nil without moving the cursor?
(defun lawlist-kill-word ()
"Mark word / symbol + whitespace to the right of the cursor, and kill same."
(interactive)
(let* (
(symbol-regexp "\\s.\\|\\s_")
(word-regexp "\\sw"))
(modify-syntax-entry ?' "_") ;; apostrophe = symbol constituent
(cond
((< 0 (skip-syntax-forward "_."))
(let ((end (point)))
(set-mark end)
(while (looking-back symbol-regexp)
(backward-char))
(let ((beg (point)))
(delete-region beg end)
(setq beg (point))
(cond
((skip-chars-forward " \t")
(setq end (point))
(set-mark end)
(delete-region beg end))))))
((< 0 (skip-syntax-forward "w"))
(let ((end (point)))
(set-mark end)
(while (looking-back word-regexp)
(backward-char))
(let ((beg (point)))
(delete-region beg end)
(setq beg (point))
(cond
((skip-chars-forward " \t")
(setq end (point))
(set-mark end)
(delete-region beg end))))))
(t
(let ((beg (point)))
(set-mark beg)
(skip-chars-forward " \t")
(let ((end (point)))
(delete-region beg end)))
(deactivate-mark)))
(modify-syntax-entry ?' "w") )) ;; apostrophe = word constituent
EDIT: lawlist-kill-word is a work in progress -- any updates to this function will be posted to a thread related to that issue -- i.e.,: Emacs: delete whitespaces or a word
As #Tobias said: wrap cursor movements in save-excursion. Save any values you want (e.g., of (point)) in variables and return them as needed.
E.g., if you want the position four lines ahead, do something like this:
(let ((posn (save-excursion (forward-line 4) (point))))
posn)
How can I configure emacs to work in the same way as other modern editors where pressing Alt+D or Alt+Backspace deletes either adjacent whitespaces or a single word? By default, emacs always deletes a word.
Trough some time of using Emacs I figured that even though I can alter the basic functionality, it usually doesn't pay off much in terms of efficiency. In fact, after I did it several times, I came to regret it and undid it. This is not true all of the time, some keybindings are really uncomfortable or rarely useful, but I don't think this is the case with how kill word works. In fact, I just now realized that: I did try the keybinding in Eclipse, but I've been using it with Emacs-style kebindings since forever...
Anyways, as I just said, before you are "fixing" that functionality, make sure it is really broken :) I never find myself needing the kind of function you describe, and maybe here's why:
M-SPC reduces the space between words to just one space. This is what I would've used if the point was between the words and I wanted to delete the extra space separating the words.
M-\ removes all horizontal space. This will join two words separated by space.
If what you are trying to achieve is some kind of "sparse" formatting, as in:
int foo = 42;
unsigned int bar = 43;
then there's M-xalign-regexp to do that.
I just never happen to have a) long consequent runs of whitepsace, unless it is the indentation, and in the case it is the indentation, TAB usually handles it better. b) even if there are long consequent runs of whitespace, I so rarely move the point by one character at a time, so it's hard to think of a situation where I'd find the point surrounded by several whitespaces. Things like Artist mode, or Dot diagrams come to mind, but it doesn't happen during code editing.
Finally, if you are trying to, well, let's say just edit an arbitrary text file and you want to add or remove horizontal space between words... Again, there's M-xalign-regexp to do that, or you could use commands that operate on rectangles, if those are several lines at the time. Well, Emacs will even recognize the ad hoc tabs and will try to align the text such as to match the last line before the point, when you hit TAB.
Finally, if for some reason I cannot fathom :) I really needed to do exactly what you describe, then I'd do it like so: kM-\BACKSPACE (it can be any other key instead of "k" - it is just right under your finger, so it's fast to type :) Or, if I'm lazy to think about it: M-SPCM-fM-bC-w - maybe sounds like a lot, but these are the commands you would be using all of the time anyway, so it doesn't hinder you in terms of speed.
(defvar movement-syntax-table
(let ((st (make-syntax-table)))
;; ` default = punctuation
;; ' default = punctuation
;; , default = punctuation
;; ; default = punctuation
(modify-syntax-entry ?{ "." st) ;; { = punctuation
(modify-syntax-entry ?} "." st) ;; } = punctuation
(modify-syntax-entry ?\" "." st) ;; " = punctuation
(modify-syntax-entry ?\\ "_" st) ;; \ = symbol
(modify-syntax-entry ?\$ "_" st) ;; $ = symbol
(modify-syntax-entry ?\% "_" st) ;; % = symbol
st)
"Syntax table used while executing custom movement functions.")
(defun delete-word-or-whitespace (&optional arg)
"http://stackoverflow.com/a/20456861/2112489"
(interactive "P")
(with-syntax-table movement-syntax-table
(let* (
beg
end
(word-regexp "\\sw")
(punctuation-regexp "\\s.")
(symbol-regexp "\\s_\\|\\s(\\|\\s)"))
(cond
;; Condition # 1
;; right of cursor = word or punctuation or symbol
((or
(save-excursion (< 0 (skip-syntax-forward "w")))
(save-excursion (< 0 (skip-syntax-forward ".")))
(save-excursion (< 0 (skip-syntax-forward "_()"))))
;; Condition #1 -- Step 1 of 2
(cond
;; right of cursor = word
((save-excursion (< 0 (skip-syntax-forward "w")))
(skip-syntax-forward "w")
(setq end (point))
(while (looking-back word-regexp)
(backward-char))
(setq beg (point))
(delete-region beg end))
;; right of cursor = punctuation
((save-excursion (< 0 (skip-syntax-forward ".")))
(skip-syntax-forward ".")
(setq end (point))
(while (looking-back punctuation-regexp)
(backward-char))
(setq beg (point))
(delete-region beg end))
;; right of cursor = symbol
((save-excursion (< 0 (skip-syntax-forward "_()")))
(skip-syntax-forward "_()")
(setq end (point))
(while (looking-back symbol-regexp)
(backward-char))
(setq beg (point))
(delete-region beg end)))
;; Condition #1 -- Step 2 of 2
(cond
;; right of cursor = whitespace
;; left of cursor = not word / not symbol / not punctuation = whitespace or bol
((and
(save-excursion (< 0 (skip-chars-forward "\s\t")))
(not (save-excursion (> 0 (skip-syntax-backward "w"))))
(not (save-excursion (> 0 (skip-syntax-backward "."))))
(not (save-excursion (> 0 (skip-syntax-backward "_()")))))
(setq beg (point))
(skip-chars-forward "\s\t")
(setq end (point))
(delete-region beg end))
;; right of cursor = whitespace
;; left of cursor = word or symbol or punctuation
((and
(save-excursion (< 0 (skip-chars-forward "\s\t")))
(or
(save-excursion (> 0 (skip-syntax-backward "w")))
(save-excursion (> 0 (skip-syntax-backward ".")))
(save-excursion (> 0 (skip-syntax-backward "_()")))))
(fixup-whitespace))))
;; Condition # 2
;; right of cursor = whitespace
;; left of cursor = bol | left of cursor = whitespace | right of cursor = whitespace + eol
((and
(save-excursion (< 0 (skip-chars-forward "\s\t")))
(or
(bolp)
(save-excursion (> 0 (skip-chars-backward "\s\t")))
(save-excursion (< 0 (skip-chars-forward "\s\t")) (eolp))))
(setq beg (point))
(skip-chars-forward "\s\t")
(setq end (point))
(delete-region beg end))
;; Condition # 3
;; right of cursor = whitespace or eol
;; left of cursor = word or symbol or punctuation
;; not bol + word or symbol or punctuation
;; not bol + whitespace + word or symbol or punctuation
((and
(or (save-excursion (< 0 (skip-chars-forward "\s\t"))) (eolp))
(or
(save-excursion (> 0 (skip-syntax-backward "w")))
(save-excursion (> 0 (skip-syntax-backward ".")))
(save-excursion (> 0 (skip-syntax-backward "_()"))))
(not (save-excursion (> 0 (skip-syntax-backward "w")) (bolp)))
(not (save-excursion (> 0 (skip-syntax-backward ".")) (bolp)))
(not (save-excursion (> 0 (skip-syntax-backward "_()")) (bolp)))
(not (save-excursion (and (> 0 (skip-syntax-backward "w")) (> 0 (skip-chars-backward "\s\t")) (bolp))))
(not (save-excursion (and (> 0 (skip-syntax-backward ".")) (> 0 (skip-chars-backward "\s\t")) (bolp))))
(not (save-excursion (and (> 0 (skip-syntax-backward "_()")) (> 0 (skip-chars-backward "\s\t")) (bolp)))))
(setq end (point))
(cond
((save-excursion (> 0 (skip-syntax-backward "w")))
(while (looking-back word-regexp)
(backward-char)))
((save-excursion (> 0 (skip-syntax-backward ".")))
(while (looking-back punctuation-regexp)
(backward-char)))
((save-excursion (> 0 (skip-syntax-backward "_()")))
(while (looking-back symbol-regexp)
(backward-char))))
(setq beg (point))
(when (save-excursion (> 0 (skip-chars-backward "\s\t")))
(skip-chars-backward "\s\t")
(setq beg (point)))
(delete-region beg end)
(skip-chars-forward "\s\t"))
;; Condition # 4
;; not bol = eol
;; left of cursor = bol + word or symbol or punctuation | bol + whitespace + word or symbol or punctuation
((and
(not (and (bolp) (eolp)))
(or
(save-excursion (> 0 (skip-syntax-backward "w")) (bolp))
(save-excursion (> 0 (skip-syntax-backward ".")) (bolp))
(save-excursion (> 0 (skip-syntax-backward "_()")) (bolp))
(save-excursion (and (> 0 (skip-syntax-backward "w")) (> 0 (skip-chars-backward "\s\t")) (bolp)))
(save-excursion (and (> 0 (skip-syntax-backward ".")) (> 0 (skip-chars-backward "\s\t")) (bolp)))
(save-excursion (and (> 0 (skip-syntax-backward "_()")) (> 0 (skip-chars-backward "\s\t")) (bolp)))))
(skip-chars-forward "\s\t")
(setq end (point))
(setq beg (point-at-bol))
(delete-region beg end))
;; Condition # 5
;; point = eol
;; not an empty line
;; whitespace to the left of eol
((and
(not (and (bolp) (eolp)))
(eolp)
(save-excursion (> 0 (skip-chars-backward "\s\t"))))
(setq end (point))
(skip-chars-backward "\s\t")
(setq beg (point))
(delete-region beg end))
;; Condition # 6
;; point = not eob
;; point = bolp and eolp
;; universal argument = C-u = '(4)
((and
(not (eobp))
(and (bolp) (eolp))
(equal arg '(4)))
(delete-forward-char 1))) )))
This has most likely been solved before, but instead of looking for code, we can write our own. So much fun!
This is how I would do it, hope it helps.
(defun kill-whitespace-or-word ()
(interactive)
(if (looking-at "[ \t\n]")
(let ((p (point)))
(re-search-forward "[^ \t\n]" nil :no-error)
(backward-char)
(kill-region p (point)))
(kill-word 1)))
Then bind it to a key:
(global-set-key (kbd "M-d") 'kill-whitespace-or-word)
If you are using a CC-Mode based buffer, you are probably looking for the Hungry Delete Mode minor mode.
Try C-c DEL and C-c DELETE in several places to get a feel for the difference.
If you like the way it works, you can toggle hungry deletion to work for the standard keys by doing M-x c-toggle-hungry-state or just rebind the hungry deletion functions to your preferred binding.
If you still think you need to piggyback one key to do forward kill word or whitespace, then you can do something similar to c-hungry-delete-forward, or just temporarily rebind c-delete-function and call it.
(defun c-hungry-delete-forward-word ()
"Delete the following word or all following whitespace
up to the next non-whitespace character.
See also \\[c-hungry-delete-backwards]."
(interactive)
(let ((c-delete-function (function kill-word)))
(c-hungry-delete-forward)))
Check out the Info page (ccmode) Hungry WS Deletion for more.