Emacs C-mode indent problem with Doxygen style comment - emacs

I am having a problem with doxygen style multi-line comments with emacs indent feature in c-mode. According to doxygen manual (http://www.doxygen.nl/manual/docblocks.html) the form below is accepted.
/********************************************//**
* ... text
***********************************************/
I am trying to use this format in emacs but when I tab in on the line '* ... text' the * ends up below the /** at the end of the first line like so:
/********************************************//**
* ... text
***********************************************/
Any suggestions on how to fix this? Still learning all the in-and-outs of emacs.

The reason it is indenting as such is that (by default) multi-line comments are lined up with the start of the comment on the previous line. In this case, the start of the containing comment is in column 47.
Now, how to fix it. Here's how I figured out how to fix it, the solution is at the end.
First, there's the cc-mode manual, specifically the section on customizing indentation. A useful key is C-c C-s which tells you which syntax is being used for indentation. In this case it is ((c 61)) - the c is the important part for now.
To customize it interactively, you can type C-c C-o (when the point is on the line whose indentation you want to fix). You'll be prompted for which syntax entry you want to customize (defaults to c in this case b/c that's the current syntax), then you'll be prompted for what you want to change the syntax entry to (default is c-lineup-C-comments).
Now we can look at that function to see how we might customize it to meet your needs. M-x find-function c-lineup-C-comments.
That's where it gets more difficult. You can customize the way cc-mode handles comment indentation, but what it looks like you want it to do (in this case) is to recognize that the c-comment you're in is immediately preceded by another c-comment, and that comment is the one you want to align indentation to.
How do you do that? The easiest way I can think of is to advise 'c-lineup-C-comments to recognize this special case and change the value of its first argument to be what you want. My limited testing shows this works for your example:
(defadvice c-lineup-C-comments (before c-lineup-C-comments-handle-doxygen activate)
(let ((langelm (ad-get-arg 0)))
(save-excursion
(save-match-data
(goto-char (1+ (c-langelem-pos langelem)))
(if (progn
(beginning-of-line)
;; only when the langelm is of form (c . something)
;; and we're at a doxygen comment line
(and (eq 'c (car langelm))
(looking-at "^\\(\\s-*\\)/\\*+//\\*\\*$")))
;; set the goal position to what we want
(ad-set-arg 0 (cons 'c (match-end 1))))))))
The end result of this advice should be that the argument passed into c-lineup-C-comments should be transformed from (c . 61) to (c . 17) (or something like that), essentially fooling the routine into lining up with the comment at the beginning of the line, and not the comment which you're currently modifying.

Which version of emacs are you using? My emacs 22 has this problem, but on another machine with emacs 23 does not. This is probalby due to some "electric" indentation. Try M-x describe-key RET RET and also M-x describe-mode to get a nice place to start searching for clues. There is also http://doxymacs.sourceforge.net/ but I have not tesed it personally.

Related

Wrong indentation of comments in Emacs

In many languages, the line comment starts with a single symbol, for example # in Python and R.
I find that in Emacs, when writing such line comments, I have to repeat the comment symbol twice to make the correct indentation.
See the following example:
(setq x-select-enable-clipboard t)
;using a single comment symbol indents wrongly
;; repeating the comment symbol indents fine
(setq-default c-basic-offset 4)
With a single ; at the beginning of the line cannot get the correct indentation. How to get the correct setting? Thanks!
EDIT:
I found the solution myself. In ESS's document:
Comments are also handled specially by ESS, using an idea borrowed
from the Emacs-Lisp indentation style. By default, comments beginning
with ‘###’ are aligned to the beginning of the line. Comments
beginning with ‘##’ are aligned to the current level of indentation
for the block containing the comment. Finally, comments beginning with
‘#’ are aligned to a column on the right (the 40th column by default,
but this value is controlled by the variable comment-column,) or just
after the expression on the line containing the comment if it extends
beyond the indentation column. You turn off the default behavior by
adding the line (setq ess-fancy-comments nil) to your .emacs file.
So I put this in my .emacs:
(setq ess-fancy-comments nil) ; this is for ESS
I think for Python mode, it has a similar variable.
Your example use Emacs Lisp, in this language the standard convention is that a single ; is indented to the right, whereas two ;; is indented like code would be indented at that point. I strongly recommend that you stick to this convention, otherwise your code would stand out as being different. And three ;;; is indented to the left. Four ;;;; is left indented, and used for major sections. (See https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html)
For Ruby, comments always indent as code, as far as I know.
The major mode should take care of this properly. If not, consider filing an enhancement request or bug report to the maintainers. Of course, "properly" might be in the eye of the beholder. You can try to make your preferences known, however. And check whether the major-mode code might already have user options for this.
Beyond that, the function that is the value of variable comment-indent-function governs this. Normally, this is set by the major mode. You can set it to any function you want (e.g. on the mode hook, so that your definition overrides the one provided by the major-mode code).
It accepts no arguments, and it returns the column you want the comment to be indented to.
Here is code that indents a comment to column 0, for example:
(defun foo () (setq comment-indent-function (lambda () 0)))
(add-hook 'SOME-MODE-HOOK 'foo 'APPEND)
For Emacs-Lisp mode, for example, you would use (add-hook 'emacs-lisp-mode-hook 'foo 'APPEND).

Emacs: Matching parenthesis when cursor is ON closing parenthesis

{It has been asked before: Emacs: highlight matching paren when cursor is on it, not after it but none of the answers are satisfactory}
I am using mic-paren with following .emacs settings (although the problem exists with all similar emacs packages, so it seems to be some kind of default emacs behavior)
(paren-activate)
(setq paren-match-face 'highlight)
(setq paren-sexp-mode t)
which highlight the all the text between two parenthesis. It works well when the cursor is ON opening parenthesis but from the other side, I have to put my cursor AFTER the closing parenthesis. This results in strange behavior when used with slime (which requires the cursor to be put ON the closing parenthesis to display general usage information and such). Is there any way to change this behavior and make emacs match parenthesis when the cursor is ON closing parenthesis?
EDIT: Minor grammar fix
Don't know about mic-paren, but using the built-in show-paren-mode, you can get what you want in Emacs-24.4 with:
(defun my-show-paren-any (orig-fun)
(or (funcall orig-fun)
(if (looking-at "\\s)")
(save-excursion (forward-char 1) (funcall orig-fun)))))
(add-function :around show-paren-data-function #'my-show-paren-any)
The following works for `mic-paren'. But, it has some afterglow;-). The opening delimiter is highlighted if the cursor is on the closing delimiter or just behind it.
(defadvice mic-paren-highlight (around cursorOnClosing activate)
"Dirty hack to highlight sexps with closing delim below cursor"
(if (eq (char-syntax (following-char)) ?\) )
(let ((paren-priority 'close))
(save-excursion
(forward-char)
ad-do-it))
ad-do-it))
Naturally, to make this work you need to install mic-paren correctly. Just follow the installation guide in mic-paren.el cited here:
Installation:
Place this file in a directory in your 'load-path and byte-compile
it. You can surely ignore the warnings.
Put the following in your .emacs file:
(GNU Emacs supports mic-paren only within a window-system but XEmacs
supports mic-paren also without X)
(when (or (featurep 'xemacs) window-system)
(require 'mic-paren) ; loading
(paren-activate) ; activating
; set here any of the customizable variables of mic-paren:
; ...
)
Restart your Emacs. mic-paren is now installed and activated!
To list the possible customizations enter C-h f paren-activate' or
go to the customization groupmic-paren-matching'.
EDITS:
follow Stefan's hint about (featurep 'xemacs)
What's important to remember here is that Emacs's point is between two characters, not on a character. For the show-paren facility to trigger, the point must be immediately outside a paren, whether opening or closing. The observed dissymmetry is caused by the block cursor being placed, arbitrarily, on the character after (rather than before) the point.
If this disturbs you, then a workaround would be to use a line cursor rather than a block cursor.
show-paren-mode is being enhanced for the next but one release, such that it will trigger also with the point immediately inside a paren.
The following advice does what you want. When the block cursor is "on" the opening parenthesis, the closing parenthesis is highlighted. When the block cursor is "on" the closing parenthesis, the opening parenthesis is highlighted.
(advice-add show-paren-data-function
:around
(lambda (orig-fun)
(cond ((looking-at "\\s(")
(funcall orig-fun))
((looking-at "\\s)")
(save-excursion (forward-char 1) (funcall orig-fun))))))
Refer to my answer on the Emacs Stack Exchange site: https://emacs.stackexchange.com/a/63458/17507. In that answer, I provide a full explanation of the code above, and also a suggested variant.

emacs function to uncomment regardless of mode

Main goal: making a smart "uncomment" function suitable for any mode.
(defun uncomment-mode-specific ()
(interactive)
(if (region-active-p)
(comment-region (region-beginning) (region-end) -1) ; so far so good
(if (= ";" (line-beginning-position)) ; here is the problem
(message "successful")
(message "unsuccessful"))
))
In the if statement, I would like to check for the value of the first character of the line, and if it equals the variable comment-start (which would return ";" in emacs lisp), goto beginning-of-line and delete the character. Ideas?
EDIT: More clarification as requested in a comment below follows. I would like a function to do:
1) If a region is selected, remove the comments (here that uncomment-region or comment-dwim would work as pointed out by Patrick)
ELSE:
2) If the first character of the line at point is a comment character, remove the comment character.
ELSE:
3) Search current line for comment (excluding \% or \;, mode dependent), move up to comment and kill the line starting with the comment sign.
I could not see how you would want this to work differently. It could then be bound to one key to simply remove comments, depending on the mode, using comment-start to identify the comment character.
I'm posting this as an alternative answer, since what you are trying to do is partly done already with the comment-dwim command. From the docs (you can find it using C-h f comment-dwim)
comment-dwim is an interactive compiled Lisp function in
`newcomment.el'.
It is bound to M-;.
(comment-dwim ARG)
Call the comment command you want (Do What I Mean).
If the region is active and transient-mark-mode is on, call
comment-region (unless it only consists of comments, in which
case it calls uncomment-region).
Else, if the current line is empty, call comment-insert-comment-function
if it is defined, otherwise insert a comment and indent it.
Else if a prefix ARG is specified, call comment-kill.
Else, call comment-indent.
You can configure comment-style to change the way regions are commented.
So in order to use it, simply select a region with C-SPC (set-mark-command) and move the caret to the other point and run comment-dwim.

How to make emacs behave closer to the regular editors?

I'm using Emacs 23.1.1 on Ubuntu with Emacs starter kit. I primarily work in the lua-mode.
Is there a way to stop Emacs being so smart about indentation? I'm used to the dumb editors, and press all the required keys manually.
I want to use two spaces per indent, tabs-to-spaces.
When I press RETURN, the new line indentation must match the previous line.
When I press TAB on the leading whitespace, the line contents must be indented by one indentation unit.
When I press TAB on the beginning of empty line, the cursor must move one indentation unit to the right.
Oh, and I'd like to get soft word wrap on 80th column and trim-trailing-spaces on save as well.
Update:
(Would put this in a comment, but it needs formatting)
If I use Thomas's solution, auto-indent on RETURN is "fixed", but TAB still indents weirdly:
local run = function(...)
x
"x" marks the spot where cursor appears after I type the first line and hit RETURN, TAB.
Emacs has a concept of modes, which means that depending on what type of file you're editing it provides special functionality that is useful for that file. Every buffer has one major mode associated and optionally a number of minor modes.
Indentation is one of the things that is typically mode-dependent. That is, you may have to configure indentation separately for every major-mode, because otherwise when you load a new file, its associated major mode may override your indentation settings. It's possible though to write a function that configures indentation and set up Emacs in a way that the function is invoked whenever a new major-mode is started.
In order to realize the settings you want, you'll need to run a few lines of elisp code. (Unfortunately your description of what should happen when you hit TAB leaves out some details, I've implemented the simplest version I could think of below -- if it's not what you want, that can be changed, of course.)
Put the following code in the file named .emacs in your home directory (~):
(setq-default indent-tabs-mode nil) ; use spaces for indentation
(defvar my-indentation-width 2
"The number of spaces I prefer for line indentation.")
(defun my-enter ()
"Inserts a newline character then indents the new line just
like the previous line"
(interactive)
(newline)
(indent-relative-maybe))
(defun my-indent ()
"When point is on leading white-space of a non-empty line, the
line is indented `my-indentation-width' spaces. If point is at
the beginning of an empty line, inserts `my-indentation-width'
spaces."
(interactive)
(insert (make-string my-indentation-width ? )))
(defun my-indentation-setup ()
"Binds RETURN to the function `my-enter' and TAB to call
`my-indent'"
(local-set-key "\r" 'my-enter)
(setq indent-line-function 'my-indent))
(defun delete-trailing-whitespace-and-blank-lines ()
"Deletes all whitespace at the end of a buffer (or, rather, a
buffer's accessible portion, see `Narrowing'), including blank
lines."
(interactive)
(let ((point (point)))
(delete-trailing-whitespace)
(goto-char (point-max))
(delete-blank-lines)
(goto-char (min point (point-max)))))
;; make sure trailing whitespace is removed every time a buffer is saved.
(add-hook 'before-save-hook 'delete-trailing-whitespace-and-blank-lines)
;; globally install my indentation setup
(global-set-key "\r" 'my-enter)
(setq indent-line-function 'my-indent)
;; also override key setting of major-modes, if any
(add-hook 'after-change-major-mode-hook 'my-indentation-setup)
This works for me in Emacs 23, although I may have missed some edge cases. However, these changes are so fundamental that I predict you will run into incompatibilities sooner or later with some major-modes that expect indentation to work they set it up. If you really want to get into Emacs it's worthwhile adapting the habits you inherited from other editors to the way Emacs does things.
For soft word-wrap there is a minor-mode called "longlines" which you can download from here: http://www.emacswiki.org/cgi-bin/emacs/download/longlines.el I haven't used it so I can't tell you how well it works.
Fixing TAB and RETURN:
(global-set-key "\t" 'self-insert-command)
(global-set-key "\r" 'newline-and-indent)
Fill column (haven't tried): say ESC x customize-var, enter fill-column, set to 80.

get and set line content in emacs buffer programmatically

I would like to translate the following function from vim script to emacs elisp (I use it to set the email recipients when writing emails).
My question is mainly how to get and set line contents in emacs, because with quick googling I could not find this out (probably I just did not know the right terms to google for, "getline" and "setline" in any case did show any results).
function! G_set_to()
let address = system('my-address-script') "shell command to choose addresses
let line = getline (2)
if strlen(line) == 4
call setline(2, line . address)
else
call setline(2, line . "; " . address)
endif
endfunction
Sorry if the answer is obvious, I am am completely new to emacs and don't even know how to use its in-built help system.
Cheers
Arian
Give this a shot, obviously customizing the variable G-address-script to suit your needs.
(require 'sendmail)
(defvar G-address-script "echo hi#google.com")
(defun G-set-to ()
"execute script in G-address-script and populate the To: line with the results"
(interactive)
(save-excursion
(mail-to)
(unless (= (current-column) 4)
(insert "; "))
(insert (shell-command-to-string G-address-script))
(when (looking-at "^$") ; when shell command has extra newline, delete it
(delete-backward-char 1))))
As far as using the help, there's a reasonable introduction to Emacs lisp here. But the quick intro is:
C-h i (that's control-h then i to see the info pages, there is one for Emacs and one for Emacs Lisp.
M-x apropos searches for terms
C-h f gives you help on a function
C-h v gives you help on a variable
In the *scratch* buffer, C-j will evaluate the expression right before the point (cursor)
M-x edebug-defun when the point is in a emacs lisp function will turn the debugger on, and the next time a function is run you'll step through it (M-x eval-defun in the function will turn the debugger off)
M-x eldoc-mode will turn on automatic documentation for emacs lisp functions and variables as you type them, read more here.
I took Trey's code and changed a few things and now it seems to work:
(defvar G-address-script "goobook_dmenu_with_cache")
(defun G-set-to ()
"execute script in G-address-script and populate the To: line with the results"
(interactive)
(save-excursion
(goto-line 2)
(re-search-forward "$")
(unless (= (current-column) 4)
(insert "; "))
(insert (shell-command-to-string G-address-script))))
Some remaining questions:
The bit where Trey's code checks if the string returned from G-address-script is empty doesn't work at the moment, what do I have to change?
Is there really no function to get the content of a specified line as a string?
Is there a better/more elegant way to do this? The vim script solution looks so much simpler, surely I am missing something.
Anyway, I'll mark this as solved in a day or so if there are no more answers as Trey solution basically does what I wanted. Thank you Trey!