C Comment in Emacs - Linux Kernel Style v2 - emacs

I received an answer about C Comment in Emacs - Linux Kernel Style that works great but
when emacs comments (comment-dwim) it's padding the second * long_function_name_vari and last */ lines with spaces (before the comment) not tabs like I have configured it. How to avoid that?
And how easily to make a comment using this style?
/* void main()
* {
* int i;
* int b;
* printf("format string");
* }
*/

Customizable variable comment-style is defined in newcomment.el saying
...
(extra-line t nil t t
"One comment for all lines, end on a line by itself")
...
which should deliver the wanted result IIUC.
Current implementation however is two-extra-lines, the opening newline undocumented so far. Please file a feature request resp. docu-bug report.

Well, after seek the newcomment.el I could understand how to tweak that behavior.
(defun my-c-comment-dwim (tabify delete-trailing)
(interactive)
(let (beg end)
(if (region-active-p)
(progn
(setq beg (region-beginning)
end (region-end))
(if (comment-only-p beg end)
(uncomment-region beg end)
(progn
(comment-region beg end)
(when (equal comment-style 'extra-line)
(save-excursion
(goto-char end)
(forward-line 2)
(setq end (line-end-position))))
(when tabify
(tabify beg end))
(when delete-trailing
(delete-trailing-whitespace beg end)))))
(comment-indent))))
(global-set-key [remap comment-dwim] (lambda ()
(interactive)
(my-c-comment-dwim t t)))

Related

Emacs: select quoted string as one operation

In programming we ofter have a task of selecting text between quotes. Suppose, we have the following PHP code:
lwt_shared_save_conditions_to_session($conditions, "bundles_listing"■);
The cursor position is shown with black square. And we want to select and copy the text "bundles_listing" into the clipboard. I created the following function:
(defun select-quoted-text ()
(interactive)
(search-backward "\"")
(forward-char 1)
(cua-set-mark)
(backward-char 1)
(search-backward "\"")
(kill-ring-save (region-beginning) (region-end))
)
It will select the text between quotes.
How can I do the following:
1.Fold this code into 1 function call:
(forward-char 1)
(cua-set-mark)
(backward-char 1)
Select text both between single ' and double " quotes.
Try this:
(defun copy-quoted ()
"Copy current string into kill-ring.
The point can be anywhere in the string."
(interactive)
(let ((beg (or (nth 8 (syntax-ppss))
(and (memq (char-after (point))
'(?\" ?\'))
(point))))
end)
(when beg
(setq end
(save-excursion
(goto-char beg)
(forward-sexp)
(point)))
(kill-ring-save beg end))))
Here's how I'd do it interactively (rather than defining a function for it):
C-SPC C-M-b M-w
That runs the following commands:
set-mark-command
backward-sexp
kill-ring-save

Emacs insert centered comment block

I would like to create a macro for emacs that will insert a latex comment block with some centerd text like:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Comment 1 %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Comment 2 Commenttext 3 %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Is this possible in emacs-lisp?
Emacs comes with the command comment-box for this purpose. It produces centered comment boxes, although the width of the box varies depending on the content. E.g., with the region set around the following line:
This is a comment
when you call M-x comment-box the text is transformed to:
;;;;;;;;;;;;;;;;;;;;;;;
;; This is a comment ;;
;;;;;;;;;;;;;;;;;;;;;;;
I use a modifed version that places the comment box around the current line if the region isn't active, and then steps out of the comment afterwards. It also temporarily reduces the fill-column, so the comment box is not wider than your longest line:
(defun ty-box-comment (beg end &optional arg)
(interactive "*r\np")
(when (not (region-active-p))
(setq beg (point-at-bol))
(setq end (point-at-eol)))
(let ((fill-column (- fill-column 6)))
(fill-region beg end))
(comment-box beg end arg)
(ty-move-point-forward-out-of-comment))
(defun ty-point-is-in-comment-p ()
"t if point is in comment or at the beginning of a commented line, otherwise nil"
(or (nth 4 (syntax-ppss))
(looking-at "^\\s *\\s<")))
(defun ty-move-point-forward-out-of-comment ()
"Move point forward until it's no longer in a comment"
(while (ty-point-is-in-comment-p)
(forward-char)))
Here's a yasnippet that you can use:
# -*- mode: snippet -*-
# name: huge_comment
# key: hc
# --
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%${1:$(repeat-char (- 33 (/ (length yas-text) 2)) " ")}$1${1:$(repeat-char (- 74 (length yas-text) (- 33 (/ (length yas-text) 2))) " ")}%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$0
How to use it: type hc, call yas-expand and start typing the text. It will re-center itself
automatically.
This snippet will work from latex-mode or text-mode. I've noticed however a bug that
messes up the cursor position if you're using AUCTeX. In that case, you can momentarily switch
to text-mode.
The question was whether it is possible in emacs-lisp. Yes it is. There are several ways to do it.
I will show one way where you can also comment several lines of text.
Maybe, in the first line there is the title of the part of text and in the second one there is the author of this part.
A better way would be to advice LaTeX-indent-line function. This way you could edit the comment text and re-indent. When I find time I will show you also this variant.
Usage: Write your comment as clear text. Mark text as region with the mouse and then run the following command.
(defun LaTeX-centered-comment (b e)
"Convert region into centered comment."
(interactive "r")
(let* ((n (count-lines b e)))
(goto-char b)
(beginning-of-line)
(insert-char ?% fill-column)
(insert ?\n)
(setq b (point))
(center-line n)
(goto-char b)
(loop for i from 1 upto n do
(replace-region (point) (+ (point) 3) "%%%")
(end-of-line)
(insert-char ?\ (max 0 (- fill-column (- (point) (line-beginning-position)) 3)))
(insert "%%%")
(forward-line))
(insert-char ?% fill-column)
(insert ?\n)
))

Sorting lines with multiline expressions under Emacs

I'm looking for a variant of M-x sort-lines that can handle multiline expressions properly. For instance:
this is the first line
this is the second lien
this is the (third
line
spanning multiple lines because of parens)
Any ideas?
Here is a similar question solved in a similar way
(defun end-of-chunk ()
"forward line or to ends of mid-expression."
(interactive)
(goto-char (point-at-eol))
(let ((limit (point-at-bol))
temp
expr-beg)
(while (and (setq temp (nth 1 (syntax-ppss)))
(<= limit temp))
(goto-char temp)
(setq expr-beg (point)))
(when expr-beg
(goto-char expr-beg)
(forward-sexp))))
(defun sort-lines-as-exprs (reverse beg end)
"sort lines, or whole expression if line ends mid-expression."
(interactive "P\nr")
(save-excursion
(save-restriction
(narrow-to-region beg end)
(goto-char (point-min))
(sort-subr reverse
'forward-line
'end-of-chunk))))

Emacs: how to write a defun which acts on region, but acts on point if there's no region?

I write a simple defun for a region, and I want to apply it even if there's no region – i.e. call it with no selection at all. I thought I could do something like the following:
(defun region-study (strt end)
(interactive "r")
(if (= strt end)
(progn ....) ;; then
(progn ....))) ;; else
But it doesn't work. As it turns out, when you call (interactive "r") with no region it doesn't just set boundaries to be equal. Try this:
(defun region-study (strt end)
(interactive "r")
(message "strt=%d; end=%d" strt end))
So my question is that: "how to write a defun which acts on region, but acts on point if there's no region?"
Edit:
So I wanted to put selection in brackets or just to insert brackets and (backward-char 1). Here's a solution:
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(progn
(setq pP (point))
(setq strt (region-beginning))
(setq end (region-end))
(setq meat (buffer-substring-no-properties strt end))
(setq news (concat lft meat rit))
(delete-region strt end)
(goto-char strt)
(insert news)
(if (= pP strt)
(goto-char strt) ; then
(goto-char (+ end 1)))) ; else
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
(defun bk-put-in-braces ()
(interactive)
(put-in-lft-rit "(" ")"))
(defun bk-put-in-curly-braces ()
(interactive)
(put-in-lft-rit "{" "}"))
(defun bk-put-in-quotes ()
(interactive)
(put-in-lft-rit "'" "'"))
(defun bk-put-in-double-quotes ()
(interactive)
(put-in-lft-rit "\"" "\""))
(defun bk-put-in-square-brackes ()
(interactive)
(put-in-lft-rit "[" "]"))
And then you bind in .emacs:
(global-set-key (kbd "C-<f9>") 'bk-put-in-square-brackes)
(global-set-key (kbd "<f9>") 'bk-put-in-curly-braces)
(global-set-key (kbd "S-<f7>") 'bk-put-in-quotes)
(global-set-key (kbd "S-<f8>") 'bk-put-in-double-quotes)
(global-set-key (kbd "S-<f9>") 'bk-put-in-braces)
That's it! Should be working in all modes.
Edit2:
#phils
Thanks. You are definetely right. One thing though - my code had an additional feature of leaving the point at the beginning or end of the region - depending on where it was in the selection. Here's Your code with this feature added:
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(let ((strt (region-beginning))
(end (region-end))
(pP (point)))
(save-excursion
(goto-char end)
(insert rit)
(goto-char strt)
(insert lft))
(if (= pP strt)
(goto-char strt) ; then
(goto-char (+ end 1)))) ; else
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
A few notes on your solution...
It's good practice to avoid unnecessary global-scope setqs. Use (let) instead to define a temporary scope for your variables.
You are doing a lot more work than required. Instead of copying the region, concatenating that copy and the delimiters into a 'news' variable, deleting the region, and then inserting 'news', all you need to do is insert the delimiter characters at the beginning and end of the region.
(In general, if you try to "think like an editor" when writing elisp, and focus on manipulating buffers rather than variables, you'll generally wind up with more efficient code.)
save-excursion is very useful (along with several other save- and with- forms).
 
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(let ((strt (region-beginning))
(end (region-end)))
(save-excursion
(goto-char end)
(insert rit)
(goto-char strt)
(insert lft)))
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
use-region-p should return t if your function should act on the region instead of at a point.
You may like to use the function region-or-word-at-point defined in thingatpt+.el

a custom comment box on emacs

What would an Emacs macro look like which turns the following line:
# abc def
into:
# +-------------+
# | abc def |
# +-------------+
? The macro need not be general at all: It can hard code the box specs (i.e. 3 spaces before and after the comment, the frame characters (|, +, - ), and assume that the comment is a one-liner. It should, however, use whatever comment character is set for the current mode, and get the box length correct.
I'd also appreciate if you knew of an existing package which does this.
Thanks!
This does what I think you want:
(defun box-comment-region (beg end)
"do some fancy commenting"
(interactive "r")
(save-restriction
(narrow-to-region beg end)
(comment-region beg end -1) ; first, uncomment
(string-rectangle (point-min)
(progn (goto-char (point-max)) (line-beginning-position))
" | ")
(goto-char (point-min))
(let ((max-len 0))
(while (< (point) (point-max))
(end-of-line)
(setq max-len (max max-len (current-column)))
(forward-line 1))
(previous-line)
(end-of-line)
(insert (make-string (- max-len (current-column)) ?\ ))
(goto-char (point-min))
(end-of-line)
(insert (make-string (- max-len (current-column)) ?\ ))
(end-of-line)
(let ((top (point)))
(goto-char (point-max))
(previous-line)
(end-of-line)
(string-rectangle top (point) " | "))
(let ((line-seg (concat " +" (make-string (- max-len 2) ?-) "+ \n")))
(goto-char (point-max))
(insert line-seg)
(goto-char (point-min))
(insert line-seg)))
(comment-region (point-min) (point-max))))
newcomment has a function called comment-box, which produces a box comment consisting of the comment characters, i.e.:
###########
# abc def #
###########
or
/***********/
/* abc def */
/***********/
depending on the mode. The only configurability it has is the number of characters to use for the box; for example in Lisp modes you end up with:
;;;;;;;;;;;;;
;; abc def ;;
;;;;;;;;;;;;;
The comment-region-default function should give you some idea of how to do comments. newcomment's comment styles aren't sufficiently flexible to implement what you want, so I think it'd be easiest to simply draw the box then add a regular (single or multiline, in languages where there is difference) comment to the region using the existing newcomment machinery.
There is a feature called picture-mode, which might do something like that.
M-x picture-mode
rebox2 is the most comprehensive emacs box drawing extension.
The function
M-x comment-box
available as of Emacs 24.4 does this using point and mark as one would expect.