in my .emacs configuration, i have the following :
(defun fold-long-comment-lines ()
"This functions allows us to fold long comment lines
automatically in programming modes. Quite handy."
(auto-fill-mode 1)
(set (make-local-variable 'fill-no-break-predicate)
(lambda ()
(not (eq (get-text-property (point) 'face)
'font-lock-comment-face)))))
the above gets invoked as part of "c-mode-common-hook" and correctly provides folding long comment lines automatically.
however, the above thing works indiscriminately, whether i am using a single line comment e.g. describing struct fields, or multi-line comments describing some complicated piece of code.
so, the basic question is, how can i get automatic folding of long comment lines only if it is a multi-line comment ?
thanks
anupam
edit-1: multi-line-comment explanation
when i say "multi-line-comment", it basically means comments like this:
/*
* this following piece of code does something totally funky with client
* state, but it is ok.
*/
code follows
a correspondingly, a single line comment would be something like this
struct foo {
char buf_state : 3; // client protocol state
char buf_value : 5; // some value
}
the above elisp code, dutifully folds both these comment lines. i would like to fold only the former, not the latter.
If you only want it to affect auto-fill-mode and not general filling (e.g. not when you hit M-q), then your code can be replaced by setting comment-auto-fill-only-comments. As for having it apply only to "multi-line comments", I think you're first going to have to explain what is the difference between. Are you saying that you only want to auto-fill when the comment already spans more than one line, or is there some other characteristic of a comment that can let Emacs figure out that a comment that currently only spans a single line can be spread over multiple lines.
You could try something like:
(set (make-local-variable 'fill-no-break-predicate)
(lambda ()
(let ((ppss (syntax-ppss)))
(or (null (nth 4 ppss)) ;; Not inside a comment.
(save-excursion
(goto-char (nth 8 ppss))
(skip-chars-backward " \t")
(not (bolp))))))) ;; Comment doesn't start at indentation.
Related
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).
I'd like to quickly generate text in a buffer that looks like this:
(fact "This is some text which will hang out
only on this part of the screen, ideally
automatically flowing to the correct
margins as I type."
(+ 1 1) => 2
;; more Clojure tests...
)
I have an Elisp keybinding which quickly spits out a starting template and puts my cursor in the right place:
(global-set-key "\C-of" (lambda ()
(interactive)
(insert "(fact \"\"\n\n )")
(backward-char 6)))
Now, when I am typing in the string portion ("This is some text..."), it'd be awesome if I could get Emacs to automatically flow text to the "correct" margins. Is there some way Emacs can be made to adjust margins and wraparound behavior based on where you're typing? At least, the first time you are typing there?
Barring that, for a given selection of text, how can I do the equivalent of fill-region, but with the desired left and right margins? Currently fill-region deletes all space between fact and "This is...., and left-justifies the rest.
There might be a simpler way that I'm overlooking now, but I would just do this:
Configure the text block in a temporary buffer, by doing this there:
a. Set fill-column to the width of the text block that you want.
b. Put the text at the beginning of the line, i.e., not indented.
c. Fill the text.
d. Use indent-rigidly to indent the text to the column you want, except for the first line.
Insert into your target buffer (fact followed by the indentation you want for the first line of the text block. Then insert the contents of the temporary buffer. Then insert whatever other text/code you need.
IOW, I would separate filling the text block from indenting it.
The following seems to work for the moment for my alternative (weaker) case:
;; Set up Midje fact with mark inserted at beginning of comment text
;; (refill as needed in appropriate columns, using C-oF).
(global-set-key "\C-of" (lambda ()
(interactive)
(insert "(fact \"\"\n\n )")
(backward-char 6)
(set-mark (point))))
;; Perform the refill operation to properly reformat the text string
;; in a Midje fact, started with C-of:
(global-set-key "\C-oF" (lambda ()
(interactive)
(set-left-margin (mark) (point) 37)
(fill-region (mark) (point))))
I expect I'll have to tweak this as I get experience using it, but it is pretty close. Still, it'd be nice to figure out how to have this happen automatically, while I'm typing inside the string.
I don't even know the proper terminology for this lisp syntax, so I don't know if the words I'm using to ask the question, make sense. But the question makes sense, I'm sure.
So let me just show you. cc-mode (cc-fonts.el) has things called "matchers" which are bits of code that run to decide how to fontify a region of code. That sounds simple enough, but the matcher code is in a form I don't completely understand, with backticks and comma-atsign and just comma and so on, and furthermore it is embedded in a c-lang-defcost, which itself is a macro. I don't know what to call all that, but I want to run edebug on that code.
Look:
(c-lang-defconst c-basic-matchers-after
"Font lock matchers for various things that should be fontified after
generic casts and declarations are fontified. Used on level 2 and
higher."
t `(;; Fontify the identifiers inside enum lists. (The enum type
;; name is handled by `c-simple-decl-matchers' or
;; `c-complex-decl-matchers' below.
,#(when (c-lang-const c-brace-id-list-kwds)
`((,(c-make-font-lock-search-function
(concat
"\\<\\("
(c-make-keywords-re nil (c-lang-const c-brace-id-list-kwds))
"\\)\\>"
;; Disallow various common punctuation chars that can't come
;; before the '{' of the enum list, to avoid searching too far.
"[^\]\[{}();,/#=]*"
"{")
'((c-font-lock-declarators limit t nil)
(save-match-data
(goto-char (match-end 0))
(c-put-char-property (1- (point)) 'c-type
'c-decl-id-start)
(c-forward-syntactic-ws))
(goto-char (match-end 0)))))))
I am reading up on lisp syntax to figure out what those things are and what to call them, but aside from that, how can I run edebug on the code that follows the comment that reads ;; Fontify the identifiers inside enum lists. ?
I know how to run edebug on a defun - just invoke edebug-defun within the function's definition, and off I go. Is there a corresponding thing I need to do to edebug the cc-mode matcher code forms?
What does def-edebug-spec do, and would I use it here? If so, how?
According to (elisp)Top > Debugging > Edebug > Edebug and Macros you have to tell Edebug how to debug a macro by defining it with debug statements or by using def-edebug-spec. This tells it what parameters should be evaluated and which shouldn't. So it can be done. In fact it looks as if c-lang-defconst already been fitted for edebug. Here is the definition in case you were interested:
(def-edebug-spec c-lang-defconst
(&define name [&optional stringp] [&rest sexp def-form]))
However, if you just want to see what the body evaluates to, then the way to do that is to use something like macro-expand-last-sexp below to see the result. Position your cursor after the sexp you want expanded (as you would for C-x C-e) and run M-x macro-expand-last-sexp RET. This will show you what it gets expanded to. You may run into troubles if you try to expand something like ,(....) so you may have to copy that sexp somewhere else and delete the , or ,#.
(defun macro-expand-last-sexp (p)
"Macro expand the previous sexp. With a prefix argument
insert the result into the current buffer and pretty print it."
(interactive "P")
(let*
((sexp (preceding-sexp))
(expanded (macroexpand sexp)))
(cond ((eq sexp expanded)
(message "No changes were found when macro expanding"))
(p
(insert (format "%S" expanded))
(save-excursion
(backward-sexp)
(indent-pp-sexp 1)
(indent-pp-sexp)))
(t
(message "%S" expanded)))))
I guess it depends on exactly what you are trying to do.
Use macroexpand or macroexpand-all to turn it into macro-free code and debug as usual?
Backticks &co may be best illustrated by an example:
(let ((a 1)
(b (list 2 3)))
`(a ,a ,b ,#b))
-> (a 1 (2 3) 2 3)
A backtick (or backquote`) is similar to a quote(') in that it prevents evaluation, except its effect can be selectively undone with a comma(,); and ,# is like ,, except that its argument, which must be a list, is spliced into the resulting list.
This question is related to another one, Emacs :TODO indicator at left side. I recently came across a minor mode I like a lot called FixmeMode. It supports auto highlighting of TODO marks, and navigating between them. However, I think it makes more sense to recognize the "TODO" strings only in comments, rather than polluting the whole file. Is it possible?
Check out the library fic-mode.el, it has been verified in C++ and Emacs-Lisp.
It was written specifically to answer this question.
The installation is like any standard package:
(require 'fic-mode)
(add-hook 'c++-mode-hook 'turn-on-fic-mode)
Though Wei Hu did ask for an easy way to add it to multiple modes, so here goes:
(defun add-something-to-mode-hooks (mode-list something)
"helper function to add a callback to multiple hooks"
(dolist (mode mode-list)
(add-hook (intern (concat (symbol-name mode) "-mode-hook")) something)))
(add-something-to-mode-hooks '(c++ tcl emacs-lisp) 'turn-on-fic-mode)
It's possible but quite a bit trickier. Fixme mode uses font-lock to do its highlighting, so it works on an as-you-type basis to highlight the keywords. Font-lock hooks in at a very low level, basically running after every change is made to the buffer's contents. It is highly optimized, though, which allows it to appear instantaneous on modern computers.
The TODO indicator in the left fringe is static. Execute the function and all current TODO's are highlighted; change the buffer (adding or removing TODO's) does not change the fringe indicator; that's only changed when the function runs again.
Your approach would have to get into syntax tables, determining first when you're in a comment and then looking for the keywords. The tricky part comes in doing this interactively (i.e. as you type). You should be able to hook into the font-lock constructs to do this, but the function you provide to search for the comment syntax table and then for the keywords better be very efficient, as it will be run each and every time a buffer changes (though it will only run on the changed region, I think). You would want to stuff all of this in font-lock-syntactic-keywords rather than font-lock-keywords because the syntactic-keyword pass happens before the syntactic pass (which happens before the keyword pass), and you need to set TODO inside comments before comments themselves are set.
Sorry it's not a full working-code answer.....
Maybe this will help: there's a fn c-in-literal in
cc-mode, and a similar csharp-in-literal in csharp mode. The
return value is c if in a C-style comment, c++ if in a C++
style comment. You could add that to the code at
Emacs :TODO indicator at left side
to get what you want.
(defun annotate-todo ()
"put fringe marker on TODO: lines in the curent buffer"
(interactive)
(let (lit)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "TODO:" nil t)
(progn
(setq lit (c-in-literal)) ;; or csharp-in-literal
(if (or (eq lit 'c) (eq lit 'c++))
(let ((overlay (make-overlay (- (point) 5) (point))))
(overlay-put overlay 'before-string
(propertize "A"
'display
'(left-fringe ;; right
horizontal-bar
better-fringes-important-bitmap))))))))))
https://github.com/tarsius/hl-todo seems to do exactly what you want. I just tried it and love it.
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.