Emacs narrow-by-regex - emacs

There are functions like M-x narrow-to-line and M-x narrow-to-page. Which routines can help me achieve functionality of non-existing M-x narrow-by-regex?
Thanks.

this seems to work. will prompt the user for the begin and end regex. (not tested very thoroughly!):
(defun narrow-to-regex ()
"narrow the buffer visibility to the section between two regexes the user provides"
(interactive)
(let* ((beginRegex (read-regexp "begin pattern"))
(endRegex (read-regexp "end pattern"))
(beg)
(end))
(goto-char (point-min)) ;; go to the start of the buffer
(if (re-search-forward beginRegex nil t nil)
(setq beg (- (point) (length beginRegex))))
(if (re-search-forward endRegex nil t nil)
(setq end (point)))
(if (and beg end (> end beg))
(narrow-to-region beg end)
(message "did not find both instances of the regex, %s %s, no narrow" beg end))))
you will have too install it by putting it into a buffer (scratch etc) and going CTRL+X followed by CTRL+E

Related

What's wrong with this elisp function?

I write a elisp function to copy the current line if no region has be selected, but it does not work on emacs 24.5. When I hit the "M-w" keystrokes , there comes a message "Mark set" in the minibuffer. Did I miss something?
(defun copy-region-or-current-line (beg end)
"copy current if no region selected, copy the region otherwise"
(interactive "r")
(let ((cur-pos (point)))
(if (region-active-p)
(kill-ring-save beg end)
(progn
(kill-whole-line)
(yank)
(goto-char cur-pos)))))
(global-set-key (kbd "M-w") 'copy-region-or-current-line)
Your function works: You're calling yank and that command sets the mark; hence the message.
That's a side effect you undoubtedly don't want, though, and the kill+yank sequence isn't necessary.
You already know about kill-ring-save, so just use that with (line-beginning-position) and (line-end-position).
FYI, on account of the optional REGION argument to kill-ring-save, you could rewrite this as:
(defun copy-region-or-current-line ()
"Copy the active region or the current line to the kill ring."
(interactive)
(if (region-active-p)
(kill-ring-save nil nil t)
(kill-ring-save (line-beginning-position) (line-end-position))))

Command to uncomment multiple lines without selecting them

Is there a command in emacs to uncomment an entire comment block without having to mark it first?
For instance, let's say the point is inside a comment in the following code:
(setq doing-this t)
;; (progn |<--This is the point
;; (er/expand-region 1)
;; (uncomment-region (region-beginning) (region-end)))
I would like a command that turns that into this:
(setq doing-this t)
(progn
(er/expand-region 1)
(uncomment-region (region-beginning) (region-end)))
It's fairly easy to write a command that (un)comments a single line, but I've yet to find one that uncomments as many lines as possible. Is there one available?
A quick reply --- code could be improved and made more useful. You might want to extend it to other kinds of comments, besides ;;;, for instance.
(defun uncomment-these-lines ()
(interactive)
(let ((opoint (point))
beg end)
(save-excursion
(forward-line 0)
(while (looking-at "^;;; ") (forward-line -1))
(unless (= opoint (point))
(forward-line 1)
(setq beg (point)))
(goto-char opoint)
(forward-line 0)
(while (looking-at "^;;; ") (forward-line 1))
(unless (= opoint (point))
(setq end (point)))
(when (and beg end)
(comment-region beg end '(4))))))
The key is comment-region. FWIW, I bind comment-region to C-x C-;. Just use it with C-u to uncomment.
You can use Emacs' comment handling functions to make a generalised version of Drew's command.
(defun uncomment-current ()
(interactive)
(save-excursion
(goto-char (point-at-eol))
(goto-char (nth 8 (syntax-ppss)))
(uncomment-region
(progn
(forward-comment -10000)
(point))
(progn
(forward-comment 10000)
(point)))))

Mark region and insert prefix

I recently switched from vi to emacs, and now I'm porting my most important macros to emacs. What I need most is the ability to prefix a marked region of text with a string, including header and footer:
Original:
line 1
line 2
line 3
line 4
After marking the 2nd and 3rd line, I want emacs to ask me for a number, say 002, and do the following, ideally remembering my choice:
line 1
*#002# Start:
*$line 2
*$line 3
*#002# End.
line 4
So far, I have managed to insert start and end tags with the following code:
(defun comment-region (start end)
"Insert COBOL comments."
(interactive "r")
(save-excursion
(goto-char end) (insert "*#xxx# End.\n")
(goto-char start) (insert "*#xxx# Start:\n")
))
However, I can't seem to find out how to prefix all lines in the region with *$ and how to make emacs ask me for a string.
Any ideas?
I've taken to solving this type of problems by dynamically generating a
snippet with yasnippet lately.
Here is the code:
(require 'yasnippet)
(defun cobol-comment-region (beg end)
"comment a region as cobol (lines 2,3 commented)
line 1
*#002# Start:
*$line 2
*$line 3
*#002# End.
line 4
"
(interactive "*r")
(setq beg (progn
(goto-char beg)
(point-at-bol 1))
end (progn
(goto-char end)
(if (bolp)
(point)
(forward-line 1)
(if (bolp)
(point)
(insert "\n")
(point)))))
(let* ((str (replace-regexp-in-string
"^" "*$" (buffer-substring-no-properties beg (1- end))))
(template (concat "*#${1:002}# Start:\n"
str
"\n*#$1# End.\n"))
(yas-indent-line 'fixed))
(delete-region beg end)
(yas-expand-snippet template)))
video included, what???
Here is a video of it in action:
Your best bet is to use cobol-mode instead of writing ad hoc functions yourself.
The file header contains detailed instructions on how to use it.
Then just use C-x C which runs the command comment-region, which comments the region according to the major mode (in your case, cobol).
This is a better approach, but its a little awkward at the end...
(defun comment-region (start end prefix)
"Insert COBOL comments."
(interactive "r\nsPrefix: ")
(save-excursion
(narrow-to-region start end)
(goto-char (point-min))
(insert "*#" prefix " #Start.\n")
(while (not (eobp))
(insert "*$")
(forward-line))
(insert "*#" prefix " #End.\n")
(widen)))

How to copy a region or a whole buffer to another buffer in Emacs without affecting the kill ring?

I'd like to copy the region to another (temporary) buffer in Emacs, but if there's no (acive) region, I'd like to copy the whole current buffer. What I did is as follows:
(defun do-something-with-region-or-buffer ()
(interactive)
(save-excursion
(let ((begin (point-min)) (end (point-max)))
(when (region-active-p)
(setq begin (region-beginning))
(setq end (region-end)))
(copy-region-as-kill begin end)
(with-temp-buffer
(switch-to-buffer (current-buffer))
(rename-buffer "*My Temp Buffer*")
(delete-other-windows)
(yank)
(do-something-with-current-buffer)))))
However, I have a strong feeling that this is suboptimal, since I'm messing around with the kill ring. How to do it without affecting it? (Bonus question: is my way of doing things with the region or the whole buffer if there's no active region a good one?)
That's how I would do it:
(defun aak/dswrob ()
(interactive)
(let* ((regionp (region-active-p))
(beg (and regionp (region-beginning)))
(end (and regionp (region-end)))
(buf (current-buffer)))
(with-temp-buffer
(switch-to-buffer (current-buffer) nil t)
(rename-buffer "*My Temp Buffer*" t)
(insert-buffer-substring buf beg end)
(read-key-sequence "Keys?"))))
It's up to you to decide if you want insert-buffer-substring or
insert-buffer-substring-no-properties, but there is no need to use
kill rings.
Also it's rather strange to do something interactively within
with-temp-buffer: are you going to run a kind of modal loop there,
or is it just displaying some progress?
As of doing things with the region or the whole buffer (NB: modulo
narrowing), it's not quite unusual (see replace-string and
friends).

emacs delete-trailing-whitespace except current line

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)