19

在这里完成emacs新手。

我在 Ubuntu 上使用 emacs 23.1.1 和emacs starter kit。我主要在 lua 模式下工作(安装时package-install lua-mode)。

我需要调整缩进的工作方式,使其符合我的编码指南。

指导方针是:

  • 制表符到空格;
  • 每个缩进两个空格;
  • 每行最多 80 个字符,没有尾随空格。

例子:

本地 foo = 函数()
  print("你好,世界!")
结尾

如果我不尝试与它的自动缩进抗争,我会从 emacs 得到什么:

本地 foo = 函数()
               打印(“你好,世界”)
结尾

更新:

(这属于评论,但由于它需要额外的格式,我必须把它放在这里。)

如果我尝试 Thomas 的解决方案,我会得到:

本地 foo = 函数()
               打印(“你好,世界”)
        结尾

请注意,它使用制表符和四个空格end缩进。不太行...

更新 2:

这件事也以错误的方式缩进:

本地酒吧 = foo(
    “一”,
    “二”,
   baz(), -- 注意三个空格
   “现状”
)  

它应该是:

本地酒吧 = foo(
    “一”,
    “二”,
    巴兹(),
    “现状”
  )

更新 3:

缩进错误的第三种情况:

本地酒吧 = foo(
    “一”,
    “二”
  )

  local t = 5 -- 此行不应缩进,
              -- 还要注意 local 和 t 之间的选项卡。

更新 4:

这是我从 Thomas 的当前版本中得到的:

本地 foo = 函数()
               打印(“你好,世界”)
        结尾

            local bar = 5 -- Emacs 把 \t 放在 5 之前

            local zzz = foo( -- Emacs 把 \t 放在 foo 之前
                "one", -- 在此处按 TAB 两次
                “二”,
               三(),
               “四”
            )

除非明确指出,我没有对缩进做任何事情,只输入代码并RETURN在每一行的末尾按下。我实际上没有输入任何评论。

它应该如下所示:

本地 foo = 函数()
  打印(“你好,世界”)
结尾

当地酒吧 = 5

本地 zzz = foo(
    “一”,
    “二”,
    三(),
    “四”
  )

更新 5:

还有一种错误的缩进情况:

本地富=
{
酒吧(); -- 在这里按了一个 TAB,但右括号杀死了它
巴兹;
}

应该:

本地富=
{
  酒吧();
  巴兹;
}

更新 6:

为了完整起见,这是我使用当前 Git HEAD 的 lua-mode得到的,没有 Thomas 的配置调整:

本地 foo = 函数()
               print("你好,世界!")
            结尾

当地酒吧 = 5

本地 foo = bar(
酒吧,
   巴兹(),
   现状(),
啊啊啊
)

本地 t =
{
“一”,
二(),
}

带调音:

本地 foo = 函数()
           print("你好,世界!")
            结尾

            当地酒吧 = 5

            本地 foo = bar(
            酒吧,
               巴兹(),
               现状(),
               啊啊啊
            )

            本地 t =
            {
            “一”,
            二(),
         }

为了符合我的编码指南,它应该如下所示:

本地 foo = 函数()
  print("你好,世界!")
结尾

当地酒吧 = 5

本地 foo = bar(
    酒吧,
    巴兹(),
    现状(),
    啊啊啊
  )

本地 t =
{
  “一”,
  二(),
}
4

7 回答 7

9

好吧,让我们再试一次......浏览了lua-mode的源代码后,我想出了以下方法。

公认奇怪的默认缩进的原因是一个名为“lua-calculate-indentation”的函数,它计算当前行缩进到的列。不幸的是,它返回的值与您所需的规范不匹配。

例如,如果你在一个新的 .lua 文件中输入一行,如下所示:

local foo = function()

并按回车键将点移动到第二行,您可以通过键入来调用上述函数M-: (lua-calculate-indentation)。结果是 15,这意味着 lua-mode 会将第二个缩进到第 15 列。这就是您在原始问题中描述和举例说明的非正统缩进的原因。

现在,为了解决这个问题,我建议重新定义函数“lua-calculate-indentation”,以便它返回你想要的缩进。为此,将以下代码放入一个空文件中,并将其以名称“my-lua.el”保存在“lua-mode.el”所在的同一目录中。

;; use an indentation width of two spaces
(setq lua-indent-level 2)

;; Add dangling '(', remove '='
(setq lua-cont-eol-regexp
      (eval-when-compile
        (concat
         "\\((\\|\\_<"
         (regexp-opt '("and" "or" "not" "in" "for" "while"
                       "local" "function") t)
         "\\_>\\|"
         "\\(^\\|[^" lua-operator-class "]\\)"
         (regexp-opt '("+" "-" "*" "/" "^" ".." "==" "<" ">" "<=" ">=" "~=") t)
         "\\)"
         "\\s *\\=")))

(defun lua-calculate-indentation (&optional parse-start)
  "Overwrites the default lua-mode function that calculates the
column to which the current line should be indented to."
  (save-excursion
    (when parse-start
      (goto-char parse-start))

    ;; We calculate the indentation column depending on the previous
    ;; non-blank, non-comment code line. Also, when the current line
    ;; is a continuation of that previous line, we add one additional
    ;; unit of indentation.
    (+ (if (lua-is-continuing-statement-p) lua-indent-level 0)
       (if (lua-goto-nonblank-previous-line)
           (+ (current-indentation) (lua-calculate-indentation-right-shift-next))
         0))))

