When writing Scala code in Emacs, I notice the following indentation issue:
List(1,2,3).foreach{ x =>
Then press enter.
Then close the bracket, and this is what ends up happening:
List(1,2,3).foreach{ x =>
}
Although this is one particular example, this issue appears in a variety of ways when auto-indenting in Emacs.
An answer to either of these two questions would be appreciated:
How can this issue be fixed so that the brace gets put in the proper place and anything within the braces is indented one level to the right?
Is it possible to disable this type of auto-indentation (i.e. like 'set noautoindent' in vi). I tried solutions like the ones suggested here: Disable auto indent globally in Emacs without success.
Thanks in advance!
I've coded up a simple piece of code - it makes emacs keep indent level for most time, and indents two spaces to the right when the previous non-empty line ends with "{", "(", ">", "=".
Add file besi.el to your load path.
(provide 'besi)
(defun besi-indent-line ()
"Indent current line"
(interactive)
(scala-indent-line-to (besi-indent)))
(defun besi-indent ()
(save-excursion
(forward-comment -100000)
(backward-char 1)
(if (or (looking-at "{") (looking-at "=") (looking-at ">") (looking-at "("))
(+ (current-indentation) 2)
(current-indentation))))
(defun besi-newline ()
(interactive)
(newline-and-indent))
Edit line in scala-mode.el
indent-line-function 'besi-indent-line
and line in scala-mode-ui.el
("\r" 'besi-newline)
Also add a line (require 'besi) to the start of scala-mode.el.
Uploaded it to github for easy reference - besi
I tried to solve this by editing scala-mode-indent.el file. It breaks indent in some of the other situations, but at least you will not have all those indents half-screen forward.
Comment out this line:
;; (scala-indentation-from-following)
And modify scala-indentation-from-preceding:
(defun scala-indentation-from-preceding ()
;; Return suggested indentation based on the preceding part of the
;; current expression. Return nil if indentation cannot be guessed.
(save-excursion
(scala-backward-spaces)
(and
(not (bobp))
(if (eq (char-syntax (char-before)) ?\()
(scala-block-indentation)
(progn
(when (eq (char-before) ?\))
(backward-sexp)
(scala-backward-spaces))
t
;;(scala-looking-at-backward scala-expr-start-re)
))
(if (scala-looking-at-backward scala-expr-start-re)
(+ (current-indentation) scala-mode-indent:step)
(current-indentation)
))))
As I said, it still remains broken after that. I plan to write a better support shortly, maybe in a week or two.
EDIT:
If you want to disable scala indentation completely, comment out the line in scala-mode.el
;; indent-line-function 'scala-indent-line
Related
I'm new to elisp, so please forgive me if the following approach is totally clumsy.
In the team I'm currently working with, there is an usual convention of closing python blocks with a pass statement (if they aren't ended by closing keywords like else or except or such). While unusual, this has the advantage that one can always recover the original indentation of the program if it is unintentionally changed (using emacs indent-region).
To get existing code in line with this convention, I wrote a small elisp function:
(defun python-check-indent ()
"Check if automatic indentation changes current indent, insert pass keyword if it does."
(interactive)
(move-beginning-of-line 1)
(skip-chars-forward " ")
(if
(< 0
(let (original)
(setq original (point))
(indent-for-tab-command)
(- (point) original)
)
)
(progn
(insert "pass")
(newline)
(indent-for-tab-command)
)
)
(next-line)
)
(global-set-key (kbd "C-`") 'python-check-indent)
The idea is simply to test whether hitting TAB would change the indentation, and insert a pass statement in that case. To facilitate processing longer blocks of code, it then advances to the next line.
When I run it using M-x python-check-indent, it does what I want (except that it moves around empty lines slightly), also when running it repeatedly to process several lines. However, when I run it repeatedly using the C-` keybinding, it starts messing up the code from the second invocation on.
So here are my questions: What is the difference between invoking a command with M-x ... and using its keybinding? And how could I change the function to be not affected by this difference?
emacs-version: GNU Emacs 23.3.1 (x86_64-apple-darwin, NS apple-appkit-1038.35) of 2011-03-10 on black.porkrind.org
(edit) current workaround: I'm now wrapping it inside a keyboard-macro, so it's "bound" to C-x e, and behaves properly.
The general rule is that it is best to avoid complex interactive
commands in your functions because they could be affected by all sorts
of options.
(defun python-check-indent ()
"Check if automatic indentation changes current indent, insert pass keyword if it does."
(interactive)
(goto-char (line-beginning-position))
(skip-chars-forward " ")
(when (< 0
(let (original)
(setq original (point))
(python-indent-line)
(- (point) original)))
(insert "pass\n")
(python-indent-line))
(forward-line))
However, even this is probably not good because python-indent-line's behavior depends on last-command and python-indent-trigger-commands. I think it would be best if you replaced the first invocation of python-indent-line with the code which computes the target indentation instead of actually indenting, something like (nth python-indent-current-level python-indent-levels).
PS. If you still have problems, I suggest that you use edebug and step through the function.
How to change default emacs mark-paragraph function behaviour to not select first empty line?
my emacs http://dl.dropbox.com/u/1019877/e2.PNG
I've made Bohzidars upgraded version and it works for first line too.
(global-set-key (kbd "M-h") (lambda ()
(interactive)
(mark-paragraph)
(if (> (line-number-at-pos) 1)
(next-line))
(beginning-of-line)))
thanks guys for the tips.
The currently accepted answer has two disadvantages: 1) doesn't accept arguments and 2) doesn't allow to mark more paragraphs by repeated calls (especially this is very useful). Here is my solution - it is the original mark-paragraph with a next-line command at the end. The condition assures it works also on the first of the file.
Possibly a more economic solution is to use advices, but I don't know how to use them yet :).
(defun rs-mark-paragraph (&optional arg allow-extend)
"The original default mark-paragraph, but doesn't mark the first
empty line. Put point at beginning of this paragraph, mark at
end. The paragraph marked is the one that contains point or
follows point.
With argument ARG, puts mark at end of a following paragraph, so that
the number of paragraphs marked equals ARG.
If ARG is negative, point is put at end of this paragraph, mark is put
at beginning of this or a previous paragraph.
Interactively, if this command is repeated
or (in Transient Mark mode) if the mark is active,
it marks the next ARG paragraphs after the ones already marked."
(interactive "p\np")
(unless arg (setq arg 1))
(when (zerop arg)
(error "Cannot mark zero paragraphs"))
(cond ((and allow-extend
(or (and (eq last-command this-command) (mark t))
(and transient-mark-mode mark-active)))
(set-mark
(save-excursion
(goto-char (mark))
(forward-paragraph arg)
(point))))
(t
(forward-paragraph arg)
(push-mark nil t t)
(backward-paragraph arg)
(if (/= (line-number-at-pos) 1)
(next-line)))))
You cannot change the behaviour of mark-paragraph, but you can easily bind another command to the C-M-h keystroke (to resemble the original M-h):
(global-set-key (kbd "C-M-h") (lambda ()
(interactive)
(mark-paragraph)
(next-line)
(beginning-of-line)))
Something like this should do the trick.
I'm not sure I see a convenient way to do this. mark-paragraph calls forward-paragraph and backward-paragraph to do the bulk of the work, and in the documentation for backward-paragraph, we have "if the first real line of a paragraph is preceded by a blank line, the paragraph starts at that blank line."
The most relevant variables to look at appear to be paragraph-start and paragraph-separate, two regular expressions used inside paragraphs.el to figure out this sort of thing. I'd be leary of changing them though, as they are going to have quite a lot of other effects.
Another option is to write your own function that does something like the following:
(defun dg-mark-paragraph ()
(interactive)
(mark-paragraph)
(goto-char (region-beginning))
(when (= (string-match paragraph-separate (thing-at-point 'line)) 0)
(forward-line)))
I wrote an interactive function which inserts the "character above the point" in to the current line. For instance, given a line containing "12345" followed by a line "abcdef" and the point sitting at the letter "c", copy-down would make the second line become "ab3cdef". copy-down again would make the second line become "ab34cdef".
My function fails (using GNU Emacs 23.3.1 under windows 7) the second time I invoke it by inserting the text from the first invocation and not advancing properly. If I put any emacs "manipulations" in-between invocations, it works fine. (For instance if I do a copy-down, "left arrow", "right arrow", copy-down it works fine for both invocations.)
Here's my function:
(defun copy-down ()
"Grab the character in the line above and insert at the current location."
(interactive)
(let ((beg (progn (previous-line 1) (point)))
(end (progn (forward-char) (point))))
(backward-char)
(next-line 1)
(insert-buffer-substring (current-buffer) beg end)))
If it matters, I usually tie my function to a key: (global-set-key [f5] 'copy-down)
PS. I got used to using this capability in the editor I used before switching to emacs many years ago and I miss it in GNU Emacs. :-(
What you have works just fine for me. That said, previous-line has interaction with other settings (specifically goal-column) and generally shouldn't be used when writing elisp. Instead you should use (forward-line -1). But, of course, your code relies on the goal-column... You can test this by running Emacs without your other configurations, ala emacs -q.
Here's a slightly different version of your code that doesn't rely on goal-column:
(defun copy-down ()
"Grab the character in the line above and insert at the current location."
(interactive)
(let* ((col (current-column))
(to-insert (save-excursion
(forward-line -1)
(move-to-column col)
(buffer-substring-no-properties (point) (1+ (point))))))
(insert to-insert)))
If the problem isn't with using previous-line, then I don't imagine my code would make much of a difference.
Another option you have is to try running it in the debugger to see where your code breaks down. Move the point inside the defun for copy-down and type M-x edebug-defun, and the next time you run it you'll be able to step through the code. Docs for edebug can be found here.
You need to use let* instead of let. The former allows you to use earlier values in later forms in the same statement.
BTW, that's an unconventional way to write elisp, you might want to look at some other code samples.
EDIT:
Hey, someone completely rearranged your function! It might work now.
Try
(defun copy-down (arg)
(interactive "p")
(let ((p (+ (current-column) (point-at-bol 0))))
(insert-buffer-substring (current-buffer) p (+ p arg))))
which has the additional functionality of taking a prefix argument to copy n (default to 1) characters down.
It seems that when vimpulse is running, autopair only works partially in the sense that pressing backspace in empty bracket pairs will no longer remove the closing bracket but only the opening one (which means backspace functions as normal backspace now). An example:
(When Vimpulse and autopair are both active, and current mode is INSERT mode, "|" denotes the cursor)
begin: (|)
Now press "backspace"
expected result: | (both opening and closing brackets are removed)
actual result: |) (only the opening bracket is removed)
I know this has to do with the fact that vimpulse (or rather viper-mode) remapped [backspace] from delete-backward-char to something else (viper-delete-backward-char I think). But I could not find a fix to it.
Could anybody find a solution to this? (so that backspace key will remove both opening and closing bracket when the bracket is empty and cursor is in between).
Thanks!
i think something like this in your init file would work:
(add-hook 'autopair-mode-hook
'(lambda ()
(define-key autopair-emulation-alist [remap viper-delete-backward-char] 'autopair-backspace)))
I will answer this question myself.
I could not figure out an "orthodoxy" way to solve the problem and I came up with a hack.
The function that is bound to in viper insert mode (viper-del-backward-char-in-insert) is adviced to check whether cursor is currently in a matched pair, if so, the character after the cursor is deleted before the actual function is called. This also takes into account possible problem caused by prefix character (backslash).
Just copy the code below into your .emacs file after viper-mode or vimpulse is loaded.
(defun not-escaped (escape-char)
"Character immediately before cursor is not prefixed by escape-char"
(let ((count 0))
(save-excursion
(if (char-before)
(backward-char))
(while (and (char-before)
(= (char-before) escape-char))
(setq count (+ count 1))
(backward-char))
(if (= 0
(% count 2))
t
nil))))
(defun in-matched-empty-pair (pair-list)
"tell if cursor is in an empty pair in pair-list"
(let ((next-char (char-after))
(prev-char (char-before))
(matched nil)
(pair)
(pair-left)
(pair-right))
(if (and next-char
prev-char)
(while (and (setq pair
(pop pair-list))
(not matched))
(setq pair-left (pop pair)
pair-right (pop pair))
(if (= next-char pair-right)
(if (and
(= prev-char pair-left)
(not-escaped ?\\))
(setq matched t)))))
(if matched
t
nil)))
(defvar viper-workaround-pairs
'(
(?\" ?\")
(?\' ?\')
(?\` ?\`)
(?\( ?\))
(?\[ ?\])
(?\{ ?\})
))
;; Workaround for integration problem with autopair
(defadvice viper-del-backward-char-in-insert (before viper-auto-delete-pair-backward())
(if (in-matched-empty-pair viper-workaround-pairs)
(delete-char 1)))
;; Activate advice
(ad-activate 'viper-del-backward-char-in-insert)
This is a hack but it is probably the best I could do now.
Here is my updated solution. Put the following in your .emacs file after the code that loads autopair and vimpulse:
(add-to-ordered-list 'emulation-mode-map-alists (car (last emulation-mode-map-alists)) 400)
It moves autopair's keymap in front of viper's one, giving it higher priority.
Maybe you have to adept the order number (here 400), depending on whether you are using additional emulation-modes.
The result can be checked with C-x v emulation-mode-map-alists. In my case:
(viper--intercept-key-maps cua--keymap-alist autopair-emulation-alist viper--key-maps)
Now, autopair-emulation-alist should be listed before viper--key-maps.
baumichel found the trick. I just add a quick snippet to help :
First, as autopair-mode simply appends autopair-emulation-alist, evaluate:
(defadvice viper-change-state-to-insert (after autopair nil activate)
(add-to-ordered-list 'emulation-mode-map-alists 'autopair-emulation-alist 300))
Then, remember that vimpulse-normalize-minor-mode-map-alist removes all viper keymaps in front of the alist, so execute:
(defadvice vimpulse-normalize-minor-mode-map-alist (after order-viper--key-maps nil activate)
(add-to-ordered-list 'emulation-mode-map-alists 'viper--key-maps 500))
That works for me! I evaluate these snippets in an embedded eval-after-load for both vimpulse and autopair.
My idea is that Emacs dev should rethink the emulation-mode-map-alists and use a property list indexing priority order like this: ((:name viper--key-maps :after (cua--keymap-alist autopair-emulation-alist)) (:name viper--intercept-key-maps :before (cua--keymap-alist autopair-emulation-alist))). Old packages like viper, CUA and so on should be better maintained because our setup becomes ugly after years with Emacs.
I've seen at least two recommendations on StackOverflow to insert newlines between sentences when editing LaTeX documents. The reason being that the practice facilitates source control, diffing, and collaborative editing.
I'm basically convinced, but I'm lazy, and I don't want to have to think about it.
So I'm searching for some emacs incantation to handle it for me. Could be a minor mode, could be a set of variables that need to be set.
I think what I don't want is
Soft wrapping of text (say using the longlines and (set long-lines-auto-wrap 't)). This is because I don't want to impose requirements on my collaborators' editors, and I sometimes use other unix tools to examine these files.
I think what I do want is
For fill-paragraph to fill between newlines that look like they mark the end of a sentence.
A solution that works with auto-fill-mode would be a bonus.
That is:
chat chat chat.
A new sentence
with goofed up wrapping that needs to be fixed.
Mumble mumble
Transformed to:
chat chat chat.
A new sentence with goofed up wrapping that needs to be fixed.
Mumble mumble
Your comments and suggestions are appreciated.
Edit: The suggestion by Jouni K. Seppänen pointed me at LaTeX-fill-break-at-separators, which suggests that emacs almost knows how to do this already. Anyway, I'm off to read some code, and will report back. Thanks again.
More general version of the same question: Editor showdown: Maintain newlines at the ends of sentences. Thanks, dreeves.
Here's what I use, which was mostly cribbed from Luca de Alfaro:
(defun fill-sentence ()
(interactive)
(save-excursion
(or (eq (point) (point-max)) (forward-char))
(forward-sentence -1)
(indent-relative t)
(let ((beg (point))
(ix (string-match "LaTeX" mode-name)))
(forward-sentence)
(if (and ix (equal "LaTeX" (substring mode-name ix)))
(LaTeX-fill-region-as-paragraph beg (point))
(fill-region-as-paragraph beg (point))))))
I bind this to M-j with
(global-set-key (kbd "M-j") 'fill-sentence)
The references to "LaTeX" are for AUCTeX support. If you don't use AUCTeX, the let can be simplified to
(let (beg (point))
(forward-sentence)
(fill-region-as-paragraph beg (point)))
I have been meaning to do this forever and I recently found this blog post which worked fairly well for me. So here is (a slightly modified version of) what I have been using for a few days.
(defun auto-fill-by-sentences ()
(if (looking-back (sentence-end))
;; Break at a sentence
(progn
(LaTeX-newline)
t)
;; Fall back to the default
(do-auto-fill)))
(add-hook 'LaTeX-mode-hook (lambda () (setq auto-fill-function 'auto-fill-by-sentences)))
;; Modified from http://pleasefindattached.blogspot.com/2011/12/emacsauctex-sentence-fill-greatly.html
(defadvice LaTeX-fill-region-as-paragraph (around LaTeX-sentence-filling)
"Start each sentence on a new line."
(let ((from (ad-get-arg 0))
(to-marker (set-marker (make-marker) (ad-get-arg 1)))
tmp-end)
(while (< from (marker-position to-marker))
(forward-sentence)
;; might have gone beyond to-marker---use whichever is smaller:
(ad-set-arg 1 (setq tmp-end (min (point) (marker-position to-marker))))
ad-do-it
(ad-set-arg 0 (setq from (point)))
(unless (or (looking-back "^\\s *")
(looking-at "\\s *$"))
(LaTeX-newline)))
(set-marker to-marker nil)))
(ad-activate 'LaTeX-fill-region-as-paragraph)
If you put a comment marker at the end of each sentence, Emacs knows not to move the next line inside the comment:
chat chat chat.%
A new sentence
with goofed up wrapping that needs to be fixed.%
Mumble mumble%
Then M-q fills each sentence separately, at least in AUCTeX 11.85. (If you test this in Emacs, there seems to be a bug where if this is the first paragraph in the buffer and you type M-q, you get an error message. Just put a newline before the text to work around it.)
If you don't want to type the comment characters, you could take LaTeX-fill-paragraph and modify it so that sentence-ending punctuation at end of line works similarly to comments.
(defun wrap-at-sentences ()
"Fills the current paragraph, but starts each sentence on a new line."
(interactive)
(save-excursion
;; Select the entire paragraph.
(mark-paragraph)
;; Move to the start of the paragraph.
(goto-char (region-beginning))
;; Record the location of the end of the paragraph.
(setq end-of-paragraph (region-end))
;; Wrap lines with 'hard' newlines (i.e., real line breaks).
(let ((use-hard-newlines 't))
;; Loop over each sentence in the paragraph.
(while (< (point) end-of-paragraph)
;; Determine the region spanned by the sentence.
(setq start-of-sentence (point))
(forward-sentence)
;; Wrap the sentence with hard newlines.
(fill-region start-of-sentence (point))
;; Delete the whitespace following the period, if any.
(while (char-equal (char-syntax (preceding-char)) ?\s)
(delete-char -1))
;; Insert a newline before the next sentence.
(insert "\n")))))
(global-set-key (kbd "M-q") 'wrap-at-sentences)
May not work in all circumstances, but:
(defun my-fill-sentence ()
"Fill sentence separated by punctuation or blank lines."
(interactive)
(let (start end)
(save-excursion
(re-search-backward "\\(^\\s-*$\\|[.?!]\\)" nil t)
(skip-syntax-forward "^w")
(setq start (point-at-bol)))
(save-excursion
(re-search-forward "\\(^\\s-*$\\|[.?!]\\)" nil t)
(setq end (point-at-eol)))
(save-restriction
(narrow-to-region start end)
(fill-paragraph nil))))
To make it work with auto-fill-mode, add (setq normal-auto-fill-function 'my-fill-sentence) to your LaTeX mode hook (I think).
I am assuming you know elisp.
There are a few approaches you can take:
Hook into auto-fill-mode. There are a lot of hard-coded
conditionals there, so it might not work for you. You can
potentially play with auto-fill-function and see if you have
the hook you need there.
Make a character (probably .) "electric" so that when you press
it, it inserts itself and then calls a function to determine how
to fill the line you're on.
Set an after-change-hook to call a function that determines how
to fill the sentence. This function will be called after every
change to the buffer, so do it efficiently. (This mechanism is
used by font-lock, so don't worry about it too much. It sounds
slow, but really isn't -- people type slowly.)
Once you have hooked in at the right place, you just have to implement
the filling logic. The source for sentence-at-point (from thingatpt) may be
instructive.
Anyway, I've never heard of anyone doing this... but it is definitely possible. Like most things in Emacs, it's just a Simple Matter Of Programming.
If the other answers are too automatic, here's a semiautomatic approach.
It's basically what you would do repeatedly if you were going to manually reformat, but condensed so you can hit a single key repeatedly instead.
;; - go to the end of the line,
;; - do ^d to suck the previous line onto this one,
;; - make sure there's only one space between the now-concatenated
;; lines, and then
;; - jump to the end and hit space so that (with auto-fill-mode)
;; the line nicely rewraps itself:
;; (turn on auto-fill-mode with M-x auto-fill-mode)
(defalias 'fill-sentence
(read-kbd-macro "C-e C-d SPC M-x just- one- space RET C-e SPC <backspace>"))
(define-key global-map [f4] 'fill-sentence) ; or whatever key you like
I like Chris Conway's macro a lot but it only works after you manually line-break each sentence. I'm a lazy guy so I want emacs to do it for me. This morning I finally sat down and looked into the problem. The solution I have now is to hack the built-in macro fill-region-as-paragraph.
After applying the following hack, a new option newline-after-sentence will be set to true. The standard M-q (fill-paragraph) will automatically fill and create line-breaks between sentences. Note that tests are only done with GNU Emacs 23.3.1 — use it at your own risk.
The full macro is long so I won't post it here. The idea is to add the following loops in fill-region-as-paragraph
...
;; Insert a line break after each sentence
(while (< (point) to)
(forward-sentence)
(if (< (point) to) (fill-newline)))
;; This is the actual filling loop.
(goto-char from)
(let (sentbeg sentend)
(while (< (point) to)
(setq sentbeg (point))
(end-of-line)
(setq sentend (point))
(fill-one-line sentbeg sentend justify) ;; original filling loop
(forward-line)))))
...
You can find the full macro in my git repository. Some details are also written in my blog. In case you don't want to read my poor English, you can simply use
$ curl http://fermi.mycloudnas.com/cgit.cgi/fill/plain/hack.el >> ~/.emacs
to append the hack to your ~/.emacs and give it a try. Comments and bug reports are all welcome.
An alternative approach would be to leave your .tex file as is, and use a tool like latexdiff
(described in this StackExchange post) instead of Unix diff. This produces a .tex file with Word-style track changes marks, and handles whitespace correctly so you don't have to worry about where your sentences end.
I wrote the following which loops over a region and inserts newlines. Instead of using forward-sentence which didn't work for me, I use re-search-forward "[.?!][]\"')}]*\\( \\)", which finds all sentences followed only by two spaces (the regexp is a modified sentence-end). The newline is made using newline-and-indent.
(defun fill-sentences-in-paragraph ()
"Put a newline at the end of each sentence in paragraph."
(interactive)
(save-excursion
(mark-paragraph)
(call-interactively 'fill-sentences-in-region)))
(defun fill-sentences-in-region (start end)
"Put a newline at the end of each sentence in region."
(interactive "*r")
(call-interactively 'unfill-region)
(save-excursion
(goto-char start)
(while (re-search-forward "[.?!][]\"')}]*\\( \\)" end t)
(newline-and-indent))))
To be able to fix improperly formatted text such as the example "chat chat chat...", fill-sentences-in-region first calls unfill-region which gets rid of sentence-breaking whitespace:
(defun unfill-region (beg end)
"Unfill the region, joining text paragraphs into a
single logical line. This is useful, e.g., for use
with 'visual-line-mode'."
(interactive "*r")
(let ((fill-column (point-max)))
(fill-region beg end)))
I use visual-line-mode and replace my default paragraph fill M-q to fill-sentences-in-paragraph with (global-set-key "\M-q" 'fill-sentences-in-paragraph).