I do have an Emacs command which adds a separator line, in log files, when there is more than 3 seconds between timestamps found on 2 consecutive lines:
(defun log-mode-display-separator-line ()
"Separate blocks of log lines with an horizontal line."
(interactive)
(save-excursion
(goto-char (point-min))
(let (last ov)
(while (re-search-forward "[0-9]\\{4\\}-[01][1-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]" nil t)
(when last
(when (> (- (float-time (date-to-time (match-string 0)))
(float-time (date-to-time last)))
3)
(setq ov (make-overlay (line-beginning-position) (line-end-position)))
(overlay-put ov 'face 'log-mode-separator-face)))
(setq last (match-string 0))))))
The log-mode-separator-face uses the overline attribute to visually put an horizontal line between "semantic" blocks of lines.
I would like to get that horizontal line automatically inserted when the buffer is reverted (every 5 seconds), but the processing may become too big on huge log files, which are constantly updated. As of now, the whole file is scanned from the beginning each time we call that command...
How can I realize this, then? (With Emacs, no doubt it is...)
First of all, there's no guarantee that the buffer is reverted every 5 seconds. Since Emacs 24.4, autorevert uses file notifications, that means the buffer is reverted whenever the file changes on disk. If you want to suppress this, set auto-revert-use-notify to nil.
Further on, it depends how you want to revert your log file. I suppose you use auto-revert-tail-mode. This mode calls the hook functions contained in before-revert-hook and after-revert-hook. As a strategy, I would write a function for after-revert-hook, which underlines the last line in your buffer to be reverted. Something like this:
(defun my-auto-revert-tail-mode-display-separator-line ()
"Separate blocks of log lines with an horizontal line."
(save-excursion
(goto-char (point-max))
(while (and (= (line-beginning-position) (line-end-position))
(> (point) (point-min)))
(forward-line -1))
(let ((ov (make-overlay (line-beginning-position) (line-end-position))))
(overlay-put ov 'face 'underline))))
(add-hook 'after-revert-hook 'my-auto-revert-tail-mode-display-separator-line)
Related
Emacs (and all other text editors) by default show blank space below the bottom lines of a buffer. I want emacs to be able to also scroll above/show blank space like this above the top lines in a buffer as well so that the top lines can be viewed in the center of the screen for small files.
With guidance from Thomas's answer here I have created a minor mode for this which is now available on MELPA:
TopSpace - Recenter line 1 with scrollable upper margin/padding
I've started a small minor-mode to accomplish this. However, as first versions go, it's probably buggy, doesn't handle all edge cases (such as e.g., narrowing), and isn't particularly efficient.
Thus, I'd be happy to accept improvements: feel free to directly edit this answer if you can make this code better or to extend it.
(defvar vertical-center-num-buffers 0
"The number of buffers in which `vertical-center-mode' is activated.")
(define-minor-mode vertical-center-mode
"This minor mode displays the contents of a buffer vertically
centered with respect to the window height. This, of course, only
makes sense for buffers whose content is shorter than the window
height."
nil
" vc"
nil
;; is the mode being turned on or off?
(if vertical-center-mode
;; on
(progn
;; keep track of the number of lines in the buffer
(setq-local vertical-center-num-lines (count-lines (point-min) (point-max)))
;; use an overlay to display empty lines at the beginning of the buffer
(setq-local vertical-center-overlay (make-overlay (point-min) (point-max)))
;; initial call to the function that centers the buffer contents
(vertical-center--lines-changed 0)
;; react to changes to the buffer or the window
(add-hook 'kill-buffer-hook 'vertical-center--kill-buffer)
(add-hook 'window-size-change-functions 'vertical-center--window-size-changed)
(when (= vertical-center-num-buffers 0)
(add-hook 'before-change-functions 'vertical-center--before-change)
(add-hook 'after-change-functions 'vertical-center--after-change))
;; this is just to play nice and remove the above hook
;; functions when they're no longer needed. Let's keep our
;; fingers crossed that we'll always stay in sync.
(setq vertical-center-num-buffers (1+ vertical-center-num-buffers)))
;; off
;; delete/unset data structures when the mode is turned off
(delete-overlay vertical-center-overlay)
(makunbound 'vertical-center-num-lines)
(makunbound 'vertical-center-overlay)
(setq vertical-center-num-buffers (1- vertical-center-num-buffers))
;; remove hook functions when they're no longer needed
(when (= vertical-center-num-buffers 0)
(remove-hook 'kill-buffer-hook 'vertical-center--kill-buffer)
(remove-hook 'window-size-change-functions 'vertical-center--window-size-changed)
(remove-hook 'before-change-functions 'vertical-center--before-change)
(remove-hook 'after-change-functions 'vertical-center--after-change))))
;; handle killing of buffers
(defun vertical-center--kill-buffer ()
(when vertical-center-mode
(setq vertical-center-num-buffers (1- vertical-center-num-buffers))))
;; react to changes in the window height
(defun vertical-center--window-size-changed (arg)
(vertical-center--lines-changed 0))
;; handle deletions of buffer text
(defun vertical-center--before-change (beginning end)
(when (boundp 'vertical-center-num-lines)
(let ((num-lines 0))
(while (< beginning end)
(when (= (char-after beginning) ?\n)
(setq num-lines (1- num-lines)))
(setq beginning (1+ beginning)))
(when (< num-lines 0)
(vertical-center--lines-changed num-lines)))))
;; handle insertions into the buffer
(defun vertical-center--after-change (beginning end previous-length)
(when (boundp 'vertical-center-num-lines)
(let ((num-lines 0))
(while (< beginning end)
(when (= (char-after beginning) ?\n)
(setq num-lines (1+ num-lines)))
(setq beginning (1+ beginning)))
(when (> num-lines 0)
(vertical-center--lines-changed num-lines)))))
;; update the display when either the buffer content or the window
;; height has changed
(defun vertical-center--lines-changed (num-lines)
(setq vertical-center-num-lines (+ vertical-center-num-lines num-lines))
(let ((top-margin (/ (- (window-height) vertical-center-num-lines) 2)))
;; set the top margin
(overlay-put vertical-center-overlay 'before-string
(when (> top-margin 0)
(make-string top-margin ?\n)))))
Save the above code in a file named "vertical-center.el" in a directory of your choice, and then add the following lines to your .emacs file:
(setq load-path (append load-path "<directory>"))
(autoload 'vertical-center-mode "vertical-center")
Here, <directory> should be the path to the directory in which you saved the "vertical-center.el" file.
After restarting Emacs, you can now activate or deactivate the mode by typing M-x vertical-center-mode.
In the JetBrains products, there's a very handy key binding that lets you visit all the spots you made an edit. Hit the key once to go to the last edit (file and location), and keep hitting the key to go back to earlier edits. It's typically when editing that you want to be editing the same places over and over again, and if one has many buffers open, many of which are not edited, this is even more useful.
Emacs has a mark ring, but that's not quite the same thing.
On a related note, is there functionality in magit, the emacs git add-on, to jump to edits?
There is GotoLastChange which allows you to travel along the chain of undo locations. You can assign it to a key:
(global-set-key "\C-x\C-\\" 'goto-last-change)
There is GotoChg which allows you to travel back and forth the chain of undo locations. Sample init code snippet:
(require 'goto-chg)
(global-set-key [(control ?.)] 'goto-last-change)
(global-set-key [(control ?,)] 'goto-last-change-reverse)
(Just like the other alternatives, GotoLastChange and session.el, it can not jump between buffers)
Global, multi-buffer goto-last-change:
;;; record two different file's last change. cycle them
(defvar feng-last-change-pos1 nil)
(defvar feng-last-change-pos2 nil)
(defun feng-swap-last-changes ()
(when feng-last-change-pos2
(let ((tmp feng-last-change-pos2))
(setf feng-last-change-pos2 feng-last-change-pos1
feng-last-change-pos1 tmp))))
(defun feng-goto-last-change ()
(interactive)
(when feng-last-change-pos1
(let* ((buffer (find-file-noselect (car feng-last-change-pos1)))
(win (get-buffer-window buffer)))
(if win
(select-window win)
(switch-to-buffer-other-window buffer))
(goto-char (cdr feng-last-change-pos1))
(feng-swap-last-changes))))
(defun feng-buffer-change-hook (beg end len)
(let ((bfn (buffer-file-name))
(file (car feng-last-change-pos1)))
(when bfn
(if (or (not file) (equal bfn file)) ;; change the same file
(setq feng-last-change-pos1 (cons bfn end))
(progn (setq feng-last-change-pos2 (cons bfn end))
(feng-swap-last-changes))))))
(add-hook 'after-change-functions 'feng-buffer-change-hook)
;;; just quick to reach
(global-set-key (kbd "M-`") 'feng-goto-last-change)
from http://shenfeng.me/emacs-last-edit-location.html
This implementation works for the last two changes in any buffers. I imagine extending the length of its change-list beyond two wouldn't be too hard.
There is the command session-jump-to-last-change in session.el which allows you to travel along the chain of undo locations. Init code snippet:
(require 'session)
(setq session-jump-undo-threshold 80) ; default was 240
(global-set-key [(control ?.)] 'session-jump-to-last-change)
(Just like the other alternatives, GotoLastChange and GotoChg, it can not jump between buffers)
Single buffer
Tracking edits and go back to where they occurred depends on the type of them.
If your edit added something, you can go back to it with a rather simple:
(goto-char (car(cadr buffer-undo-list)))
If you deleted, something you can go back to it with:
(goto-char (abs (cdr(cadr buffer-undo-list))))
and you might like displaying what you deleted in the minibuffer:
(progn
(goto-char (abs (cdr(cadr buffer-undo-list))))
(message "DEL->: %s" (substring-no-properties (car(cadr buffer-undo-list)))))
Summing up:
(defun last-edit ()
"Go back to last add/delete edit"
(interactive)
(let* ((ubuf (cadr buffer-undo-list))
(beg (car ubuf))
(end (cdr ubuf)))
(cond
((integerp beg) (goto-char beg))
((stringp beg) (goto-char (abs end))
(message "DEL-> %s" (substring-no-properties beg)))
(t (message "No add/delete edit occurred")))))
Read C-h v buffer-undo-list and you might integrate this for less subtle edits, such as setting text properties (assuming you really need it).
Multi-buffer
I used the buffer-undo-list variable to carry out the tasks. There is a distinct list for each buffer and, as far as I know, there is no global undo-list. Most likely you know in which buffer you typed something and you want Emacs to bring to the edited spot. There is in this case a single global-mark-ring variable recording the sequence of buffers that you have been.
Successive uses of the command Meta-Xpop-global-mark,
or simply
Ctrl-X Ctrl-Space,
will bring you to earlier visited buffers (and mark positions). Once you get to the target buffer, you can trigger Meta-Xlast-edit (or the bound keys).
I use M-q for fill-paragraph, can I do the un-fill-paragraph in auto-fill-mode?
With org mode, I sometimes enter [[Very long HTML][Name with spaces]], and for the 'Name with spaces' the auto-fill mode break the whole line based on the inserted space, which makes it very ugly.
Is there a command something like un-fill-paragraph? Or, is there a way disable auto-fill-mode temporarily/locally?
Emacs does not record what was your line before calling fill-paragraph. So the only thing you can do is C-_ which runs the command undo. It can undo your fill-paragraph command but only if it is the preceding command call.
If you want to put a multi-line paragraph on one line you could do like this :
Select the region
C-M-% C-q C-j RET SPACE RET !
Xah Lee has updated his code since monotux's answer, and I refactored it somewhat for readability:
(defun my-toggle-fill-paragraph ()
;; Based on http://xahlee.org/emacs/modernization_fill-paragraph.html
"Fill or unfill the current paragraph, depending upon the current line length.
When there is a text selection, act on the region.
See `fill-paragraph' and `fill-region'."
(interactive)
;; We set a property 'currently-filled-p on this command's symbol
;; (i.e. on 'my-toggle-fill-paragraph), thus avoiding the need to
;; create a variable for remembering the current fill state.
(save-excursion
(let* ((deactivate-mark nil)
(line-length (- (line-end-position) (line-beginning-position)))
(currently-filled (if (eq last-command this-command)
(get this-command 'currently-filled-p)
(< line-length fill-column)))
(fill-column (if currently-filled
most-positive-fixnum
fill-column)))
(if (region-active-p)
(fill-region (region-beginning) (region-end))
(fill-paragraph))
(put this-command 'currently-filled-p (not currently-filled)))))
To remake a long line out of a paragraph in Org mode, I gave myself a new command. Here is the associated Emacs Lisp code:
(defun fp-unfill-paragraph (&optional justify region)
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(interactive)
(let ((fill-column 100000))
(fill-paragraph justify region)))
(global-set-key "\C-ceu" 'fp-unfill-paragraph)
Of course, you adjust the command keybinding as you see fit!
I use the following snippet to fill and un-fill paragraphs (using only M-q), it is really, really handy. I borrowed it from Xah Lee, but removed some comments and whitespace in order to make it fit in here. The link in the first comment goes to his original code.
;; http://xahlee.org/emacs/modernization_fill-paragraph.html
(defun compact-uncompact-block ()
"Remove or add line endings on the current block of text.
This is similar to a toggle for fill-paragraph and unfill-paragraph
When there is a text selection, act on the region.
When in text mode, a paragraph is considered a block. When in programing
language mode, the block defined by between empty lines.
Todo: The programing language behavior is currently not done.
Right now, the code uses fill* functions, so does not work or work well
in programing lang modes. A proper implementation to compact is replacing
newline chars by space when the newline char is not inside string.
"
(interactive)
(let (bds currentLineCharCount currentStateIsCompact
(bigFillColumnVal 4333999) (deactivate-mark nil))
(save-excursion
(setq currentLineCharCount
(progn
(setq bds (bounds-of-thing-at-point 'line))
(length (buffer-substring-no-properties (car bds) (cdr bds)))))
(setq currentStateIsCompact
(if (eq last-command this-command)
(get this-command 'stateIsCompact-p)
(if (> currentLineCharCount fill-column) t nil)))
(if (and transient-mark-mode mark-active)
(if currentStateIsCompact
(fill-region (region-beginning) (region-end))
(let ((fill-column bigFillColumnVal))
(fill-region (region-beginning) (region-end)))
)
(if currentStateIsCompact
(fill-paragraph nil)
(let ((fill-column bigFillColumnVal))
(fill-paragraph nil))))
(put this-command 'stateIsCompact-p
(if currentStateIsCompact
nil t)))))
(global-set-key (kbd "M-q") 'compact-uncompact-block)
I recently added Emacs (delete-trailing-whitespace) function to my 'before-save-hook for some programming modes, but I find it rather frustrating that it deletes whitespace from the line I am currently editing. Any suggestions as to how to fix this problem?
Since delete-trailing-whitespace respects narrowing, one solution is to narrow the buffer to the portion before the current line and call it, then narrow to the portion after the current line and call it again:
(defun delete-trailing-whitespace-except-current-line ()
(interactive)
(let ((begin (line-beginning-position))
(end (line-end-position)))
(save-excursion
(when (< (point-min) begin)
(save-restriction
(narrow-to-region (point-min) (1- begin))
(delete-trailing-whitespace)))
(when (> (point-max) end)
(save-restriction
(narrow-to-region (1+ end) (point-max))
(delete-trailing-whitespace))))))
Put this function on your before-save-hook instead of delete-trailing-whitespace.
This wrapper for delete-trailing-whitespace can be used to do what you want:
(defun delete-trailing-whitespace-except-current-line ()
"do delete-trailing-whitespace, except preserve whitespace of current line"
(interactive)
(let ((current-line (buffer-substring (line-beginning-position) (line-end-position)))
(backward (- (line-end-position) (point))))
(delete-trailing-whitespace)
(when (not (string-equal (buffer-substring (line-beginning-position) (line-end-position))
current-line))
(delete-region (line-beginning-position) (line-end-position))
(insert current-line)
(backward-char backward))))
I ran into the same problem, and found out that ws-butler perfectly solves it.
There is a simple sample config code:
;; autoload ws-butler on file open
(add-hook 'find-file-hook #'ws-butler-global-mode)
(setq require-final-newline t)
I simply have a wrapper to make two calls to `delete-trailing-whitespace':
(defun modi/delete-trailing-whitespace-buffer ()
"Delete trailing whitespace in the whole buffer, except on the current line.
The current line exception is because we do want to remove any whitespace
on the current line on saving the file (`before-save-hook') while we are
in-between typing something.
Do not do anything if `do-not-delete-trailing-whitespace' is non-nil."
(interactive)
(when (not (bound-and-true-p do-not-delete-trailing-whitespace))
(delete-trailing-whitespace (point-min) (line-beginning-position))
(delete-trailing-whitespace (line-end-position) (point-max))))
(add-hook 'before-save-hook #'modi/delete-trailing-whitespace-buffer)
My problem is I am opening a buffer using (set-buffer (find-tag-noselect (current-word))) and then I try to copy some text out of that buffer. The text that I get back has only the properties (fontified nil). find-tag-noselect automatically opens the buffer found in the TAGS file but it seems it does not run the font lock mode over it. When I manually switch to this buffer after it has been opened and then run the function again when it copies the text it has all the correct text properties attached. So what do I need to do to have this buffer completely initialized so that the correct syntax highlighting will be copied in?
(defvar newline-string "
")
(defun get-initial-indent-regexp-python()
"Gets the initial amount of spaces for the function we are looking at, does not account for tabs"
(concat "^" (get-current-indent-string) (concat "[^ #" newline-string "]")))
(defun get-end-of-function-python(spaces-regex)
"Gets the point at the end of a python block"
(save-excursion
(forward-line 1)
(while (and (not (looking-at spaces-regex)) (equal (forward-line 1) 0)))
(point)))
(defun get-point-at-end-of-function ()
"This might be better served checking the major mode."
(setq extension (file-name-extension (buffer-file-name)))
(if (equal extension "py")
(get-end-of-function-python (get-initial-indent-regexp-python))))
(defun inline-function ()
"Must change to overlays, be able to toggle visibility"
(interactive)
(let (text indent-string)
; clean all overlays without attached buffer
(save-excursion
(set-buffer (find-tag-noselect (current-word)))
(setq text (buffer-substring (point) (get-point-at-end-of-function))))
(setq text (concat newline-string text))
(save-excursion
(move-end-of-line nil)
(let (overlay)
(setq overlay (make-overlay (point) (+ (point) 1) (current-buffer)))
(overlay-put overlay 'display text)
(setq inline-func-overlays (cons overlay inline-func-overlays))))))
What's happening is that font-lock is done on-the-fly, so only the displayed parts of the buffer get "fontified". If you want/need to overrule this optimization, you need different functions depending on the circumstance (depending on how font-lock happens to be configured). We should add a new font-lock-ensure-fontified function for that, but in the mean time, you can take ps-print-.el as an example:
(defun ps-print-ensure-fontified (start end)
(cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode))
(jit-lock-fontify-now start end))
((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode))
(lazy-lock-fontify-region start end))))
I'm not exactly sure what you're trying to do, but set-buffer does not display the buffer, so its effect ends when the current command terminates. It's generally useful only for temporary buffer switches inside a function and I guess this is the reason it doesn't run font-lock on the buffer. When you manually go to the buffer you're probably using a different function - switch-to-buffer.
Try explicitly calling 'font-lock-fontify-buffer'.