suppose I have a line:
This is a title
I want to highlight this line like this:
This is a title
===============
Any ideas if such functionality is already available in emacs?
Heh, I wanted that a long time ago so I wrote one. I've no idea if it's already packaged and out there in another form. Here's my version:
(defun underline-previous-line ()
"Insert enough dashes on the current line to \"underline\" the line above the point.
Underline the line above the current point,
but don't underline any whitespace at the beginning of the line.
Delete the current line when made of whitespace and/or dashes."
(interactive)
(let ((p (point)))
(forward-line -1)
(if (looking-at "^\\([ \t]*\\).+$")
(progn
(goto-char p)
(beginning-of-line)
(let ((spaces (if (match-end 1) (- (match-end 1) (match-beginning 1)) 0)))
(insert (concat
(make-string spaces ?\ )
(make-string (- (match-end 0) (match-beginning 0) spaces) ?\-)
(save-match-data
(if (looking-at "^[- ]*-[- ]*$") ; need one dash
(delete-region (match-beginning 0) (match-end 0))
"\n")))))))
(goto-char p)
;; yes, next-line is what we want for intuitive cursor placement
;; a save-excursion makes life a little more difficult b/c the point
;; moves around oldly b/c of the insert
(next-line 1)))
Just change the '-' to '=' and it'll do what you want.
WRT to readability not written the shortest way:
(defun underline ()
(interactive "*")
(let* ((len (- (line-end-position) (line-beginning-position)))
(strg (make-string len ?\=)))
(end-of-line)
(insert "\n")
(insert strg)))
Install markdown-mode. It does this with the function markdown-insert-title (bound to C-c C-t t).
Edit: I don't have the newest version 2.0 yet, but if I understand the release notes correctly, markdown-insert-title has been renamed to markdown-insert-header-setext-1 and its keybinding has been changed to C-c C-t !.
Related
I am trying to write a simple Elisp Emacs function that takes a paragraph (point indicated by [X]) and expands it into a series of bullet points with each bullet containing a sentence.
much more useful, especially with huge windows. In my experience, it slows down redraw a little bit, but it’s worth it.There are two ways to enable it: the first is with M-x visual-line-mode[X] (for those with real menus, apparently Options->Line Wrapping in this Buffer->Word Wrap), which will give you a minor mode “wrap” in the mode line.
and returns
+ much more useful, especially with huge windows.
+ In my experience, it slows down redraw a little bit, but it’s worth it.
+ There are two ways to enable it: the first is with M-x visual-line-mode[X] (for those with real menus, apparently Options->Line Wrapping in this Buffer->Word Wrap), which will give you a minor mode “wrap” in the mode line.
Here is what I have so far:
(defun jds/explode ()
"explode paragraph, more documentation needed"
(interactive)
(save-excursion
(let ((bop (copy-marker (progn (backward-paragraph) (point))))
(eop (copy-marker (progn (forward-paragraph) (point)))))
(goto-char bop)
(back-to-indentation) ;; goto first non-whitespace character
(if (re-search-forward "^[:blank:]*[+-x] " nil t) nil (insert "+ "))
(while (< (point) eop)
(forward-sentence)
(forward-whitespace 1)
(unless (>= (point) eop)
(org-meta-return)))))))))
But this just seems to run but not do anything. I think the problem may be that the backward-paragraph function may not be putting the point on the first non-black character (the m in much). But that said, my Elisp is very weak and I am struggling to figure out the problem.
Turns out this works - just needed to add +/-1 to point
(defun jds/explode ()
"explode paragraph, more documentation needed"
(interactive)
(save-excursion
(let ((bop (copy-marker (progn (backward-paragraph) (+ (point) 1))))
(eop (copy-marker (progn (forward-paragraph) (- (point) 1)))))
(goto-char bop)
(if (looking-at-p "^[:blank:]*[+-x] ") nil (insert "+ "))
(while (< (point) eop)
(forward-sentence)
(forward-whitespace 1)
(unless (>= (point) eop)
(org-meta-return))))))
(defun explode-paragraph ()
"Explode paragraph. If run twice it changes list marker."
(interactive)
(save-mark-and-excursion
(let ((bop (copy-marker (progn (backward-paragraph) (1+ (point)))))
(eop (copy-marker (progn (forward-paragraph) (point)))))
(goto-char bop)
(if (looking-at-p "^\s*[\-\+x] ") nil (insert "+ "))
(while (< (point) eop)
(forward-sentence)
(forward-whitespace 1)
(unless (>= (point) eop)
(org-meta-return))))))
I extended your implementation to work for my use-case. I changed a couple of things:
I changed [:blank:] to \s because it was matching on lines under a header (if anyone knows why this is I'd be happy to be educated).
I used the (+1 (point) notation and removed the -1 from the eop, as I didn't find it necessary.
I escaped the special symbols inside [...] because -x was matching lines starting with 'A'.
In my own version of this function I have the first line (summary sentence) a level up from the other sentences, but I think this should cover most cases for its original intended purpose.
I've got to comply with a C style guide that says the following about multi-line comments:
Multi-line comments shall follow the following rules:
Comments starting with // shall not be used for multi-line comments.
The opening /* shall be alone on a line, or, if it is a doxygen multi-line comment, shall appear at the beginning of a line.
The closing */ shall be alone on a line.
The closing */ shall be aligned with the opening /*.
The body of the multi-line comment shall be indented one tab stop relative to the /* and */.
Example:
/*
Comment.
More text.
*/
However, emacs doesn't seem to be able to treat the last comment line differently and indents it like this:
/*
Comment.
More text.
*/
Does anyone know how to convince emacs to treat the last comment line differently similar to the way closing braces in statements (e.g., defun-close, block-close) are handled differently?
EDIT: This is not a direct answer to your question, but should solve your requirements.
This may not be the prettiest solution, but it's working well.
If you change the offset for the syntactic symbol c (issuing M-x c-set-offsetRET, with the cursor laying on a multiline comment) to c-lineup-C-comments you get something similar to what you want, but the comment text is indented by 1 character relative to the opening *.
Here is a modified version of c-lineup-C-comments that indents the comment text by c-basic-offset spaces.
(defun my-c-lineup-C-comments (langelem)
"Line up C block comment continuation lines.
Various heuristics are used to handle many of the common comment
styles. Some examples:
/* /** /* /* text /* /**
* text * text text text ** text ** text
*/ */ */ */ */ */
/*********************************************************************
* text
********************************************************************/
/*********************************************************************
Free form text comments:
In comments with a long delimiter line at the start, the indentation
is kept unchanged for lines that start with an empty comment line
prefix. The delimiter line is whatever matches the
`comment-start-skip' regexp.
*********************************************************************/
The variable `c-comment-prefix-regexp' is used to recognize the
comment line prefix, e.g. the `*' that usually starts every line
inside a comment.
Works with: The `c' syntactic symbol."
(save-excursion
(let* ((here (point))
(prefixlen (progn (back-to-indentation)
(if (looking-at c-current-comment-prefix)
(- (match-end 0) (point))
0)))
(starterlen
;; Get the length of the comment starter, not including
;; the first '/'. We check if the comment prefix matched
;; on the current line matches the starter or if it
;; matches comment-start-skip, and choose whichever is
;; longest.
(max (save-excursion
(goto-char (1+ (c-langelem-pos langelem)))
(if (and (match-string 0)
(looking-at (regexp-quote (match-string 0))))
(- (match-end 0) (match-beginning 0))
0))
(save-excursion
(goto-char (c-langelem-pos langelem))
(looking-at comment-start-skip)
(- (or (match-end 1)
(save-excursion
(goto-char (match-end 0))
(skip-chars-backward " \t")
(point)))
(point)
1)))))
(if (and (> starterlen 10) (zerop prefixlen))
;; The comment has a long starter and the line doesn't have
;; a nonempty comment prefix. Treat it as free form text
;; and don't change the indentation.
(vector (current-column))
;; Go back to the previous non-blank line, if any.
(while
(progn
(forward-line -1)
(back-to-indentation)
(and (> (point) (c-langelem-pos langelem))
(looking-at "[ \t]*$"))))
;; Is the starting line the first continuation line with content?
(if (>= (c-langelem-pos langelem) (point))
(if (zerop prefixlen)
;; No nonempty comment prefix. Align after comment
;; starter.
(progn
(looking-at comment-start-skip)
(goto-char (match-end 0))
;; The following should not be necessary, since
;; comment-start-skip should match everything (i.e.
;; typically whitespace) that leads up to the text.
;;(if (looking-at "\\([ \t]+\\).+$")
;; ;; Align with the text that hangs after the
;; ;; comment starter.
;; (goto-char (match-end 1)))
;;
;; EDITED HERE: this line was
;; (vector (current column))
(vector (+ (- c-basic-offset 1 starterlen) (current-column))))
;; How long is the comment starter? if greater than the
;; length of the comment prefix, align left. if less
;; than or equal, align right. this should also pick up
;; Javadoc style comments.
(if (> starterlen prefixlen)
(progn
(goto-char (c-langelem-pos langelem))
(vector (+ 1 (current-column) )))
(goto-char (+ (c-langelem-pos langelem) starterlen 1))
(vector (- (current-column) prefixlen))))
;; We didn't start on the first non-blank continuation line. If the
;; previous line has a nonempty comment prefix, align with it.
;; Otherwise, align with the previous nonempty line, but align the
;; comment ender with the starter.
(when (or (not (looking-at c-current-comment-prefix))
(eq (match-beginning 0) (match-end 0)))
(goto-char here)
(back-to-indentation)
(if (looking-at (concat "\\(" c-current-comment-prefix "\\)\\*/"))
(goto-char (c-langelem-pos langelem))
(while (and (zerop (forward-line -1))
(looking-at "^[ \t]*$")))
(back-to-indentation)
(if (< (point) (c-langelem-pos langelem))
;; Align with the comment starter rather than
;; with the code before it.
(goto-char (c-langelem-pos langelem)))))
(vector (current-column)))))))
You can use it issuing M-x c-set-offsetRET, with the cursor laying on a multiline comment.
EDIT
Following your comment, there are at least 2 ways to make it the default:
Add a hook to c-mode-hook:
(defun my-c-mode-hook ()
(c-set-offset 'c 'my-c-lineup-C-comments))
(add-hook 'c-mode-hook 'my-c-mode-hook)
Add a new C style using c-add-style and setting it as default customizing c-default-style:
(c-add-style "mystyle"
'("awk" ;; or whatever style you are currently using!
(c-offsets-alist
(c . my-c-lineup-C-comments)
)
)
)
To customize c-default-style, type
M-xcustomize-variableRETc-default-styleRET
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)))))
I wrote a snippet to copy previous line to point,if I repeat the command,it copy more previous line. It's here:
(defun my-copy-line (num)
"copy lines"
(interactive "p")
(save-excursion
(move-end-of-line 1)
(push-mark)
(move-beginning-of-line num)
(kill-ring-save (point) (mark))))
(defvar copy-line-num 1)
(defun my-copy-line-here (num)
"copy line ahead here"
(interactive "p")
(if (eq this-command last-command)
(setq copy-line-num (+ copy-line-num num)) ;count num lines up
(setq copy-line-default 1))
(save-excursion
(save-excursion ;make current line blank
(move-beginning-of-line 1)
(push-mark)
(move-end-of-line 1)
(kill-region (point) (mark))) ;不用kill-line,以免删除空白行
(push-mark)
(previous-line copy-line-num)
(my-copy-line 1)
(exchange-point-and-mark)
(yank))
(setq this-command 'my-copy-line-here))
I intended to yank previous line to override current line.If I repeat my-copy-line-here,I'll yank the 2th previous line,this is accomplished by the test (if (eq this-command last-command).But it failed ,Because every time after executing my-copy-line-here,it sets the last-command to yank,instead my-copy-line-here.I just can't figure out what's going on.I need your help.
`M-y (yank-pop) works similarly, pasting previous copied lines on repeated calls. Checking its sources, I see two differences with yours:
; explicit check for yank
(if (not (eq last-command 'yank))
; setting this command
(setq this-command 'yank)
Perhaps one or both of these together can be useful. Set this-command after calling yank maybe?
What is the easiest way to move selected region or line (if there is no selection) up or down in emacs? I'm looking for the same functionality as is in eclipse (bounded to M-up, M-down).
Update: Install the move-text package from Marmalade or MELPA to get the following code.
Here's what I use, which works on both regions and individual lines:
(defun move-text-internal (arg)
(cond
((and mark-active transient-mark-mode)
(if (> (point) (mark))
(exchange-point-and-mark))
(let ((column (current-column))
(text (delete-and-extract-region (point) (mark))))
(forward-line arg)
(move-to-column column t)
(set-mark (point))
(insert text)
(exchange-point-and-mark)
(setq deactivate-mark nil)))
(t
(let ((column (current-column)))
(beginning-of-line)
(when (or (> arg 0) (not (bobp)))
(forward-line)
(when (or (< arg 0) (not (eobp)))
(transpose-lines arg)
(when (and (eval-when-compile
'(and (>= emacs-major-version 24)
(>= emacs-minor-version 3)))
(< arg 0))
(forward-line -1)))
(forward-line -1))
(move-to-column column t)))))
(defun move-text-down (arg)
"Move region (transient-mark-mode active) or current line
arg lines down."
(interactive "*p")
(move-text-internal arg))
(defun move-text-up (arg)
"Move region (transient-mark-mode active) or current line
arg lines up."
(interactive "*p")
(move-text-internal (- arg)))
(global-set-key [M-S-up] 'move-text-up)
(global-set-key [M-S-down] 'move-text-down)
A line can be moved using transpose-lines bound to C-x C-t. I don't know about regions, though.
I found this elisp snippet that does what you want, except you need to change the bindings.
(defun move-text-internal (arg)
(cond
((and mark-active transient-mark-mode)
(if (> (point) (mark))
(exchange-point-and-mark))
(let ((column (current-column))
(text (delete-and-extract-region (point) (mark))))
(forward-line arg)
(move-to-column column t)
(set-mark (point))
(insert text)
(exchange-point-and-mark)
(setq deactivate-mark nil)))
(t
(beginning-of-line)
(when (or (> arg 0) (not (bobp)))
(forward-line)
(when (or (< arg 0) (not (eobp)))
(transpose-lines arg))
(forward-line -1)))))
(defun move-text-down (arg)
"Move region (transient-mark-mode active) or current line
arg lines down."
(interactive "*p")
(move-text-internal arg))
(defun move-text-up (arg)
"Move region (transient-mark-mode active) or current line
arg lines up."
(interactive "*p")
(move-text-internal (- arg)))
(global-set-key [\M-\S-up] 'move-text-up)
(global-set-key [\M-\S-down] 'move-text-down)
You should try drag-stuff !
It works exactly like eclipse Alt+Up/Down for single lines, as well as for selected region lines!
In addition to that it allows you to move words with Alt+Left/Right
This is exactly what you're looking for! And it is even available from the ELPA repos!
Other solutions never worked for me. Some of them were buggy(transposing lines while changing their order, wtf?) and some of them were moving exactly selected region, leaving unselected parts of the lines on their positions. But drag-stuff works exactly like in eclipse!
And even more! You can try selecting a region and using Alt+Left/Right ! This will transpose selected region by one character to the left or right. Amazing!
To enable it globally simply run this:
(drag-stuff-global-mode)
I have written a couple of interactive functions for moving lines up/down:
;; move line up
(defun move-line-up ()
(interactive)
(transpose-lines 1)
(previous-line 2))
(global-set-key [(control shift up)] 'move-line-up)
;; move line down
(defun move-line-down ()
(interactive)
(next-line 1)
(transpose-lines 1)
(previous-line 1))
(global-set-key [(control shift down)] 'move-line-down)
The keybindings are IntelliJ IDEA style, but you can use anything you want. I should probably implement some functions that operate on regions as well.
Here is my snippet to move the current line or the lines spanned by the active region. It respects cursor position and highlighted region. And it won't break lines when the region doesn't begin/end at line border(s). (It is inspired by eclipse; I found the eclipse way more convenient than 'transpose-lines'.)
;; move the line(s) spanned by the active region up/down (line transposing)
;; {{{
(defun move-lines (n)
(let ((beg) (end) (keep))
(if mark-active
(save-excursion
(setq keep t)
(setq beg (region-beginning)
end (region-end))
(goto-char beg)
(setq beg (line-beginning-position))
(goto-char end)
(setq end (line-beginning-position 2)))
(setq beg (line-beginning-position)
end (line-beginning-position 2)))
(let ((offset (if (and (mark t)
(and (>= (mark t) beg)
(< (mark t) end)))
(- (point) (mark t))))
(rewind (- end (point))))
(goto-char (if (< n 0) beg end))
(forward-line n)
(insert (delete-and-extract-region beg end))
(backward-char rewind)
(if offset (set-mark (- (point) offset))))
(if keep
(setq mark-active t
deactivate-mark nil))))
(defun move-lines-up (n)
"move the line(s) spanned by the active region up by N lines."
(interactive "*p")
(move-lines (- (or n 1))))
(defun move-lines-down (n)
"move the line(s) spanned by the active region down by N lines."
(interactive "*p")
(move-lines (or n 1)))
There is an entry in the emacs wiki just for this:
http://www.emacswiki.org/emacs/MoveLine
For moving regions:
http://www.emacswiki.org/emacs/MoveRegion
There's no built-in. You can use transpose-lines (C-x C-t) but you cannot use it repeatedly. Look at the functions on http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/.
It should be easy to adapt that to regions, too.
The transpose-paragraph function could help you.
You might also want to have a look to the transpose section in the Emacs manual.
Essentially:
C-t
Transpose two characters (transpose-chars).
M-t
Transpose two words (transpose-words).
C-M-t
Transpose two balanced expressions (transpose-sexps).
C-x C-t
Transpose two lines (transpose-lines).
I use the smart-shift package (in Melpa) for this. By default it rebinds C-C <arrow> to move a line or region. It moves horizontally by a major-mode-specific amount (e.g. c-basic-offset or python-indent-offset). Works on regions also.
;; binds C-C <arrows>
(when (require 'smart-shift nil 'noerror)
(global-smart-shift-mode 1))