Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure indentation in emacs lua-mode?

Complete emacs newbie here.

I'm using emacs 23.1.1 on Ubuntu with emacs starter kit. I primarily work in the lua-mode (installed with package-install lua-mode).

I need to tune how indentation works, so it would match my coding guidelines.

The guidelines are:

  • tabs-to-spaces;
  • two spaces per indent;
  • 80 chars per line maximum, without trailing spaces.

Example:

local foo = function()
  print("Hello, world!")
end

What I get with emacs if I don't try to fight with its auto-indent:

local foo = function()
               print("Hello, world")
end

Update:

(This belongs to a comment, but since it needs extra formatting, I have to place it here.)

If I try solution by Thomas, I get this:

local foo = function()
               print("Hello, world")
        end

Note that end is indented with a tab and four spaces. Does not quite work...

Update 2:

This thing is also gets indented in the wrong way:

local bar = foo(
    "one",
    "two",
   baz(), -- Note three spaces
   "quo"
)  

It should be:

local bar = foo(
    "one",
    "two",
    baz(),
    "quo"
  )

Update 3:

Third case of the wrong indentation:

local bar = foo(
    "one",
    "two"
  )

  local t = 5 -- This line should not be indented, 
              -- also note tab between local and t.

Update 4:

Here is what I get with the current version from Thomas:

local foo = function()
               print("Hello, world")
        end

            local bar = 5 -- Emacs put \t before 5

            local zzz = foo( -- Emacs put \t before foo
                "one", -- Pressed TAB here twice
                "two",
               three(),
               "four"
            )

Except where explicitly noted, I did not do anything for indentation, only typed in the code and pressed RETURN at the end of each line. I did not actually type any comments.

It should look as follows:

local foo = function()
  print("Hello, world")
end

local bar = 5

local zzz = foo(
    "one",
    "two",
    three(),
    "four"
  )

Update 5:

One more wrong indentation case:

local foo =
{
bar(); -- Did press a TAB here, but closing brace killed it
baz;
}

Should be:

local foo =
{
  bar();
  baz;
}

Update 6:

For the sake of completeness, here is what I get with the current Git HEAD of lua-mode, without Thomas's configuration tuning:

local foo = function()
               print("Hello, world!")
            end

local bar = 5

local foo = bar(
bar,
   baz(),
   quo(),
aaa
)

local t =
{
"one",
two(),
}

With tuning:

local foo = function()
           print("Hello, world!")
            end

            local bar = 5

            local foo = bar(
            bar,
               baz(),
               quo(),
               aaa
            )

            local t =
            {
            "one",
            two(),
         }

To match my coding guidelines, it should look as follows:

local foo = function()
  print("Hello, world!")
end

local bar = 5

local foo = bar(
    bar,
    baz(),
    quo(),
    aaa
  )

local t =
{
  "one",
  two(),
}
like image 932
Alexander Gladysh Avatar asked Jan 10 '11 02:01

Alexander Gladysh


3 Answers

If you enter the following code into .emacs file in your home directory, it will make lua-mode (and only lua-mode) behave the following way:

  • If you press ENTER, a newline will be inserted and by default the next line will be indented like the previous line.
  • Whenever you press TAB to indent the line, point either jumps to the first non-whitespace character of the line or, if the line is empty of point is already at that character, two spaces are inserted.

Especially the latter may not be what you want, but perhaps its a first approximation.

(defvar my-lua-indent 2
  "The number of spaces to insert for indentation")

(defun my-lua-enter ()
  "Inserts a newline and indents the line like the previous
non-empty line."
  (interactive)
  (newline)
  (indent-relative-maybe))

(defun my-lua-indent ()
  "Moves point to the first non-whitespace character of the
line if it is left of it. If point is already at that
position, or if it is at the beginning of an empty line,
inserts two spaces at point."
  (interactive)
  (when (looking-back "^\\s *")
    (if (looking-at "[\t ]")
        (progn (back-to-indentation)
               (when (looking-at "$")
                 (kill-line 0)
                 (indent-relative-maybe)
                 (insert (make-string my-lua-indent ? ))))
      (insert (make-string my-lua-indent ? )))))

(defun my-lua-setup ()
  "Binds ENTER to my-lua-enter and configures indentation the way
I want it. Makes sure spaces are used for indentation, not tabs."
  (setq indent-tabs-mode nil)
  (local-set-key "\r" 'my-lua-enter)
  (setq indent-line-function 'my-lua-indent))

;; add `my-lua-setup' as a call-back that is invoked whenever lua-mode
;; is activated.
(add-hook 'lua-mode-hook 'my-lua-setup)

Restart Emacs for these changes to take effect.

like image 166
Thomas Avatar answered Nov 03 '22 16:11

Thomas


I know it's been a while since this was asked, but I just wanted to point out that this is still an issue, with lua-mode installed via the Emacs package system.

However, the latest version on GitHub works very well, didn't notice any indentation weirdness. All you have to do to conform with the Lua style guide is to set indent-tabs-mode to nil and lua-indent-level to 2.

like image 25
fhd Avatar answered Nov 03 '22 15:11

fhd


A cleaner way to do this was added in 2019, in the form of two lua-indent- variables. This gets us almost there, but it still double-indents nested blocks for some reason. Adding a little advice hack finishes the job.

(setq lua-indent-nested-block-content-align nil)
(setq lua-indent-close-paren-align nil)

(defun lua-at-most-one-indent (old-function &rest arguments)
  (let ((old-res (apply old-function arguments)))
    (if (> old-res lua-indent-level) lua-indent-level old-res)))

(advice-add #'lua-calculate-indentation-block-modifier
            :around #'lua-at-most-one-indent)
like image 1
tommaisey Avatar answered Nov 03 '22 17:11

tommaisey