4

在大多数现代编辑器中,您可以突出显示一段代码并缩进或取消缩进一个制表符或您正在使用的许多空格,这是标准的;你如何在emacs中做到这一点?

因此,例如我刚刚打开了 sublime text,突出显示了以下代码:

variation1 person phoneMap carrierMap addressMap =
    case M.lookup person phoneMap of
      Nothing -> Nothing
      Just number ->
          case M.lookup number carrierMap of
            Nothing -> Nothing
            Just carrier -> M.lookup carrier addressMap

然后按下标签并得到

  variation1 person phoneMap carrierMap addressMap =
      case M.lookup person phoneMap of
        Nothing -> Nothing
        Just number ->
            case M.lookup number carrierMap of
              Nothing -> Nothing
              Just carrier -> M.lookup carrier addressMap

该代码上的一个 shift-tab 将其返回到原来的位置,如果我继续按 shift-tab,我最终会得到以下信息:

variation1 person phoneMap carrierMap addressMap =
case M.lookup person phoneMap of
Nothing -> Nothing
Just number ->
case M.lookup number carrierMap of
Nothing -> Nothing
Just carrier -> M.lookup carrier addressMap

引用另一个回复:

emacs 语言模式实际上并没有“进一步缩进此块 1 选项卡”的概念。相反,他们非常固执己见,并且有“这是正确的缩进”的概念,这就是您在语言模式下点击制表符时所得到的。

除非我使用以下代码执行此操作(haskell 模式和 ghc mod 已启用):

import Monad
import System
import IO
import Random
import Control.Monad.State

type RandomState a = State StdGen a
data CountedRandom = CountedRandom {
      crGen :: StdGen
    , crCount :: Int
    }

type CRState = State CountedRandom

getRandom :: Random a => RandomState a
getRandom =
  get >>= \gen ->
  let (val, gen') = random gen in
  put gen' >>
  return val  

我得到以下信息:

import Monad
  import System
  import IO
  import Random
  import Control.Monad.State

type RandomState a = State StdGen a
data CountedRandom = CountedRandom {
  crGen :: StdGen
  , crCount :: Int
  }

type CRState = State CountedRandom

               getRandom :: Random a => RandomState a
               getRandom =
  get >>= \gen ->
  let (val, gen') = random gen in
  put gen' >>
  return val  

当我想要

import Monad
import System
import IO
import Random
import Control.Monad.State

type RandomState a = State StdGen a
data CountedRandom = CountedRandom {
      crGen :: StdGen
    , crCount :: Int
    }

type CRState = State CountedRandom

getRandom :: Random a => RandomState a
getRandom =
  get >>= \gen ->
    let (val, gen') = random gen in
    put gen' >>
    return val  

足够接近来自ataylor的解决方案:

(defcustom tab-shift-width 4
  "Sets selected text shift width on tab"
  :type 'integer)
(make-variable-buffer-local 'tab-shift-width)

(global-set-key 
 (kbd "<tab>")
 (lambda (start end)
   (interactive "r")
   (if (use-region-p)
       (save-excursion
     (let ((deactivate-mark nil))
       (indent-rigidly start end tab-shift-width)))
     (indent-for-tab-command))))

(global-set-key 
 (kbd "S-<tab>")
 (lambda (start end)
   (interactive "r")
   (if (use-region-p)
       (save-excursion
     (let ((deactivate-mark nil))
       (indent-rigidly start end (- tab-shift-width))))
     (indent-for-tab-command))))

如果 emacs 支持缩进检测(即,只获取某个变量的值),那就太好了;我发现与此最接近的是一个名为 dtrt indent 的插件,但它不适用于 Haskell。

4

4 回答 4

2

indent-region将根据当前模式重新缩进一段文本。

要强制添加缩进级别,您可以使用string-rectangle,它会提示您输入字符串。在这里,您可以提供缩进级别的字符串(例如制表符、4 个空格等)。该字符串将插入当前选定区域的每一行,在当前列中,有效地缩进它。或者,您可以从 获得类似的效果open-rectangle,它将空白插入矩形中,角由点和标记定义。

另一种强制缩进的方法是调用indent-rigidly( C-x TAB)。这会覆盖特定于模式的缩进规则并缩进固定数量。数字参数指定缩进多少,负参数将取消缩进。如果您希望这是选择区域时的默认行为,您可以执行以下操作:

(global-set-key 
 (kbd "<tab>")
 (lambda (start end)
   (interactive "r")
   (if (use-region-p)
       (save-excursion
     (let ((deactivate-mark nil))
       (indent-rigidly start end 4)))
     (indent-for-tab-command))))
于 2012-05-07T19:32:32.373 回答
2

Haskell 代码很难正确缩进,因为一段代码有多个“正确”的缩进。

haskell-mode它有一个非常具体的行格式,它希望你遵循(如,你必须在正确的地方换行),它有一些缩进规则来格式化与该行格式匹配的代码。存在这些规则是为了使自动缩进结果更加一致。规则大致是这样的:

  • 在每个引入块的关键字之后,您应该换行或确保整个块适合布局。否则,你会得到很多像在你的getRandom例子中一样的悬挂块
  • 所有块都缩进两个空格。这包括模块块;如果这样做module Bla where,则该行之后的整个部分将缩进。这意味着您应该保留默认的 Haskell 模块文件格式以使缩进顺序生效。
  • 行的缩进需要尽可能明确;如果一条线根据其缩进可能意味着不同的东西,它将导致它被缩进到haskell-mode认为在上下文中有意义的位置。在某些情况下,解决此问题是不可能的。

因为不可能将 Haskell 代码结构化以使其满足 的要求haskell-mode,所以您不能像这样缩进一段时间的 Haskell 代码文件。您只需要在本地使用自动缩进。这可以通过多种方式完成:

  • 当您在一行时,您可以通过按 将当前行缩进到相对于前一行而言最可能“正确”的位置TAB。通过TAB再次按下,您将把行带到“下一个”缩进级别,并不断循环通过所有可能的逻辑缩进步骤。
  • 如果您选择在本地找到的一系列块(函数体等)并使用M-x indent-region,则结果很可能是正确的。

在这种情况下,我通常会从具有“错误”缩进的行开始,按TAB一次,然后逐行向下,在每行上按TAB一次或多次,直到该行的缩进为正确的。当前行的当前“逻辑缩进位置”是根据前面的代码上下文计算的,因此从顶部更正缩进几乎总是会产生正确的结果。

于 2012-05-08T00:10:54.567 回答
0

我突出显示该区域并点击C-M-\. 在多行缩进页面indent-region中可以找到更多乐趣。

于 2012-05-07T19:23:30.287 回答
0

emacs 语言模式实际上并没有“进一步缩进此块 1 选项卡”的概念。相反,他们非常固执己见,并且有“这是正确的缩进”的概念,这就是您在语言模式下点击制表符时所得到的。

一旦你习惯了它,其他任何事情都会显得很奇怪。在您的 Haskell 代码中,这些 case 语句实际上只有一个有效的缩进,除非您添加大括号和分号,否则其他任何内容都是语法错误。如果您真的想自定义 emacs 认为“正确”的缩进,请查看如何自定义您的模式。许多语言模式重用 c-mode 变量,所以这里可能是一个不错的起点(虽然我不确定 Haskell 模式是做什么的,但我从未发现需要自定义它)。

编辑:我在您的评论中看到您的麻烦来自没有安装 Haskell 模式,请到 github 页面获取它。

于 2012-05-07T19:32:25.187 回答