(defun lua-calculate-indentation-right-shift-next (&optional parse-start)
  "Assuming that the next code line is not a block ending line,
this function returns the column offset that line should be
indented to with respect to the current line."
  (let ((eol)
        (token)
        (token-info)
        (shift 0))
    (save-excursion
      (when parse-start
        (goto-char parse-start))

      ; count the balance of block-opening and block-closing tokens
      ; from the beginning to the end of this line.
      (setq eol (line-end-position))
      (beginning-of-line)
      (while (and (lua-find-regexp 'forward lua-indentation-modifier-regexp)
                  (<= (point) eol)
                  (setq token (match-string 0))
                  (setq token-info (assoc token lua-block-token-alist)))
        ; we found a token. Now, is it an opening or closing token?
        (if (eq (nth 2 token-info) 'open)
            (setq shift (+ shift lua-indent-level))
          (when (or (> shift 0)
                    (string= token ")"))
            (setq shift (- shift lua-indent-level))))))
    shift))

这段代码将缩进级别设置为两个空格(而不是 3),修改了一个正则表达式来检测语句是否跨越多行,最后使用辅助重新定义缩进函数。

剩下要做的就是确保实际加载了此代码。这必须在加载原始 lua 模式之后发生,否则该代码将重新安装原始缩进功能。

我们这样做的方式有点 hacky:我们安装了一个回调函数,每次缓冲区将其主模式更改为 lua 模式时都会调用该函数。然后它检查是否定义了前面提到的辅助函数——如果没有,它加载“my-lua.el”。这有点脆弱,但只要你不玩 lua 源代码,你应该没问题。

将以下行添加到您的 ~/emacs.d/agladysh.el 文件中(假设“agladysh”是您的用户名):

(add-hook 'lua-mode-hook 
          (lambda () (unless (fboundp 'lua-calculate-indentation-right-shift-next)
                       (load-file (locate-file "my-lua.el" load-path)))))

我假设 lua-mode 在您的加载路径上,如果您遵循 lua-mode 的安装说明,它应该是。

我希望这次它对你有用,如果没有,请告诉我。

于 2011-01-10T22:04:16.127 回答
4

我知道这个问题已经有一段时间了,但我只是想指出这仍然是一个问题,通过 Emacs 包系统安装了 lua-mode。

但是, GitHub 上的最新版本运行良好,没有发现任何缩进怪异。为了符合Lua 风格指南,你所要做的就是设置indent-tabs-modetonillua-indent-levelto 2

于 2013-06-09T10:45:08.773 回答
2

如果您将以下代码输入到.emacs您的主目录中的文件中,它将使 lua-mode(并且只有 lua-mode)的行为方式如下:

  • 如果按 ENTER,将插入一个换行符,默认情况下下一行将像上一行一样缩进。
  • 每当您按 TAB 缩进该行时,point 或者跳转到该行的第一个非空白字符,或者,如果该行是空的 point 已经在该字符处,则插入两个空格。

尤其是后者可能不是您想要的,但可能是第一个近似值。

(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)

重新启动 Emacs 以使这些更改生效。

于 2011-01-10T10:02:47.173 回答
1

2019 年以两个lua-indent-变量的形式添加了一种更简洁的方法。这让我们几乎到了那里,但由于某种原因它仍然使嵌套块双缩进。添加一点建议技巧即可完成工作。

(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)
于 2021-04-20T10:18:38.013 回答
0

我是 lua-mode.el 的维护者(但不是作者)。由于我在 Emacs Lisp 方面的流利程度远低于该线程的其他贡献者,因此我欢迎使用补丁。我只想指出,默认规则没有什么奇怪或不正确的:据我所知,这个想法只是当你在一个匿名函数中时,缩进应该将 function 关键字作为它的左边距。当您考虑在其他地方使用函数表达式时,这很有意义,例如作为函数参数。

所以,一个简单的解决方法是不要写

局部 f = 函数...

局部函数...

除非您正在使用早于“本地函数”语法的 Lua 版本。

话虽如此,我明白为什么你可能想要不同的缩进。在这种情况下,我觉得有一个配置变量 lua-indent-function-from-function-keyword 是合理的(更好的名字,有人吗?),我很乐意接受一个实现它的补丁。

于 2011-01-11T15:08:48.797 回答
0

我现在帮不上什么忙 - 我有两天的最后期限 8-( - 但这是我在 .emacs 中用来使 lua-mode 对我有用的东西......

(setq lua-indent-level 2)
(setq lua-electric-flag nil)
(defun lua-abbrev-mode-off () (abbrev-mode 0))
(add-hook 'lua-mode-hook 'lua-abbrev-mode-off)
(setq save-abbrevs nil)   ;; is this still needed?

我以一种不寻常的方式缩进我的代码 - 请参见下面的示例 - 所以我已经训练自己只在 lua-mode 可以从上面的行中正确推断出正确的缩进时才按 TAB ......

map = function (f, A, n)
    local B = {}                 -- TAB here doesn't work
    for i=1,(n or #A) do         -- TAB here works
      table.insert(B, f(A[i]))   -- TAB here works
    end                          -- TAB here works
    return B                     -- TAB here works
  end                            -- TAB here works
于 2011-01-10T14:27:57.630 回答
-1

我认为你正在寻找的很多东西都可以在emacs 手册中找到自定义 C 缩进定义,它属于一般缩进引擎描述。

你可以让它做任何你能想象的事情,这比做任何你想象的事情要好得多。

于 2011-01-10T02:59:46.070 回答