Fix undesirable EMACS tabbing behavior in ESS/Stata - emacs

ESS/Stata mode in emacs incorrectly indents lines that follow lines ending in operators. It seems to incorrectly interpret these lines as multiline commands.
For example:
gen foo = 1
/* generate another variable */
gen bar = 1
The line "gen bar = 1" should not be indented. It looks like EMACS interprets the trailing slash in the comment as an operator, and thinks this line of code spans two lines.
In fact, multiline commands in stata have 3 trailing slashes, and newlines without 3 trailing slashes indicate the end of a statement. e.g. the following indentation would be correct:
gen bar = 1
gen ///
foo = 1
Is there something I can put in my .emacs to correct this behavior? I don't want to give up automatic tabbing completely - it works very well for everything except comments that /* look like this */.
Thanks,
Pnj

You're right, ESS interprets the trailing / as an indication of line continuation. This is hard-coded into the function ess-continued-statement-p, so to modify the behaviour you have to rewrite the code. The following code (in your .emacs) works for your examples.
(eval-after-load 'ess-mode
'(defun ess-continued-statement-p ()
"this is modified code"
(let ((eol (point)))
(save-excursion
(cond ((memq (preceding-char) '(nil ?\, ?\; ?\} ?\{ ?\]))
nil)
;; ((bolp))
((= (preceding-char) ?\))
(forward-sexp -2)
(looking-at "if\\b[ \t]*(\\|function\\b[ \t]*(\\|for\\b[ \t]*(\\|while\\b[ \t]*("))
((progn (forward-sexp -1)
(and (looking-at "else\\b\\|repeat\\b")
(not (looking-at "else\\s_\\|repeat\\s_"))))
(skip-chars-backward " \t")
(or (bolp)
(= (preceding-char) ?\;)))
(t
(progn (goto-char eol)
(skip-chars-backward " \t")
(or (and (> (current-column) 1)
(save-excursion (backward-char 1)
;;;; Modified code starts here: ;;;;
(or (looking-at "[-:+*><=]")
(and (looking-at "/")
(save-excursion (backward-char 1)
(not (looking-at "*")))))))
;;;; End of modified code ;;;;
(and (> (current-column) 3)
(progn (backward-char 3)
(looking-at "%[^ \t]%")))))))))))

Related

Haskell with emacs org-mode: Variable not in scope

