8

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

Tyler
  • 9,872
  • 2
  • 33
  • 57
pnj
  • 83
  • 4

1 Answers1

5

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]%")))))))))))
Tyler
  • 9,872
  • 2
  • 33
  • 57
  • [`defadvice`](http://www.gnu.org/software/emacs/elisp/html_node/Advising-Functions.html) might be cleaner alternative here. – jfs Nov 16 '11 at 19:51
  • Tyler, I copied your code into my .emacs, but the behavior is unchanged. No errors or anything obvious in my *Messages* buffer. Any further suggestions or things I can do to help diagnose? – pnj Dec 12 '11 at 19:40
  • if you add a doc-string to the redefined function, you can check to see that it has loaded with `C-h f ess-continued-statement-p`. If you don't see the doc-string, the modified code isn't getting evaluated. That would indicate there's something run with the `eval-after-load` command, such as the wrong mode being cited. I'll add a doc-string above. – Tyler Dec 12 '11 at 21:00
  • `describe-function ess-continued-statement-p` returns with `ess-continued-statement-p is a compiled Lisp function in ess-mode. not documented`. – pnj Dec 15 '11 at 01:27
  • FYI, I notice when I load a file in this mode, I get an error message `File mode specification error: (void-function run-mode-hooks)`. This happened even without inserting the above code into my .emacs. I interpret it as being a version issue, but could this explain why the overridden function isn't called? – pnj Dec 15 '11 at 01:31
  • Yes, it sounds like you need to update your Emacs, ESS, or probably both. I believe `run-mode-hooks` was introduced in Emacs 22 (released in 2007), and a fix for your problem was added to ESS version 5.3.11 (released in 2009). Your software is getting old! – Tyler Dec 15 '11 at 17:23
  • Interesting. Unfortunately I don't have permission to install this myself; hopefully can convince the admins... Thanks again! – pnj Dec 21 '11 at 18:48
  • You can install the latest version of ESS into your home directory without administrator privileges. In a nutshell, download ESS from their website, unpack it somewhere convenient (like ~/ess/), and add the following line to your .emacs: (load "~/ess/ess-VERSION/lisp/ess-site"), where ess-VERSION is replaced by the actual version directory found in ~/ess/. – Tyler Dec 21 '11 at 19:03
  • Yes! With emacs 23.3.1 and ESS 5.14, the problem persists; however, the lisp function above (ess-continued-statement-p) corrects the problem. Thank you! It is amazing to have correctly tabbed code again. – pnj Dec 27 '11 at 20:55