Im an emacs newbie, I want emacs to be able to indent my code like this
egg = spam.foooooo('vivivivivivivivivi')\
.foooooo('emacs', 'emacs', 'emacs', 'emacs')
It's not possible to do this automatically by default (without manually inserting spaces or C-c >), since emacs always indents 4 spaces (unless Im splitting multiple arguments over multiple lines).
Whats the best approach to do this?
PS: If this is a bad idea (against PEP 8 or something) please do tell me
I agree with Aaron about the desirability of your stylistic choice, but since I also agree with him that Emacs Lisp is fun, I'll describe how you might go about implementing this.
Emacs python-mode computes the indentation of a line in the function python-calculate-indentation and the relevant section for handling continuation lines is buried deep inside the function, with no easy way to configure it.
So we have two options:
Replace the whole of python-calculate-indentation with our own version (a maintenance nightmare whenever python-mode changes); or
"Advise" the function python-calculate-indentation: that is, wrap it in our own function that handles the case we're interested in, and otherwise defers to the original.
Option (2) seems just about doable in this case. So let's go for it! The first thing to do is to read the manual on advice which suggests that our advice should look like this:
(defadvice python-calculate-indentation (around continuation-with-dot)
"Handle continuation lines that start with a dot and try to
line them up with a dot in the line they continue from."
(unless
(this-line-is-a-dotted-continuation-line) ; (TODO)
ad-do-it))
Here ad-do-it is a magic token that defadvice substitutes with the original function. Coming from a Python background you might well ask, "why not do this decorator-style?" The Emacs advice mechanism is designed (1) to keep advice well separated from the original; and (2) to have multiple pieces of advice for a single function that don't need to co-operate; (3) to allow you individual control over which pieces of advice are turned on and off. You could certainly imagine writing something similar in Python.
Here's how to tell if the current line is a dotted continuation line:
(beginning-of-line)
(when (and (python-continuation-line-p)
(looking-at "\\s-*\\."))
;; Yup, it's a dotted continuation line. (TODO)
...)
There's one problem with this: that call to beginning-of-line actually moves point to the beginning of the line. Oops. We don't want to move point around when merely calculating indention. So we better wrap this up in a call to save-excursion to make sure that point doesn't go a-wandering.
We can find the dot that we need to line up with by skipping backwards over tokens or parenthesized expressions (what Lisp calls "S-expressions" or "sexps") until either we find the dot, or else we get to the start of the statement. A good Emacs idiom for doing a search in a restricted part of the buffer is to narrow the buffer to contain just the part we want:
(narrow-to-region (point)
(save-excursion
(end-of-line -1)
(python-beginning-of-statement)
(point)))
and then keep skipping sexps backwards until we find the dot, or until backward-sexp stops making progress:
(let ((p -1))
(while (/= p (point))
(setq p (point))
(when (looking-back "\\.")
;; Found the dot to line up with.
(setq ad-return-value (1- (current-column)))
;; Stop searching backward and report success (TODO)
...)
(backward-sexp)))
Here ad-return-value is a magic variable that defadvice uses for the return value from the advised function. Ugly but practical.
Now there are two problems with this. The first is that backward-sexp can signal an error in certain circumstances, so we better catch that error:
(ignore-errors (backward-sexp))
The other problem is that of breaking out of the loop and also indicating success. We can do both at once by declaring a named block and then calling return-from. Blocks and exits are Common Lisp features so we'll need to (require 'cl)
Let's put it all together:
(require 'cl)
(defadvice python-calculate-indentation (around continuation-with-dot)
"Handle continuation lines that start with a dot and try to
line them up with a dot in the line they continue from."
(unless
(block 'found-dot
(save-excursion
(beginning-of-line)
(when (and (python-continuation-line-p)
(looking-at "\\s-*\\."))
(save-restriction
;; Handle dotted continuation line.
(narrow-to-region (point)
(save-excursion
(end-of-line -1)
(python-beginning-of-statement)
(point)))
;; Move backwards until we find a dot or can't move backwards
;; any more (e.g. because we hit a containing bracket)
(let ((p -1))
(while (/= p (point))
(setq p (point))
(when (looking-back "\\.")
(setq ad-return-value (1- (current-column)))
(return-from 'found-dot t))
(ignore-errors (backward-sexp))))))))
;; Use original indentation.
ad-do-it))
(ad-activate 'python-calculate-indentation)
I won't claim that this is the best way to do this, but it illustrates a bunch of moderately tricky Emacs and Lisp features: advice, excursions, narrowing, moving over sexps, error handling, blocks and exits. Enjoy!
That's pretty ugly and would require you to write some emacs lisp. I need to learn emacs lisp so if it wasn't so ugly, I would probably be up for doing it. But it is and I'm not. Looks like you get to learn emacs lisp :) (if you actually want to do this). I'm sort of jealous. At any rate, you said that informing you that this is a bad idea was an acceptable answer so here goes:
That's a terrible stylistic choice. Isn't
egg = spam.foo('viviviv')
egg = egg.foo('emacs', 'emacs', 'emacs')
easier to read?
While not specifically against PEP 8, it is mentioned that use of the line continuation character should be kept to a minimum. Also, this most definitively and objectively goes against the spirit of PEP 8. I'm just not sure how ;)
Related
I'm running both emacs 23 and 24 with "--no-init-file" to avoid loading my customizations. But then I explicitly load my ancient version of python-mode.el (version 3.105, last copyright notice 1998), and see the same behavior I'm about to describe, so I believe it's core emacs, not python.
Consider this code (the * marks the cursor location):
*def emacs_is_fun():
for x in range(3):
print(x)
Put the cursor at column 4 at the start of "def".
With emacs 23, running mark-sexp selects "def".
With emacs 24, mark-sexp selects the entire code block, to the end
of the print statement.
This isn't bad. The main problem is this common usage:
*very_long_var_name[very_long_expn] += long_function_call(long_arg_list, blah)
Again, the cursor is at the start of the printable part of the line, col 4.
In emacs 23, mark-sexp selects very_long_var_name.
In emacs 24, mark-sexp selects the full line, from col 4 to the end.
I've been using Ctrl-alt-space alt-w to quickly save variable names.
(Or alt-2 ctrl-alt-space alt-w to save a ref expression.) Now it's
gone. It's emacs, so this must be customizable, but I haven't found
where the new behaviour is implemented (and remember I'm using a python-mode
that is about 15 years old). What do I need to put in my .emacs file?
#Eric Interesting. Thanks for the context in the comment of my other answer.
I think you may just want this then:
(add-hook 'python-mode-hook (lambda () (setq forward-sexp-function nil)))
From comments inside python-mode built-in emacs 24 (which I think you may be getting instead)
At last but not least the specialized python-nav-forward-sexp allows easy navigation between code blocks. If you prefer cc-mode-like forward-sexp movement, setting forward-sexp-function to nil is enough...
This gels closer to what I think of a sexp as, like mentioned in my other answer, but outside of lisp a sexp seems at least somewhat ambiguous.
Seems like this was a bug fix in emacs 24. As that is technically now marking the full sexp. It seems like you want the functionality of marking a symbol instead.
I think by putting this in your .emacs you'll get the functionality you want.
(defun your-mark-symbol (&optional arg allow-extend)
"mark-sexp in lisp.el but with fowrad-symbol instead of foward-sexp"
(interactive "P\np")
(cond ((and allow-extend
(or (and (eq last-command this-command) (mark t))
(and transient-mark-mode mark-active)))
(setq arg (if arg (prefix-numeric-value arg)
(if (< (mark) (point)) -1 1)))
(set-mark
(save-excursion
(goto-char (mark))
(forward-symbol arg)
(point))))
(t
(push-mark
(save-excursion
(forward-symbol (prefix-numeric-value arg))
(point))
nil t))))
(global-set-key (kbd "C-M-SPC") 'your-mark-symbol)
Note that is literally a copy of mark-sexp but with foward-symbol instead of forward-sexp.
This could very well cause unexpected weirdness if you're using mark-sexp via C-M-SPC in other buffers/modes, in which case you would want to do make this keybinding via mode hook instead.
The latest version of Emacs (e.g. 24.3.93.1) come with python.el. How can I cycle through different levels of indentation for a given block?
For instance in the code:
for ix in range(10);
line1
line2 # <- two possible values of indentation for this line
The EmacsWiki doesn't seem to provide info on this and I couldn't find anything on C-h m. Is this functionality supported?
Both python-modes use TAB for cycling. Should TAB not cycle, check your init resp. consider filing a bug-report.
BTW the way it's done differs slightly: from outmost position python.el will dedent immediatly, while first hit at python-mode.el from correct outmost position does nothing. Second TAB at python-mode.el will jump to column 0, then stepping up indent by indent. Python.el does the inverse, steps down indent by indent, but jumps to outmost from column zero.
Use C-h m in order to know that. It invokes the describe-mode function.
You can also look at the python.el file and look for define-key:
;; Indent specific
(define-key map "\177" 'python-indent-dedent-line-backspace)
(define-key map (kbd "<backtab>") 'python-indent-dedent-line)
(define-key map "\C-c<" 'python-indent-shift-left)
(define-key map "\C-c>" 'python-indent-shift-right)
(define-key map ":" 'python-indent-electric-colon)
Or indent
;; Indentation: Automatic indentation with indentation cycling is
;; provided, it allows you to navigate different available levels of
;; indentation by hitting <tab> several times. Also when inserting a
;; colon the `python-indent-electric-colon' command is invoked and
;; causes the current line to be dedented automatically if needed.
snakemake is a python-like replacement for make that is geared more towards workflows than compilation. It's quite nice, but also quite new, and I cannot seem to find a mode for it in Emacs. I just want something very simple: a very slight modification from fundamental-mode, so I in perusing the emacs manual, I started the following in init.el:
(define-derived-mode snake-mode fundamental-mode
...
)
like make, snakemake is strict about indents (actual tab "\t" characters, not how emacs behaves by default when one types TAB). When I instead type "C-q TAB" it puts a real tab character in the buffer : this works, I tried it with a Snakefile in fundamental-mode and it runs perfectly. So to avoid typing "C-q TAB" each time I want a TAB in this mode, the first addition I would like to make to snake-mode is to rebind the TAB key to "C-q TAB" (or something like this). So I perused the emacs manual and tried:
(define-derived-mode snake-mode fundamental-mode
(global-set-key (kbd "\t") (kbd "C-q \t"))
...
)
but this and other alternatives aren't working ... maybe rebinding standard keys like the TAB key is not a recommended practice?
the other addition to the snake-mode I would like is for it to highlight syntax according to python (but not have any python behaviour, e.g., python indenting behaviour)
To conclude, just these 2 simple modifications to fundamental-mode in creating a "snake-mode" and a way to also invoke snake-mode if the filename is "Snakefile" was all I was looking for, but I've already spent several hours perusing the emacs manual and doing some googling, and it seems I'm not even close. This is so simple, and I'm quite sure it is possible; any advice?
Thanks
Murray
Your prayers have been answered:
https://github.com/kyleam/snakemake-mode
I am very happy with it.
Can be gotten from melpa as snakemake-mode.
The following (somewhat elegant, I think ... well at least it is short) kludge does the trick for now. It indeed does the two things I was asking for, i.e., (1) rebinds the TAB key (in a nice way), and (2) does syntax highlighting according to python (plus it only goes to this mode when the file is called "Snakefile", which is nice), and hence this answers my question
; snake-mode
(add-to-list 'auto-mode-alist '("Snakefile" . snake-mode))
(defun insert-tab ()
(interactive)
(insert " ")) ; a "real" tab, i.e., what "C-q \t" would give
(define-minor-mode snake-mode
"Snakemake."
:lighter " snake-make"
(python-mode)
(setq indent-line-function 'insert-tab)
)
; how to hard-code "\t" to a "real" tab (not recommended)
; (global-set-key "\t" `insert-tab)
; end snake-mode
How elegant this is, is, I'm sure, up for debate. And it is only a start on a journey for a proper mode for snakemake (that does highlighting for snakemake specific words like "rule" and "output:", etc., etc.)
Don't do this. It's not how major modes are supposed to handle indentation. They should never rebind TAB, see C-h v indent-line-function:
Function to indent the current line.
This function will be called with no arguments.
If it is called somewhere where auto-indentation cannot be done
(e.g. inside a string), the function should simply return `noindent'.
Setting this function is all you need to make TAB indent appropriately.
Don't rebind TAB unless you really need to.
It won't work anyway, because you can't bind key bindings to other key bindings.
Instead, set indent-tabs-mode to t in your mode function, to make Emacs use tab characters for indentation, and set indent-line-function buffer-locally, to a function that indents appropriately according to the rules of the language. You have to write this function yourself, obviously.
The define-derived-mode macro automatically provides a keymap named after the mode it defines. You can use that together with define-key to make the TAB key simply insert a tab like this:
(define-derived-mode snake-mode fundamental-mode "Snake"
"A mode for Python's snakemake."
(define-key snake-mode-map "\t" 'self-insert-command))
Alternatively, you could set up the indentation mechanism of your mode so that it intelligently indents a line by inserting a (single) TAB at the beginning of the line whenever that is appropriate. That way you don't have to rebind TAB, although of course it's much harder to implement intelligent indentation correctly than to simply rebind a key. See lunaryorn's answer for more information.
I find myself adding debugging "print" statements quite often -- stuff like this:
print("a_variable_name: %s" % a_variable_name)
How do you all do that? Am I being neurotic in trying to find a way to optimize this? I may be working on a function and put in a half-dozen or so of those lines, figure out why it's not working, and then cut them out again.
Have you developed an efficient way of doing that?
I'm coding Python in Emacs.
Sometimes a debugger is great, but sometimes using print statements is quicker, and easier to setup and use repeatedly.
This may only be suitable for debugging with CPython (since not all Pythons implement inspect.currentframe and inspect.getouterframes), but I find this useful for cutting down on typing:
In utils_debug.py:
import inspect
def pv(name):
record=inspect.getouterframes(inspect.currentframe())[1]
frame=record[0]
val=eval(name,frame.f_globals,frame.f_locals)
print('{0}: {1}'.format(name, val))
Then in your script.py:
from utils_debug import pv
With this setup, you can replace
print("a_variable_name: %s' % a_variable_name)
with
pv('a_variable_name')
Note that the argument to pv should be the string (variable name, or expression), not the value itself.
To remove these lines using Emacs, you could
C-x ( # start keyboard macro
C-s pv('
C-a
C-k # change this to M-; if you just want to comment out the pv call
C-x ) # end keyboard macro
Then you can call the macro once with C-x e
or a thousand times with C-u 1000 C-x e
Of course, you have to be careful that you do indeed want to remove all lines containing pv(' .
Don't do that. Use a decent debugger instead. The easiest way to do that is to use IPython and either to wait for an exception (the debugger will set off automatically), or to provoke one by running an illegal statement (e.g. 1/0) at the part of the code that you wish to inspect.
I came up with this:
Python string interpolation implementation
I'm just testing it and its proving handy for me while debugging.
I'm editing some Python code with rather long functions and decided it would be useful to quickly get the function name without scrolling up. I put this bit of code together to do it. Is there something built in to emacs in general, or the standard python mode in particular, which I can use instead?
(defun python-show-function-name()
"Message the name of the function the point is in"
(interactive)
(save-excursion
(beginning-of-defun)
(message (format "%s" (thing-at-point 'line)))))
You may find decent results with which-function-mode:
Which Function mode is a minor mode
that displays the current function
name in the mode line, updating it as
you move around in a buffer.
To either enable or disable Which
Function mode, use the command M-x
which-function-mode. This command is
global; it applies to all buffers,
both existing ones and those yet to be
created. However, it takes effect only
in certain major modes, those listed
in the value of which-func-modes. If
the value is t, then Which Function
mode applies to all major modes that
know how to support it—in other words,
all the major modes that support
Imenu.
Although I see it getting a little confused in one Python file that I have here...
Did you try py-beginning-of-def-or-class?
(defun python-show-function-name()
"Message the name of the function the point is in"
(interactive)
(save-excursion
(py-beginning-of-def-or-class)
(message (format "%s" (thing-at-point 'line)))))
I find it gives me better results than your beginning-of-defun, but if that's not the problem you're having, then maybe I'm just seeing another symptom of the cause of the wonkiness in my other answer.
C-c C-u (py-goto-block-up) might be what you want.