After wandering off in frustration from before, I've decided to try Haskell in Emacs org-mode again. I'm using Haskell stack-ghci (8.6.3), Emacs 26.2, org-mode 9.2.3 set up with intero. This code block
#+begin_src haskell :results raw :session *haskell*
pyth2 :: Int -> [(Int, Int, Int)]
pyth2 n =
[ (x, y, z)
| x <- [1 .. n]
, y <- [x .. n]
, z <- [y .. n]
, x ^ 2 + y ^ 2 == z ^ 2
]
#+end_src
produces this RESULTS:
*Main| *Main| *Main| *Main| *Main|
<interactive>:59:16: error: Variable not in scope: n
<interactive>:60:16: error: Variable not in scope: n
<interactive>:61:16: error: Variable not in scope: n
However, this
#+begin_src haskell :results raw
tripleMe x = x + x + x
#+end_src
works fine. I've added the :set +m to both ghci.conf and the individual code block to no effect. This code works fine in a separate hs file run in a separate REPL. The pyth2 code in a separate file also can be called from the org-mode started REPL and run just fine as well. Not sure how to proceed. Can include Emacs init info if necessary.
Over on the org-mode mailing list I got an answer that basically is saying the same as you, D. Gillis. He had a similar work-around that actually is more org-mode-centric. Under a heading where your code blocks will be put this "drawer"
:PROPERTIES:
:header-args:haskell: :prologue ":{\n" :epilogue ":}\n"
:END:
and then (possibly in a local variable) run
#+begin_src haskell :results output
:set prompt-cont ""
#+end_src
For reasons unknown I've had to include the :results output otherwise a cryptic error of "expecting a string" happens.
On a few other notes, haskell babel doesn't respond/care about the :session option, i.e., when you run a code block, a REPL *haskell* starts and that will be the sole REPL. Also, a haskell-mode started REPL doesn't play well with an existing org-mode initiated REPL, i.e., if you start a REPL from haskell-mode, it kills the original org-mode *haskkell*REPL, and any new attempt to run org-mode code blocks can't see this new, non-*haskell*REPL. Then if you kill the haskell-mode REPL and try to run org-mode blocks, you get
executing Haskell code block...
inferior-haskell-start-process: List contains a loop: ("--no-build" "--no-load" "--ghci-options=-ferror-spans" "--no-build" "--no-load" . #2)
... you're hosed -- and nothing seems to shake it, not any restart/refresh, nor killing, reloading the file, i.e., a complete restart of Emacs is necessary. Anyone knowing a better solution, please tells usses.
This is a GHCi issue.
The same error occurs when your code is copied directly into GHCi, which also gives a parse error when it encounters the new line after the equal sign. This first error isn't showing up here because org-babel only shows the value of the last expression (in this case, the error caused by the list comprehension).
I'm not entirely familiar with how Haskell-mode sends the code to GHCi, but it looks like it involves loading in the buffer into GHCi as a file, which may be why you didn't have this problem working from the hs file.
There are a few options to fix this, none of which are completely ideal:
Move some portion of the list into the first line (e.g. the first line could be pyth2 n = [).
Wrap the entire function definition with :{ and :}.
Write an Elisp function to modify what is being sent to GHCi and then changes it back after it is evaluated.
The first two options require you to format your code in a form that the GHCi will accept. In your example case, the first option may not be too bad, but this won't always be so trivial for all multi-line declarations (e.g. pattern-matching function declarations). The downside to the second option is that it requires adding brackets to the code that shouldn't be there in real source code.
To fix the issue of extraneous brackets being added, I've written an Elisp command (my-org-babel-execute-haskell-blocks) that places these brackets around code blocks that it finds, evaluates the region, and then deletes the brackets. Note that this function requires that blocks be separated from all other code with at least one empty line.
Calling my-org-babel-execute-haskell-blocks on your example declares the function without any errors.
EDIT: The previous function I gave failed to work on pattern matching declarations. I've rewritten the function to fix this issue as well as to be comment aware. This new function should be significantly more useful. However, it's worth noting that I didn't handle multi-line comments in a sophisticated manner, so code blocks with multi-line comments may not be wrapped properly.
(defun my-org-babel-execute-haskell-blocks ()
"Wraps :{ and :} around all multi-line blocks and then evaluates the source block.
Multi-line blocks are those where all non-indented, non-comment lines are declarations using the same token."
(interactive)
(save-excursion
;; jump to top of source block
(my-org-jump-to-top-of-block)
(forward-line)
;; get valid blocks
(let ((valid-block-start-ends (seq-filter #'my-haskell-block-valid-p (my-get-babel-blocks))))
(mapcar #'my-insert-haskell-braces valid-block-start-ends)
(org-babel-execute-src-block)
(mapcar #'my-delete-inserted-haskell-braces (reverse valid-block-start-ends)))))
(defun my-get-blocks-until (until-string)
(let ((block-start nil)
(block-list nil))
(while (not (looking-at until-string))
(if (looking-at "[[:space:]]*\n")
(when (not (null block-start))
(setq block-list (cons (cons block-start (- (point) 1))
block-list)
block-start nil))
(when (null block-start)
(setq block-start (point))))
(forward-line))
(when (not (null block-start))
(setq block-list (cons (cons block-start (- (point) 1))
block-list)))))
(defun my-get-babel-blocks ()
(my-get-blocks-until "#\\+end_src"))
(defun my-org-jump-to-top-of-block ()
(forward-line)
(org-previous-block 1))
(defun my-empty-line-p ()
(beginning-of-line)
(= (char-after) 10))
(defun my-haskell-type-declaration-line-p ()
(beginning-of-line)
(and (not (looking-at "--"))
(looking-at "^.*::.*$")))
(defun my-insert-haskell-braces (block-start-end)
(let ((block-start (car block-start-end))
(block-end (cdr block-start-end)))
(goto-char block-end)
(insert "\n:}")
(goto-char block-start)
(insert ":{\n")))
(defun my-delete-inserted-haskell-braces (block-start-end)
(let ((block-start (car block-start-end))
(block-end (cdr block-start-end)))
(goto-char block-start)
(delete-char 3)
(goto-char block-end)
(delete-char 3)))
(defun my-get-first-haskell-token ()
"Gets all consecutive non-whitespace text until first whitespace"
(save-excursion
(beginning-of-line)
(let ((starting-point (point)))
(re-search-forward ".*?[[:blank:]\n]")
(goto-char (- (point) 1))
(buffer-substring-no-properties starting-point (point)))))
(defun my-haskell-declaration-line-p ()
(beginning-of-line)
(or (looking-at "^.*=.*$") ;; has equals sign
(looking-at "^.*\n[[:blank:]]*|")
(looking-at "^.*where[[:blank:]]*$")))
(defun my-haskell-block-valid-p (block-start-end)
(let ((block-start (car block-start-end))
(block-end (cdr block-start-end))
(line-count 0))
(save-excursion
(goto-char block-start)
(let ((token 'nil)
(is-valid t))
;; eat top comments
(while (or (looking-at "--")
(looking-at "{-"))
(forward-line))
(when (my-haskell-type-declaration-line-p)
(progn
(setq token (my-get-first-haskell-token)
line-count 1)
(forward-line)))
(while (<= (point) block-end)
(let ((current-token (my-get-first-haskell-token)))
(cond ((string= current-token "") ; line with indentation
(when (null token) (setq is-valid nil))
(setq line-count (+ 1 line-count)))
((or (string= (substring current-token 0 2) "--") ;; skip comments
(string= (substring current-token 0 2) "{-"))
'())
((and (my-haskell-declaration-line-p)
(or (null token) (string= token current-token)))
(setq token current-token
line-count (+ 1 line-count)))
(t (setq is-valid nil)
(goto-char (+ 1 block-end))))
(forward-line)))
(and is-valid (> line-count 1))))))

Emacs24 and python-mode: indention in docstrings

I have the following code/text:
def f():
"""
Return nothing.
.. NOTE::
First note line
second note line
In Emacs23 (23.4.1) I was able to press TAB in the last line ("second note line"; nomatter how this line was indented) and it was aligned correctly like this:
def f():
"""
Return nothing.
.. NOTE::
First note line
second note line
I.e., it uses the previous line and indents the following line in the same way.
Now in Emacs24 (24.3.1) this does not work anymore and it is aligned like this:
def f():
"""
Return nothing.
.. NOTE::
First note line
second note line
I.e. it aligns the multi-line string block, but does not depend on the previous line.
It affects only docstrings; code is indented as I want. I am using python-mode. How can I change this, so that pressing TAB aligns the block correctly?
Python mode has changed quite a bit between Emacs 23 and 24. There is no configuration that would allow you to do what you want.
But, Emacs is quite flexible and you can advise the (python-indent-context) function to make it return a different result that will lead to the behavior you want. The function (python-indent-context) returns a character at which the indentation is measured and used for indenting the current line. By default, when inside a string, it returns the point where the beginning of the string resides. Thus, your line will be indented to the indentation of the start of the string. We can easily modify it to return a point in the previous non-empty line instead, for instance like this:
(defun python-fake-indent-context (orig-fun &rest args)
(let ((res (apply orig-fun args))) ; Get the original result
(pcase res
(`(:inside-string . ,start) ; When inside a string
`(:inside-string . ,(save-excursion ; Find a point in previous non-empty line
(beginning-of-line)
(backward-sexp)
(point))))
(_ res)))) ; Otherwise, return the result as is
;; Add the advice
(advice-add 'python-indent-context :around #'python-fake-indent-context)
The same effect can be achieved using the old defadvice for older Emacs:
(defadvice python-indent-context (after python-fake-indent-context)
(pcase ad-return-value
(`(:inside-string . ,start) ; When inside a string
(setq ad-return-value ; Set return value
`(:inside-string . ,(save-excursion ; Find a point in previous non-empty line
(beginning-of-line)
(backward-sexp)
(point)))))))
(ad-activate 'python-indent-context)
What about editing the section de-stringified in a separate buffer? That would allow python-mode with all its facilities.
Here a first draft - original string will be stored in kill-ring:
(defun temp-edit-docstring ()
"Edit docstring in python-mode. "
(interactive "*")
(let ((orig (point))
(pps (parse-partial-sexp (point-min) (point))))
(when (nth 3 pps)
(let* (;; relative position in string
(relpos (- orig (+ 2 (nth 8 pps))))
(beg (progn (goto-char (nth 8 pps))
(skip-chars-forward (char-to-string (char-after)))(push-mark)(point)))
(end (progn (goto-char (nth 8 pps))
(forward-sexp)
(skip-chars-backward (char-to-string (char-before)))
(point)))
(docstring (buffer-substring beg end)))
(kill-region beg end)
(set-buffer (get-buffer-create "Edit docstring"))
(erase-buffer)
(switch-to-buffer (current-buffer))
(insert docstring)
(python-mode)
(goto-char relpos)))))
When ready, copy the contents back into original buffer.
Which remains to be implemented still.

Creating emacs mode: defining indentation

I'm writing a simple mode for a Lisp-like language, and am having trouble setting up indentation. I've been following the emacswiki mode tutorial.
However, I can't figure out how to adapt their example indentation to my needs because they don't do any form of counting.
Basically, I just need to add 2 spaces to my indentation count every time I see a { or (, even if there are multiple on the same line, and subtract 2 spaces when I see closures of the above. I'm new to elisp; how can I adapt their example to count braces and brackets?
For convenience, here is the code they are using (for a non-bracket language):
(defun wpdl-indent-line ()
"Indent current line as WPDL code"
(interactive)
(beginning-of-line)
(if (bobp) ; Check for rule 1
(indent-line-to 0)
(let ((not-indented t) cur-indent)
(if (looking-at "^[ \t]*END_") ; Check for rule 2
(progn
(save-excursion
(forward-line -1)
(setq cur-indent (- (current-indentation) default-tab-width)))
(if (< cur-indent 0)
(setq cur-indent 0)))
(save-excursion
(while not-indented
(forward-line -1)
(if (looking-at "^[ \t]*END_") ; Check for rule 3
(progn
(setq cur-indent (current-indentation))
(setq not-indented nil))
; Check for rule 4
(if (looking-at "^[ \t]*\\(PARTICIPANT\\|MODEL\\|APPLICATION\\|WORKFLOW\\|ACTIVITY\\|DATA\\|TOOL_LIST\\|TRANSITION\\)")
(progn
(setq cur-indent (+ (current-indentation) default-tab-width))
(setq not-indented nil))
(if (bobp) ; Check for rule 5
(setq not-indented nil)))))))
(if cur-indent
(indent-line-to cur-indent)
(indent-line-to 0))))) ; If we didn't see an indentation hint, then allow no indentation
How can I just implement lisp-like indentation (but also with curly braces)?
If you want something simple for a Lisp-style language, I suggest you start with (syntax-ppss) which returns the "parsing state" at point. The first element of that state is the current paren-nesting depth. While I used the word "paren", this doesn't really count parens but counts those chars which the syntax-table defines as paren-like, so if you set your syntax-table such that { and } are declared as paren-like, then those will also be counted.
So you could start with something like
(defun foo-indent-function ()
(save-excursion
(beginning-of-line)
(indent-line-to (* 2 (car (syntax-ppss))))))
Do not define this as interactive, since the way to use it is by adding
(set (make-local-variable 'indent-line-function) #'foo-indent-function)
in your major-mode function.
But maybe a better option is to simply do:
(require 'smie)
...
(define-derived-mode foo-mode "Foo"
...
(smie-setup nil #'ignore)
...)
This will use an indentation step of 4 (configured in smie-indent-basic).

Customize Elisp plist indentation

I don't like how plists are indented in Elisp.
;; current desired Python (for comparison)
;; '(a 1 '(a 1 {'a': 1,
;; b 2 b 2 'b': 2,
;; c 3) c 3) 'c': 3}
Tried on M-x emacs-version 24.3.1, ran emacs -Q, typed the plist and pressed C-x h C-M-\.
This indentation makes sense when it isn't a list:
(mapcar (lambda (x) (x + 1))
'(1 2 3 4))
How do I change formatting settings so that only plists (or, if that's impossible, all quoted lists) have the desired rectangular indentation, but indentation of everything else stays the same? I need this stored locally in an .el file, so that when I edit this file, it is indented as desired, but this behavior doesn't end up anywhere else.
Found it:
(setq lisp-indent-function 'common-lisp-indent-function)
Here's a sample file:
(setq x '(a 1
b 2
c 3))
;;; Local Variables:
;;; lisp-indent-function: common-lisp-indent-function
;;; End:
I'll just dump my whole indentation config here:
(setq lisp-indent-function 'common-lisp-indent-function)
(put 'cl-flet 'common-lisp-indent-function
(get 'flet 'common-lisp-indent-function))
(put 'cl-labels 'common-lisp-indent-function
(get 'labels 'common-lisp-indent-function))
(put 'if 'common-lisp-indent-function 2)
(put 'dotimes-protect 'common-lisp-indent-function
(get 'when 'common-lisp-indent-function))
You can fix this (in my opinion) bug by overriding lisp-indent-function. The original source of the hack was this Github Gist, which was referenced with some more explanation from this Emacs Stack Exchange answer.
However, I was very uncomfortable overriding a core function like this. For one, it's very opaque—how is a reader supposed to tell what is changed? And worse—what if the official definition of lisp-indent-function changed in the future? How would I know that I needed to update my hack?
As a response, I created the library el-patch, which is specifically designed to address this problem. After installing the package, you can override lisp-indent-function as follows:
(el-patch-defun lisp-indent-function (indent-point state)
"This function is the normal value of the variable `lisp-indent-function'.
The function `calculate-lisp-indent' calls this to determine
if the arguments of a Lisp function call should be indented specially.
INDENT-POINT is the position at which the line being indented begins.
Point is located at the point to indent under (for default indentation);
STATE is the `parse-partial-sexp' state for that position.
If the current line is in a call to a Lisp function that has a non-nil
property `lisp-indent-function' (or the deprecated `lisp-indent-hook'),
it specifies how to indent. The property value can be:
* `defun', meaning indent `defun'-style
(this is also the case if there is no property and the function
has a name that begins with \"def\", and three or more arguments);
* an integer N, meaning indent the first N arguments specially
(like ordinary function arguments), and then indent any further
arguments like a body;
* a function to call that returns the indentation (or nil).
`lisp-indent-function' calls this function with the same two arguments
that it itself received.
This function returns either the indentation to use, or nil if the
Lisp function does not specify a special indentation."
(el-patch-let (($cond (and (elt state 2)
(el-patch-wrap 1 1
(or (not (looking-at "\\sw\\|\\s_"))
(looking-at ":")))))
($then (progn
(if (not (> (save-excursion (forward-line 1) (point))
calculate-lisp-indent-last-sexp))
(progn (goto-char calculate-lisp-indent-last-sexp)
(beginning-of-line)
(parse-partial-sexp (point)
calculate-lisp-indent-last-sexp 0 t)))
;; Indent under the list or under the first sexp on the same
;; line as calculate-lisp-indent-last-sexp. Note that first
;; thing on that line has to be complete sexp since we are
;; inside the innermost containing sexp.
(backward-prefix-chars)
(current-column)))
($else (let ((function (buffer-substring (point)
(progn (forward-sexp 1) (point))))
method)
(setq method (or (function-get (intern-soft function)
'lisp-indent-function)
(get (intern-soft function) 'lisp-indent-hook)))
(cond ((or (eq method 'defun)
(and (null method)
(> (length function) 3)
(string-match "\\`def" function)))
(lisp-indent-defform state indent-point))
((integerp method)
(lisp-indent-specform method state
indent-point normal-indent))
(method
(funcall method indent-point state))))))
(let ((normal-indent (current-column))
(el-patch-add
(orig-point (point))))
(goto-char (1+ (elt state 1)))
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
(el-patch-swap
(if $cond
;; car of form doesn't seem to be a symbol
$then
$else)
(cond
;; car of form doesn't seem to be a symbol, or is a keyword
($cond $then)
((and (save-excursion
(goto-char indent-point)
(skip-syntax-forward " ")
(not (looking-at ":")))
(save-excursion
(goto-char orig-point)
(looking-at ":")))
(save-excursion
(goto-char (+ 2 (elt state 1)))
(current-column)))
(t $else))))))
Here is another less heavyweight solution, based on emacsql-fix-vector-indentation. An advice around calculate-lisp-indent is sufficient.
This only works for plists that use keywords as keys, but that covers a majority of plists. To make this work on quoted lists instead, you could change the looking-at regexp to detect the ' or "`", but that will not cover, say, a nested list.
This can further be packaged up into a minor mode if there is a need to turn it off.
(defun my/inside-plist? ()
"Is point situated inside a plist?
We determine a plist to be a list that starts with a keyword."
(let ((start (point)))
(save-excursion
(beginning-of-defun)
(let ((sexp (nth 1 (parse-partial-sexp (point) start))))
(when sexp
(setf (point) sexp)
(looking-at (rx "(" (* (syntax whitespace)) ":")))))))
(define-advice calculate-lisp-indent (:around (func &rest args)
plist)
(if (save-excursion
(beginning-of-line)
(my/inside-plist?))
(let ((lisp-indent-offset 1))
(apply func args))
(apply func args)))

How to switch the point to previous line after a } was input?

I am working with emacs24 with cc-mode, I want to know how to make my emacs more "clever". After I type a }, it will auto insert a new line and indent as excepted. I want to know how to switch the point to previous line.
For example, when i define a function, Now my emacs behavior is:
void f()
{
}
//point
"//point" is the position of cursor after } was input.
But i want is this:
void f()
{
//point
}
I hope the position of cursor can switch to previous line and indent automatically.
I know emacs can do this, but I don't know how to do it, who can help me?
I think you are after these.. C-M-u, C-M-d, C-M-f and C-M-b
Practice a bit... They are kind of global and they do behave contextually in almost all modes..
UPDATE:
ohh.. It seems you want to place the cursor automatically.. actually in more general Emacs will help you not to type } at all. I mean emacs can insert closing paran automatically.
There is inbuilt one
electric pair mode
third party
autopair.el
I don't trust anything electric, so I wrote this function.
(defconst insert-logical-brackets-logical-bracket-begin "{")
(defconst insert-logical-brackets-logical-bracket-end "}")
(defconst insert-logical-brackets-default-style 0)
(make-variable-buffer-local 'logical-bracket-begin)
(make-variable-buffer-local 'logical-bracket-end)
(make-variable-buffer-local 'insert-logical-brackets-default-style)
(defun insert-logical-brackets(&optional style)
"If STYLE = 0(default, according to `insert-logical-brackets-default-style' value), make a newline before opening bracket, if line is not empty. Make a newline after closing bracket, if there is something after this bracket. Make two newlines in the middle.
If STYLE = 1, don't make newlines before opening a bracket(one of c styles).
If STYLE = 2, don't make newlines before opening and after closing bracket.
If STYLE = 3, allways make all newlines.
If STYLE is not nil, don't make newlines between brackets(still makes before/after lines)."
(interactive "P")
(when (eq style nil)
(setq style insert-logical-brackets-default-style))
(funcall indent-line-function)
(unless (or (eq 1 style) (eq 2 style))
(when (or (/= (point) (save-excursion (back-to-indentation) (point))) (eq 3 style))
(newline)
(funcall indent-line-function)))
(unless (and (integerp style) (= 2 style))
(when (or (not (looking-at "\n")) (eq 3 style))
(newline)
(funcall indent-line-function)
(forward-line -1)
(goto-char (point-at-eol))))
(insert logical-bracket-begin)
(funcall indent-line-function)
(let ((return-point (point)))
(when (or (not style) (or (eq 0 style) (eq 1 style) (eq 2 style) (eq 3 style)))
(newline)
(funcall indent-line-function)
(setq return-point (point))
(newline))
(insert logical-bracket-end)
(funcall indent-line-function)
(goto-char return-point)))
Take a look at template systems like yasnippet: http://www.emacswiki.org/emacs/CategoryTemplates
auto-indent-mode maybe what you want!