Existe um pacote ou modo de alinhamento automático para o Emacs?

15

Há momentos em que estou editando arquivos (manifestos do Puppet, por exemplo) em que desejo alinhar o conteúdo do buffer rapidamente. Por exemplo, eu sei que posso usar align-regexpou alignalinhar códigos como este, desde que eu tenha selecionado:

# M-x align-regexp "=>" will line everything up nicely 
file { "/etc/foo":
  ensure => present,
  mode => "0666",
  source => "puppet:///modules/example/foo",
}

Mas o que eu realmente quero é que isso aconteça rapidamente - sem ter que selecionar uma região ou todo o buffer. Existe um pacote ou modo que fará isso ou algo que precisaria ser incorporado ao modo em que estou interessado?

Edit: perguntei sobre o Puppet e o CFEngine, já que é o que eu codifico na maioria dos dias atualmente e tenho uma forte preferência pelo texto alinhado. No entanto, também fiquei curioso (e não expressei isso muito bem) em saber se o alinhamento rápido é um recurso comum nos modos Emacs (principalmente nos modos de linguagens de programação) ou se a maioria das pessoas se alinha ao salvar ou em algum momento outro ponto

Saint Aardvark, o Carpete
fonte
região de expansão , que é útil para selecionar escopos sucessivamente maiores.
bastibe
11
Você pode descrever mais sobre o que você costuma alinhar? São apenas sinais de igual e no modo fantoche? Você pode modificar o código nesta resposta do Emacs SE para identificação automática por @Malabarba para obter o que deseja. Simplesmente substitua indent-regionpor align-to-equalse defina esta função como (defun align-to-equals (begin end) (interactive "r") (align-regexp begin end "\\(\\s-*\\)=" 1 1 nil)); e emacs-lisp-mode-hookcom puppet-mode-hook.
precisa

Respostas:

5

Se você deseja marcar uma região para alinhamento automático, provavelmente não é muito difícil fazer algo como:

(require 'cl-lib)

(defvar my--auto-align-overlays nil)
(make-variable-buffer-local 'my--auto-align-overlays)

(defun my-auto-align (beg end regexp)
  (interactive "r\nsRegexp: ")
  (let ((ol (make-overlay beg end)))
    (overlay-put ol 'evaporate t)
    (overlay-put ol 'my--auto-align-regexp regexp)
    (overlay-put ol 'modification-hooks '(my--auto-align-function))
    (push ol my--auto-align-overlays)
    (add-hook 'post-command-hook 'my--auto-align-pch nil t)))

(defun my--auto-align-function (ol &rest _args)
  (cl-pushnew ol my--auto-align-overlays)
  (add-hook 'post-command-hook 'my--auto-align-pch nil t))

(defun my--auto-align-pch ()
  (dolist (ol my--auto-align-overlays)
    (align-regexp (overlay-start ol) (overlay-end ol)
                  (concat "\\(\\s-*\\)" (overlay-get ol 'my--auto-align-regexp))
                  1 align-default-spacing))
  (setq my--auto-align-overlays nil)
  (remove-hook 'post-command-hook 'my--auto-align-pch))

Mas se você quiser que seja totalmente automático, precisará encontrar uma maneira de caracterizar quais regiões deseja alinhar automaticamente (e com qual regexp), o que é mais difícil. Eu acho que você poderia fornecer alguns regexps e, em seguida, varrer o buffer em busca de linhas consecutivas que correspondam a um desses regexps.

Stefan
fonte
Eu não usei sobreposições antes, mas o manual do Elisp parece dizer que elas são para alterar a aparência - eu entendi isso certo? Nesse caso, isso significa que essa resposta altera apenas a aparência do buffer, e não o conteúdo real do arquivo depois que ele é salvo? (É o último que eu estava procurando, mas mudar a aparência seria uma opção interessante.)
São Aardvark o Carpete
2
As sobreposições @SaintAardvarktheCarpeted são comumente usadas para alterar a aparência, mas sua aplicabilidade vai além disso. Nesta resposta (IIUC), as sobreposições são usadas para marcar regiões que devem ser alinhadas (para que o buffer seja realmente alterado, não apenas a aparência). A função my-auto-aligné usada para definir essas sobreposições (marque as regiões que você deseja alinhar). A razão (eu acho) que Stefan está passando por todo esse problema é que (ao contrário do recuo), se você apenas tentar alinhar todo o buffer, obterá resultados indesejados, então precisará alinhar as peças de cada vez.
Malabarba 15/10
3

Modo Puppet fornece puppet-align-block. Você pode organizar para que essa função seja chamada automaticamente, por exemplo, adicionando-a post-command-hooklocalmente (não testada):

(defun puppet-auto-align ()
  (unless (puppet-in-string-or-comment-p)
    (puppet-align-block)))

(define-minor-mode puppet-auto-align-mode
  :init-value nil
  :keymap nil
  :lighter "PAl"
  :group 'puppet-lint
  (if puppet-auto-align-mode
      (add-hook 'post-command-hook #'puppet-auto-align nil 'local)
    (remove-hook 'post-command-hook #'puppet-auto-align 'local)))

(add-hook 'puppet-mode-hook #'puppet-auto-align-mode)

Observe, porém, que há uma boa razão para não fazer isso. Não é particularmente inteligente e substituirá qualquer alinhamento manual que você possa fazer em qualquer lugar, o que será particularmente prejudicial se o alinhamento automático não funcionar para um código Puppet mais complicado.

Portanto, falando como mantenedor do Puppet Mode, eu recomendo isso e não o ajudaremos nem aceitaremos relatórios de erros, se você estiver usando esse código.

Além disso, para blocos de recursos grandes, pode ser lento, então você provavelmente deseja usar um timer inativo em vez de post-command-hookdiretamente.

lunaryorn
fonte